srat.bend

bend-osdev-acpi@0.1.1.0 · 188 lines · 20 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.1.0/word64.bend as W
20import bend-osdev-bytes@0.1.1.0/bytes.bend as B
21import bend-osdev-acpi@0.1.1.0/error.bend as E
22import bend-osdev-acpi@0.1.1.0/header.bend as H
23import bend-osdev-acpi@0.1.1.0/fields.bend as F
24import bend-osdev-acpi@0.1.1.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))]))