1 # bend-osdev-acpi, madt.bend: the Multiple APIC Description Table, "APIC" 2 # (ACPI 6.5, section 5.2.12): after the header, the local interrupt 3 # controller address (4 bytes, offset 36) and flags (4 bytes, offset 40; 4 # bit 0 PCAT_COMPAT, dual 8259s present), then interrupt controller 5 # structures from offset 44 (entries.bend). The structures read here, with 6 # their minimum lengths (later revisions may lengthen a structure; the extra 7 # bytes are ignored): 8 # 9 # type structure (table) length 10 # 0 Processor Local APIC (5.2.12.2) 8 11 # 1 I/O APIC (5.2.12.3) 12 12 # 2 Interrupt Source Override (5.2.12.5) 10 13 # 3 NMI Source (5.2.12.6) 8 14 # 4 Local APIC NMI (5.2.12.7) 6 15 # 5 Local APIC Address Override (5.2.12.8) 12 16 # 9 Processor Local x2APIC (5.2.12.12) 16 17 # 10 Local x2APIC NMI (5.2.12.13) 12 18 # 11 GIC CPU Interface, GICC (5.2.12.14) 76 (80 from ACPI 6.0, 82 19 # from 6.5: the SPE and TRBE interrupts read as 0 when absent) 20 # 12 GIC Distributor, GICD (5.2.12.15) 24 21 # 13 GIC MSI Frame (5.2.12.16) 24 22 # 14 GIC Redistributor, GICR (5.2.12.17) 16 23 # 15 GIC Interrupt Translation Service (5.2.12.18) 20 24 # 16 Multiprocessor Wakeup (5.2.12.19) 16 25 # 26 # Every other type (I/O SAPIC, Local SAPIC, platform interrupt sources, the 27 # LoongArch controllers, OEM types) is kept as AcpiMadtOther with its bytes. 28 import Base 29 import bend-osdev-word64@0.1.1.1/word64.bend as W 30 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 31 import ./error.bend as E 32 import ./header.bend as H 33 import ./fields.bend as F 34 import ./entries.bend as N 35 36 # the GICC's addresses, grouped (bendlang/bend#1069: records of many W64s) 37 type AcpiGiccAddrs is Data: 38 AcpiGiccAddrs{parked: W.W64, base: W.W64, gicv: W.W64, gich: W.W64, gicr: W.W64} 39 40 type AcpiMadtEntry is Data: 41 # flags: bit 0 Enabled, bit 1 Online Capable 42 AcpiMadtLapic{uid: U32, apic_id: U32, flags: U32} 43 AcpiMadtIoApic{id: U32, address: U32, gsi_base: U32} 44 # flags: MPS INTI flags, bits 0-1 polarity, bits 2-3 trigger mode 45 AcpiMadtIso{bus: U32, source: U32, gsi: U32, flags: U32} 46 AcpiMadtNmiSource{flags: U32, gsi: U32} 47 # uid 0xFF: every processor 48 AcpiMadtLapicNmi{uid: U32, flags: U32, lint: U32} 49 AcpiMadtLapicOverride{address: W.W64} 50 AcpiMadtX2apic{x2apic_id: U32, flags: U32, uid: U32} 51 # uid 0xFFFFFFFF: every processor 52 AcpiMadtX2apicNmi{flags: U32, uid: U32, lint: U32} 53 AcpiMadtGicc{cpu_interface: U32, uid: U32, flags: U32, parking_version: U32, perf_gsiv: U32, vgic_gsiv: U32, addrs: AcpiGiccAddrs, mpidr: W.W64, efficiency_class: U32, spe_gsiv: U32, trbe_gsiv: U32} 54 AcpiMadtGicd{gic_id: U32, base: W.W64, version: U32} 55 AcpiMadtGicMsi{id: U32, base: W.W64, flags: U32, spi_count: U32, spi_base: U32} 56 AcpiMadtGicr{base: W.W64, length: U32} 57 AcpiMadtGicIts{id: U32, base: W.W64} 58 AcpiMadtWakeup{version: U32, mailbox: W.W64} 59 # any other type: its type and its bytes after the two header bytes 60 AcpiMadtOther{kind: U32, data: B.Octets} 61 62 type AcpiMadt is Data: 63 AcpiMadt{header: H.AcpiHeader, lapic_address: U32, flags: U32, entries: List<&2, AcpiMadtEntry>} 64 65 def AcpiMadt.entries(m: AcpiMadt) -> List<&2, AcpiMadtEntry>: 66 match m: 67 case AcpiMadt{h, a, f, es}: 68 es 69 70 def AcpiMadt.lapic_address32(m: AcpiMadt) -> U32: 71 match m: 72 case AcpiMadt{h, a, f, es}: 73 a 74 75 def AcpiMadt.flags(m: AcpiMadt) -> U32: 76 match m: 77 case AcpiMadt{h, a, f, es}: 78 f 79 80 # Reading one structure from its bytes (d: all of them, type and length 81 # included); the minimum length of each type is checked first 82 83 def madt.min.go(k: Nat) -> Nat: 84 match k: 85 case 0n: 86 8n 87 case 1n: 88 12n 89 case 2n: 90 10n 91 case 3n: 92 8n 93 case 4n: 94 6n 95 case 5n: 96 12n 97 case 9n: 98 16n 99 case 10n: 100 12n 101 case 11n: 102 76n 103 case 12n: 104 24n 105 case 13n: 106 24n 107 case 14n: 108 16n 109 case 15n: 110 20n 111 case 16n: 112 16n 113 case _: 114 2n 115 116 def madt.min(+k: U32) -> Nat: 117 madt.min.go(U32.to_nat(k)) 118 119 def madt.gicc(+d: B.Octets) -> AcpiMadtEntry: 120 AcpiMadtGicc{F.AcpiF.u32(d, 4n), F.AcpiF.u32(d, 8n), F.AcpiF.u32(d, 12n), F.AcpiF.u32(d, 16n), F.AcpiF.u32(d, 20n), F.AcpiF.u32(d, 56n), AcpiGiccAddrs{F.AcpiF.u64(d, 24n), F.AcpiF.u64(d, 32n), F.AcpiF.u64(d, 40n), F.AcpiF.u64(d, 48n), F.AcpiF.u64(d, 60n)}, F.AcpiF.u64(d, 68n), F.AcpiF.u8(d, 76n), F.AcpiF.u16(d, 78n), F.AcpiF.u16(d, 80n)} 121 122 def madt.typed(k: Nat, +d: B.Octets) -> AcpiMadtEntry: 123 match k: 124 case 0n: 125 AcpiMadtLapic{F.AcpiF.u8(d, 2n), F.AcpiF.u8(d, 3n), F.AcpiF.u32(d, 4n)} 126 case 1n: 127 AcpiMadtIoApic{F.AcpiF.u8(d, 2n), F.AcpiF.u32(d, 4n), F.AcpiF.u32(d, 8n)} 128 case 2n: 129 AcpiMadtIso{F.AcpiF.u8(d, 2n), F.AcpiF.u8(d, 3n), F.AcpiF.u32(d, 4n), F.AcpiF.u16(d, 8n)} 130 case 3n: 131 AcpiMadtNmiSource{F.AcpiF.u16(d, 2n), F.AcpiF.u32(d, 4n)} 132 case 4n: 133 AcpiMadtLapicNmi{F.AcpiF.u8(d, 2n), F.AcpiF.u16(d, 3n), F.AcpiF.u8(d, 5n)} 134 case 5n: 135 AcpiMadtLapicOverride{F.AcpiF.u64(d, 4n)} 136 case 9n: 137 AcpiMadtX2apic{F.AcpiF.u32(d, 4n), F.AcpiF.u32(d, 8n), F.AcpiF.u32(d, 12n)} 138 case 10n: 139 AcpiMadtX2apicNmi{F.AcpiF.u16(d, 2n), F.AcpiF.u32(d, 4n), F.AcpiF.u8(d, 8n)} 140 case 11n: 141 madt.gicc(d) 142 case 12n: 143 AcpiMadtGicd{F.AcpiF.u32(d, 4n), F.AcpiF.u64(d, 8n), F.AcpiF.u8(d, 20n)} 144 case 13n: 145 AcpiMadtGicMsi{F.AcpiF.u32(d, 4n), F.AcpiF.u64(d, 8n), F.AcpiF.u32(d, 16n), F.AcpiF.u16(d, 20n), F.AcpiF.u16(d, 22n)} 146 case 14n: 147 AcpiMadtGicr{F.AcpiF.u64(d, 4n), F.AcpiF.u32(d, 12n)} 148 case 15n: 149 AcpiMadtGicIts{F.AcpiF.u32(d, 4n), F.AcpiF.u64(d, 8n)} 150 case 16n: 151 AcpiMadtWakeup{F.AcpiF.u16(d, 2n), F.AcpiF.u64(d, 8n)} 152 case _: 153 AcpiMadtOther{F.AcpiF.u8(d, 0n), B.Octets.drop(2n, d)} 154 155 def madt.entry.pick(ok: Bool, +k: U32, +off: Nat, +d: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiMadtEntry>: 156 match ok: 157 case True{}: 158 Done{madt.typed(U32.to_nat(k), d)} 159 case False{}: 160 Fail{E.AcpiBadEntry{off, k}} 161 162 def AcpiMadtEntry.of_raw(e: N.AcpiRawEntry) -> Result<&2, &2, E.AcpiError, AcpiMadtEntry>: 163 match e: 164 case N.AcpiRawEntry{+k, off, +d}: 165 madt.entry.pick(Nat.is_le(madt.min(k), B.Octets.len(d)), k, off, d) 166 167 def madt.rev(xs: List<&2, AcpiMadtEntry>, acc: List<&2, AcpiMadtEntry>) -> List<&2, AcpiMadtEntry>: 168 match xs: 169 case Nil{}: 170 acc 171 case Con{h, t}: 172 madt.rev(t, Con{h, acc}) 173 174 def madt.push(acc: Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>, r: Result<&2, &2, E.AcpiError, AcpiMadtEntry>) -> Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>: 175 match acc r: 176 case Fail{e} _: 177 Fail{e} 178 case Done{xs} Done{x}: 179 Done{Con{x, xs}} 180 case Done{xs} Fail{e}: 181 Fail{e} 182 183 def madt.fin(r: Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>) -> Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>: 184 match r: 185 case Fail{e}: 186 Fail{e} 187 case Done{xs}: 188 Done{madt.rev(xs, Nil{})} 189 190 def madt.all(es: List<&2, N.AcpiRawEntry>, acc: Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>) -> Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>: 191 match es: 192 case Nil{}: 193 madt.fin(acc) 194 case Con{h, t}: 195 madt.all(t, madt.push(acc, AcpiMadtEntry.of_raw(h))) 196 197 def madt.mk2(+h: H.AcpiHeader, +a: U32, +f: U32, r: Result<&2, &2, E.AcpiError, List<&2, AcpiMadtEntry>>) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 198 match r: 199 case Fail{e}: 200 Fail{e} 201 case Done{es}: 202 Done{AcpiMadt{h, a, f, es}} 203 204 def madt.mk(+h: H.AcpiHeader, +a: U32, +f: U32, r: Result<&2, &2, E.AcpiError, List<&2, N.AcpiRawEntry>>) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 205 match r: 206 case Fail{e}: 207 Fail{e} 208 case Done{es}: 209 madt.mk2(h, a, f, madt.all(es, Done{Nil{}})) 210 211 def madt.body(ok: Bool, +h: H.AcpiHeader, +body: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 212 match ok: 213 case False{}: 214 Fail{E.AcpiTooShort{44n, Nat.add(36n, B.Octets.len(body))}} 215 case True{}: 216 madt.mk(h, F.AcpiF.u32(body, 0n), F.AcpiF.u32(body, 4n), N.AcpiRawEntry.split(B.Octets.drop(8n, body), 44n)) 217 218 # a checked table (header.bend: AcpiSdt.parse) as an MADT 219 def AcpiMadt.of_sdt(t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 220 match t: 221 case H.AcpiSdt{h, +body}: 222 madt.body(Nat.is_le(8n, B.Octets.len(body)), h, body) 223 224 def madt.parse(r: Result<&2, &2, E.AcpiError, H.AcpiSdt>) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 225 match r: 226 case Fail{e}: 227 Fail{e} 228 case Done{t}: 229 AcpiMadt.of_sdt(t) 230 231 # the MADT at the front of o: checked (length, checksum, signature "APIC"), 232 # then read 233 def AcpiMadt.parse(+o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiMadt>: 234 madt.parse(H.AcpiSdt.parse_sig(B.Octets.of_string("APIC"), o)) 235 236 # Queries 237 238 def madt.override(es: List<&2, AcpiMadtEntry>, +dflt: W.W64) -> W.W64: 239 match es: 240 case Nil{}: 241 dflt 242 case Con{AcpiMadtLapicOverride{a}, t}: 243 a 244 case Con{e, t}: 245 madt.override(t, dflt) 246 247 # the local APIC's physical address: the 64-bit override structure's, if 248 # there is one (5.2.12.8), else the 32-bit field 249 def AcpiMadt.lapic_address(m: AcpiMadt) -> W.W64: 250 match m: 251 case AcpiMadt{h, a, f, es}: 252 madt.override(es, W.W64.from_u32(a)) 253 254 # Writing: each structure as bytes (the lengths of this revision: GICC 82) 255 256 def madt.u16(v: U32) -> B.Octets: 257 B.Octets.le16(v) 258 259 def madt.u32(v: U32) -> B.Octets: 260 B.Octets.le32(v) 261 262 def madt.u64(v: W.W64) -> B.Octets: 263 B.Octets.le64(v) 264 265 def madt.u8(v: U32) -> B.Octets: 266 B.Octets.of_list([v]) 267 268 def madt.z(n: Nat) -> B.Octets: 269 B.Octets.zeros(n) 270 271 def AcpiMadtEntry.encode(e: AcpiMadtEntry) -> B.Octets: 272 match e: 273 case AcpiMadtLapic{u, a, f}: 274 N.AcpiRawEntry.encode(0, B.Octets.concat([madt.u8(u), madt.u8(a), madt.u32(f)])) 275 case AcpiMadtIoApic{i, a, g}: 276 N.AcpiRawEntry.encode(1, B.Octets.concat([madt.u8(i), madt.z(1n), madt.u32(a), madt.u32(g)])) 277 case AcpiMadtIso{b, s, g, f}: 278 N.AcpiRawEntry.encode(2, B.Octets.concat([madt.u8(b), madt.u8(s), madt.u32(g), madt.u16(f)])) 279 case AcpiMadtNmiSource{f, g}: 280 N.AcpiRawEntry.encode(3, B.Octets.concat([madt.u16(f), madt.u32(g)])) 281 case AcpiMadtLapicNmi{u, f, l}: 282 N.AcpiRawEntry.encode(4, B.Octets.concat([madt.u8(u), madt.u16(f), madt.u8(l)])) 283 case AcpiMadtLapicOverride{a}: 284 N.AcpiRawEntry.encode(5, B.Octets.concat([madt.z(2n), madt.u64(a)])) 285 case AcpiMadtX2apic{x, f, u}: 286 N.AcpiRawEntry.encode(9, B.Octets.concat([madt.z(2n), madt.u32(x), madt.u32(f), madt.u32(u)])) 287 case AcpiMadtX2apicNmi{f, u, l}: 288 N.AcpiRawEntry.encode(10, B.Octets.concat([madt.u16(f), madt.u32(u), madt.u8(l), madt.z(3n)])) 289 case AcpiMadtGicc{ci, u, f, pv, pg, vg, AcpiGiccAddrs{pk, b, gv, gh, gr}, mp, ec, sp, tr}: 290 N.AcpiRawEntry.encode(11, B.Octets.concat([madt.z(2n), madt.u32(ci), madt.u32(u), madt.u32(f), madt.u32(pv), madt.u32(pg), madt.u64(pk), madt.u64(b), madt.u64(gv), madt.u64(gh), madt.u32(vg), madt.u64(gr), madt.u64(mp), madt.u8(ec), madt.z(1n), madt.u16(sp), madt.u16(tr)])) 291 case AcpiMadtGicd{i, b, v}: 292 N.AcpiRawEntry.encode(12, B.Octets.concat([madt.z(2n), madt.u32(i), madt.u64(b), madt.z(4n), madt.u8(v), madt.z(3n)])) 293 case AcpiMadtGicMsi{i, b, f, c, s}: 294 N.AcpiRawEntry.encode(13, B.Octets.concat([madt.z(2n), madt.u32(i), madt.u64(b), madt.u32(f), madt.u16(c), madt.u16(s)])) 295 case AcpiMadtGicr{b, l}: 296 N.AcpiRawEntry.encode(14, B.Octets.concat([madt.z(2n), madt.u64(b), madt.u32(l)])) 297 case AcpiMadtGicIts{i, b}: 298 N.AcpiRawEntry.encode(15, B.Octets.concat([madt.z(2n), madt.u32(i), madt.u64(b), madt.z(4n)])) 299 case AcpiMadtWakeup{v, m}: 300 N.AcpiRawEntry.encode(16, B.Octets.concat([madt.u16(v), madt.z(4n), madt.u64(m)])) 301 case AcpiMadtOther{k, d}: 302 N.AcpiRawEntry.encode(k, d) 303 304 def madt.enc(es: List<&2, AcpiMadtEntry>) -> List<&2, B.Octets>: 305 match es: 306 case Nil{}: 307 Nil{} 308 case Con{h, t}: 309 Con{AcpiMadtEntry.encode(h), madt.enc(t)} 310 311 # the table (signature set to "APIC", length and checksum computed) 312 def AcpiMadt.build(m: AcpiMadt) -> B.Octets: 313 match m: 314 case AcpiMadt{H.AcpiHeader{s, l, r, c, o, t, orv, ci, cr}, a, f, es}: 315 H.AcpiSdt.build(H.AcpiHeader{B.Octets.of_string("APIC"), l, r, c, o, t, orv, ci, cr}, B.Octets.append(B.Octets.append(madt.u32(a), madt.u32(f)), B.Octets.concat(madt.enc(es))))