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). 17 import Base 18 import bend-osdev-word64@0.1.1.1/word64.bend as W 19 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 20 import ./error.bend as E 21 import ./header.bend as H 22 import ./fields.bend as F 23 24 type AcpiMcfgEntry is Data: 25 AcpiMcfgEntry{base: W.W64, segment: U32, start_bus: U32, end_bus: U32} 26 27 type AcpiMcfg is Data: 28 AcpiMcfg{header: H.AcpiHeader, entries: List<&2, AcpiMcfgEntry>} 29 30 def 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 37 def 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) 47 def 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 53 def 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 60 def 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 63 def AcpiMcfg.entries(m: AcpiMcfg) -> List<&2, AcpiMcfgEntry>: 64 match m: 65 case AcpiMcfg{h, es}: 66 es 67 68 def 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 73 def 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 78 def 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 85 def 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 92 def 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 101 def 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 104 def 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))))