srat.bend
bend-osdev-acpi@0.1.0.0 · 188 lines · 0 definitions
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.
18import Base
19import bend-osdev-word64@0.1.0.0/word64.bend as W
20import bend-osdev-bytes@0.1.0.0/bytes.bend as B
21import bend-osdev-acpi@0.1.0.0/error.bend as E
22import bend-osdev-acpi@0.1.0.0/header.bend as H
23import bend-osdev-acpi@0.1.0.0/fields.bend as F
24import bend-osdev-acpi@0.1.0.0/entries.bend as N
25
26type 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
39type AcpiSrat is Data:
40 AcpiSrat{header: H.AcpiHeader, entries: List<&2, AcpiSratEntry>}
41
42def AcpiSrat.entries(s: AcpiSrat) -> List<&2, AcpiSratEntry>:
43 match s:
44 case AcpiSrat{h, es}:
45 es
46
47def 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
66def 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
85def 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
92def 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
97def 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
104def 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
113def 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
120def 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
127def 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
134def 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
141def 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
146def 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
153def 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
158def srat.z(n: Nat) -> B.Octets:
159 B.Octets.zeros(n)
160
161def 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
178def 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
185def 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))]))