mcfg.bend

bend-osdev-acpi@0.1.1.0 · 107 lines · 15 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.0/word64.bend as W
19import bend-osdev-bytes@0.1.1.0/bytes.bend as B
20import bend-osdev-acpi@0.1.1.0/error.bend as E
21import bend-osdev-acpi@0.1.1.0/header.bend as H
22import bend-osdev-acpi@0.1.1.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))))