mcfg.bend
bend-osdev-acpi@0.1.2.0 · 107 lines · 0 definitions
1# bend-osdev-acpi, mcfg.bend: the PCI Express memory-mapped configuration
2# space table, "MCFG" (PCI Firmware Specification, revision 3.3, PCI-SIG,
3# section 4.1.2; its signature is reserved by ACPI 6.5, section 5.2.6):
4# after the header, 8 reserved bytes, then 16-byte allocation structures
5# from offset 44:
6#
7# offset size field
8# 0 8 Base Address of the enhanced configuration (ECAM) region
9# 8 2 PCI Segment Group Number
10# 10 1 Start Bus Number
11# 11 1 End Bus Number
12# 12 4 Reserved
13#
14# The base address is that of bus 0 of the segment, whatever the start bus
15# (PCI Firmware Specification, 4.1.2), so bus b, device d, function f,
16# register r is at base + (b << 20 | d << 15 | f << 12 | r).
17import Base
18import bend-osdev-word64@0.1.1.1/word64.bend as W
19import bend-osdev-bytes@0.1.1.1/bytes.bend as B
20import bend-osdev-acpi@0.1.2.0/error.bend as E
21import bend-osdev-acpi@0.1.2.0/header.bend as H
22import bend-osdev-acpi@0.1.2.0/fields.bend as F
23
24type AcpiMcfgEntry is Data:
25 AcpiMcfgEntry{base: W.W64, segment: U32, start_bus: U32, end_bus: U32}
26
27type AcpiMcfg is Data:
28 AcpiMcfg{header: H.AcpiHeader, entries: List<&2, AcpiMcfgEntry>}
29
30def mcfg.read(n: Nat, +o: B.Octets) -> List<&2, AcpiMcfgEntry>:
31 match n:
32 case 0n:
33 Nil{}
34 case 1n+p:
35 Con{AcpiMcfgEntry{F.AcpiF.u64(o, 0n), F.AcpiF.u16(o, 8n), F.AcpiF.u8(o, 10n), F.AcpiF.u8(o, 11n)}, mcfg.read(p, B.Octets.drop(16n, o))}
36
37def mcfg.body(ok: Bool, +h: H.AcpiHeader, +body: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiMcfg>:
38 match ok:
39 case False{}:
40 Fail{E.AcpiBadSize{B.Octets.len(body)}}
41 case True{}:
42 +es = B.Octets.drop(8n, body)
43 Done{AcpiMcfg{h, mcfg.read(Nat.div(B.Octets.len(es), 16n), es)}}
44
45# a checked table as an MCFG: the body is 8 reserved bytes and a whole
46# number of 16-byte structures (AcpiBadSize otherwise)
47def AcpiMcfg.of_sdt(t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiMcfg>:
48 match t:
49 case H.AcpiSdt{h, +body}:
50 +n = B.Octets.len(body)
51 mcfg.body(Bool.and(Nat.is_le(8n, n), Nat.is_eq(Nat.mod(Nat.sub(n, 8n), 16n), 0n)), h, body)
52
53def mcfg.parse(r: Result<&2, &2, E.AcpiError, H.AcpiSdt>) -> Result<&2, &2, E.AcpiError, AcpiMcfg>:
54 match r:
55 case Fail{e}:
56 Fail{e}
57 case Done{t}:
58 AcpiMcfg.of_sdt(t)
59
60def AcpiMcfg.parse(+o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiMcfg>:
61 mcfg.parse(H.AcpiSdt.parse_sig(B.Octets.of_string("MCFG"), o))
62
63def AcpiMcfg.entries(m: AcpiMcfg) -> List<&2, AcpiMcfgEntry>:
64 match m:
65 case AcpiMcfg{h, es}:
66 es
67
68def mcfg.covers(+seg: U32, +bus: U32, e: AcpiMcfgEntry) -> Bool:
69 match e:
70 case AcpiMcfgEntry{b, s, lo, hi}:
71 Bool.and(U32.is_eq(s, seg), Bool.and(U32.is_le(lo, bus), U32.is_le(bus, hi)))
72
73def mcfg.addr(+e: AcpiMcfgEntry, +bus: U32, +dev: U32, +fun: U32, +reg: U32) -> W.W64:
74 match e:
75 case AcpiMcfgEntry{b, s, lo, hi}:
76 W.W64.add(b, W.W64.from_u32(U32.or(U32.shln(U32.and(bus, 255), 20n), U32.or(U32.shln(U32.and(dev, 31), 15n), U32.or(U32.shln(U32.and(fun, 7), 12n), U32.and(reg, 4095))))))
77
78def mcfg.hit(hit: Bool, +e: AcpiMcfgEntry, +bus: U32, +dev: U32, +fun: U32, +reg: U32) -> Maybe<&2, W.W64>:
79 match hit:
80 case True{}:
81 Some{mcfg.addr(e, bus, dev, fun, reg)}
82 case False{}:
83 None{}
84
85def mcfg.first(es: List<&2, AcpiMcfgEntry>, +seg: U32, +bus: U32, +dev: U32, +fun: U32, +reg: U32) -> Maybe<&2, W.W64>:
86 match es:
87 case Nil{}:
88 None{}
89 case Con{+e, t}:
90 Maybe.or(&2, W.W64, mcfg.hit(mcfg.covers(seg, bus, e), e, bus, dev, fun, reg), mcfg.first(t, seg, bus, dev, fun, reg))
91
92def mcfg.enc(es: List<&2, AcpiMcfgEntry>) -> List<&2, B.Octets>:
93 match es:
94 case Nil{}:
95 Nil{}
96 case Con{AcpiMcfgEntry{b, s, lo, hi}, t}:
97 Con{B.Octets.concat([B.Octets.le64(b), B.Octets.le16(s), B.Octets.of_list([lo, hi]), B.Octets.zeros(4n)]), mcfg.enc(t)}
98
99# the physical address of a configuration register, if a structure covers
100# the segment and bus
101def AcpiMcfg.ecam_address(m: AcpiMcfg, +seg: U32, +bus: U32, +dev: U32, +fun: U32, +reg: U32) -> Maybe<&2, W.W64>:
102 mcfg.first(AcpiMcfg.entries(m), seg, bus, dev, fun, reg)
103
104def AcpiMcfg.build(m: AcpiMcfg) -> B.Octets:
105 match m:
106 case AcpiMcfg{H.AcpiHeader{s, l, r, c, o, t, orv, ci, cr}, es}:
107 H.AcpiSdt.build(H.AcpiHeader{B.Octets.of_string("MCFG"), l, r, c, o, t, orv, ci, cr}, B.Octets.append(B.Octets.zeros(8n), B.Octets.concat(mcfg.enc(es))))