1 # bend-osdev-acpi, srat.bend: the System Resource Affinity Table, "SRAT" 2 # (ACPI 6.5, section 5.2.16): after the header, 4 reserved bytes (1, for 3 # compatibility) and 8 reserved bytes, then static resource allocation 4 # structures from offset 48 (entries.bend). The structures read here, with 5 # their lengths: 6 # 7 # type structure (section) length 8 # 0 Processor Local APIC/SAPIC Affinity (5.2.16.1) 16 9 # 1 Memory Affinity (5.2.16.2) 40 10 # 2 Processor Local x2APIC Affinity (5.2.16.3) 24 11 # 3 GICC Affinity (5.2.16.4) 18 12 # 4 GIC ITS Affinity (5.2.16.5) 12 13 # 5 Generic Initiator Affinity (5.2.16.6) 32 14 # 6 Generic Port Affinity (5.2.16.7, same layout as 5) 32 15 # 16 # Flags: bit 0 Enabled; for memory also bit 1 Hot Pluggable, bit 2 17 # NonVolatile. Other types are kept as AcpiSratOther with their bytes. 18 import Base 19 import bend-osdev-word64@0.1.0.0/word64.bend as W 20 import bend-osdev-bytes@0.1.0.0/bytes.bend as B 21 import ./error.bend as E 22 import ./header.bend as H 23 import ./fields.bend as F 24 import ./entries.bend as N 25 26 type AcpiSratEntry is Data: 27 # the proximity domain joined from its low byte (offset 2) and its high 28 # three bytes (offset 9) 29 AcpiSratLapic{domain: U32, apic_id: U32, flags: U32, sapic_eid: U32, clock_domain: U32} 30 AcpiSratMemory{domain: U32, base: W.W64, length: W.W64, flags: U32} 31 AcpiSratX2apic{domain: U32, x2apic_id: U32, flags: U32, clock_domain: U32} 32 AcpiSratGicc{domain: U32, uid: U32, flags: U32, clock_domain: U32} 33 AcpiSratGicIts{domain: U32, its_id: U32} 34 # kind 5 (generic initiator) or 6 (generic port); the 16-byte device 35 # handle as stored (ACPI or PCI form, by handle_type) 36 AcpiSratGeneric{kind: U32, handle_type: U32, domain: U32, handle: B.Octets, flags: U32} 37 AcpiSratOther{kind: U32, data: B.Octets} 38 39 type AcpiSrat is Data: 40 AcpiSrat{header: H.AcpiHeader, entries: List<&2, AcpiSratEntry>} 41 42 def AcpiSrat.entries(s: AcpiSrat) -> List<&2, AcpiSratEntry>: 43 match s: 44 case AcpiSrat{h, es}: 45 es 46 47 def srat.min(k: Nat) -> Nat: 48 match k: 49 case 0n: 50 16n 51 case 1n: 52 40n 53 case 2n: 54 24n 55 case 3n: 56 18n 57 case 4n: 58 12n 59 case 5n: 60 32n 61 case 6n: 62 32n 63 case _: 64 2n 65 66 def srat.typed(k: Nat, +d: B.Octets) -> AcpiSratEntry: 67 match k: 68 case 0n: 69 AcpiSratLapic{U32.or(F.AcpiF.u8(d, 2n), U32.shln(F.AcpiF.u24(d, 9n), 8n)), F.AcpiF.u8(d, 3n), F.AcpiF.u32(d, 4n), F.AcpiF.u8(d, 8n), F.AcpiF.u32(d, 12n)} 70 case 1n: 71 AcpiSratMemory{F.AcpiF.u32(d, 2n), F.AcpiF.u64(d, 8n), F.AcpiF.u64(d, 16n), F.AcpiF.u32(d, 28n)} 72 case 2n: 73 AcpiSratX2apic{F.AcpiF.u32(d, 4n), F.AcpiF.u32(d, 8n), F.AcpiF.u32(d, 12n), F.AcpiF.u32(d, 16n)} 74 case 3n: 75 AcpiSratGicc{F.AcpiF.u32(d, 2n), F.AcpiF.u32(d, 6n), F.AcpiF.u32(d, 10n), F.AcpiF.u32(d, 14n)} 76 case 4n: 77 AcpiSratGicIts{F.AcpiF.u32(d, 2n), F.AcpiF.u32(d, 8n)} 78 case 5n: 79 AcpiSratGeneric{5, F.AcpiF.u8(d, 3n), F.AcpiF.u32(d, 4n), F.AcpiF.bytes(d, 8n, 16n), F.AcpiF.u32(d, 24n)} 80 case 6n: 81 AcpiSratGeneric{6, F.AcpiF.u8(d, 3n), F.AcpiF.u32(d, 4n), F.AcpiF.bytes(d, 8n, 16n), F.AcpiF.u32(d, 24n)} 82 case _: 83 AcpiSratOther{F.AcpiF.u8(d, 0n), B.Octets.drop(2n, d)} 84 85 def srat.entry.pick(ok: Bool, +k: U32, +off: Nat, +d: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSratEntry>: 86 match ok: 87 case True{}: 88 Done{srat.typed(U32.to_nat(k), d)} 89 case False{}: 90 Fail{E.AcpiBadEntry{off, k}} 91 92 def AcpiSratEntry.of_raw(e: N.AcpiRawEntry) -> Result<&2, &2, E.AcpiError, AcpiSratEntry>: 93 match e: 94 case N.AcpiRawEntry{+k, off, +d}: 95 srat.entry.pick(Nat.is_le(srat.min(U32.to_nat(k)), B.Octets.len(d)), k, off, d) 96 97 def srat.rev(xs: List<&2, AcpiSratEntry>, acc: List<&2, AcpiSratEntry>) -> List<&2, AcpiSratEntry>: 98 match xs: 99 case Nil{}: 100 acc 101 case Con{h, t}: 102 srat.rev(t, Con{h, acc}) 103 104 def srat.push(acc: Result<&2, &2, E.AcpiError, List<&2, AcpiSratEntry>>, r: Result<&2, &2, E.AcpiError, AcpiSratEntry>) -> Result<&2, &2, E.AcpiError, List<&2, AcpiSratEntry>>: 105 match acc r: 106 case Fail{e} _: 107 Fail{e} 108 case Done{xs} Done{x}: 109 Done{Con{x, xs}} 110 case Done{xs} Fail{e}: 111 Fail{e} 112 113 def srat.all(es: List<&2, N.AcpiRawEntry>, acc: Result<&2, &2, E.AcpiError, List<&2, AcpiSratEntry>>) -> Result<&2, &2, E.AcpiError, List<&2, AcpiSratEntry>>: 114 match es: 115 case Nil{}: 116 acc 117 case Con{h, t}: 118 srat.all(t, srat.push(acc, AcpiSratEntry.of_raw(h))) 119 120 def srat.mk(+h: H.AcpiHeader, r: Result<&2, &2, E.AcpiError, List<&2, AcpiSratEntry>>) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 121 match r: 122 case Fail{e}: 123 Fail{e} 124 case Done{es}: 125 Done{AcpiSrat{h, srat.rev(es, Nil{})}} 126 127 def srat.raw(+h: H.AcpiHeader, r: Result<&2, &2, E.AcpiError, List<&2, N.AcpiRawEntry>>) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 128 match r: 129 case Fail{e}: 130 Fail{e} 131 case Done{es}: 132 srat.mk(h, srat.all(es, Done{Nil{}})) 133 134 def srat.body(ok: Bool, +h: H.AcpiHeader, +body: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 135 match ok: 136 case False{}: 137 Fail{E.AcpiTooShort{48n, Nat.add(36n, B.Octets.len(body))}} 138 case True{}: 139 srat.raw(h, N.AcpiRawEntry.split(B.Octets.drop(12n, body), 48n)) 140 141 def AcpiSrat.of_sdt(t: H.AcpiSdt) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 142 match t: 143 case H.AcpiSdt{h, +body}: 144 srat.body(Nat.is_le(12n, B.Octets.len(body)), h, body) 145 146 def srat.parse(r: Result<&2, &2, E.AcpiError, H.AcpiSdt>) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 147 match r: 148 case Fail{e}: 149 Fail{e} 150 case Done{t}: 151 AcpiSrat.of_sdt(t) 152 153 def AcpiSrat.parse(+o: B.Octets) -> Result<&2, &2, E.AcpiError, AcpiSrat>: 154 srat.parse(H.AcpiSdt.parse_sig(B.Octets.of_string("SRAT"), o)) 155 156 # Writing 157 158 def srat.z(n: Nat) -> B.Octets: 159 B.Octets.zeros(n) 160 161 def AcpiSratEntry.encode(e: AcpiSratEntry) -> B.Octets: 162 match e: 163 case AcpiSratLapic{+dm, a, f, s, c}: 164 N.AcpiRawEntry.encode(0, B.Octets.concat([B.Octets.of_list([dm, a]), B.Octets.le32(f), B.Octets.of_list([s]), F.AcpiF.le24(U32.shrn(dm, 8n)), B.Octets.le32(c)])) 165 case AcpiSratMemory{dm, b, l, f}: 166 N.AcpiRawEntry.encode(1, B.Octets.concat([B.Octets.le32(dm), srat.z(2n), B.Octets.le64(b), B.Octets.le64(l), srat.z(4n), B.Octets.le32(f), srat.z(8n)])) 167 case AcpiSratX2apic{dm, x, f, c}: 168 N.AcpiRawEntry.encode(2, B.Octets.concat([srat.z(2n), B.Octets.le32(dm), B.Octets.le32(x), B.Octets.le32(f), B.Octets.le32(c), srat.z(4n)])) 169 case AcpiSratGicc{dm, u, f, c}: 170 N.AcpiRawEntry.encode(3, B.Octets.concat([B.Octets.le32(dm), B.Octets.le32(u), B.Octets.le32(f), B.Octets.le32(c)])) 171 case AcpiSratGicIts{dm, i}: 172 N.AcpiRawEntry.encode(4, B.Octets.concat([B.Octets.le32(dm), srat.z(2n), B.Octets.le32(i)])) 173 case AcpiSratGeneric{k, ht, dm, hd, f}: 174 N.AcpiRawEntry.encode(k, B.Octets.concat([srat.z(1n), B.Octets.of_list([ht]), B.Octets.le32(dm), F.AcpiF.fit(16n, hd), B.Octets.le32(f), srat.z(4n)])) 175 case AcpiSratOther{k, d}: 176 N.AcpiRawEntry.encode(k, d) 177 178 def srat.enc(es: List<&2, AcpiSratEntry>) -> List<&2, B.Octets>: 179 match es: 180 case Nil{}: 181 Nil{} 182 case Con{h, t}: 183 Con{AcpiSratEntry.encode(h), srat.enc(t)} 184 185 def AcpiSrat.build(s: AcpiSrat) -> B.Octets: 186 match s: 187 case AcpiSrat{H.AcpiHeader{sg, l, r, c, o, t, orv, ci, cr}, es}: 188 H.AcpiSdt.build(H.AcpiHeader{B.Octets.of_string("SRAT"), l, r, c, o, t, orv, ci, cr}, B.Octets.concat([B.Octets.le32(1), srat.z(8n), B.Octets.concat(srat.enc(es))]))