acpi.bend
bend-osdev-acpi@0.1.1.0 · 276 lines · 42 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14import Base
15import bend-osdev-word64@0.1.1.0/word64.bend as W
16import bend-osdev-bytes@0.1.1.0/bytes.bend as B
17import bend-osdev-acpi@0.1.1.0/error.bend as E
18import bend-osdev-acpi@0.1.1.0/header.bend as H
19import bend-osdev-acpi@0.1.1.0/rsdp.bend as P
20import bend-osdev-acpi@0.1.1.0/rsdt.bend as S
21import bend-osdev-acpi@0.1.1.0/fadt.bend as F
22import bend-osdev-acpi@0.1.1.0/facs.bend as FS
23import bend-osdev-acpi@0.1.1.0/registry.bend as R
24
25
26
27type AcpiMemRegion is Data:
28 AcpiMemRegion{base: W.W64, bytes: B.Octets}
29
30type AcpiMemImage is Data:
31 AcpiMemImage{regions: List<&2, AcpiMemRegion>}
32
33def mem.slice(inside: Bool, +off: Nat, +n: Nat, +o: B.Octets) -> Maybe<&2, B.Octets>:
34 match inside:
35 case False{}:
36 None{}
37 case True{}:
38 Some{B.Octets.slice(off, n, o)}
39
40
41
42def mem.near(near: Bool, +off: W.W64, +n: Nat, +o: B.Octets) -> Maybe<&2, B.Octets>:
43 match near:
44 case False{}:
45 None{}
46 case True{}:
47 +k = U32.to_nat(W.W64.lo(off))
48 mem.slice(Nat.is_le(Nat.add(k, n), B.Octets.len(o)), k, n, o)
49
50def mem.above(above: Bool, +base: W.W64, +addr: W.W64, +n: Nat, +o: B.Octets) -> Maybe<&2, B.Octets>:
51 match above:
52 case False{}:
53 None{}
54 case True{}:
55 +off = W.W64.sub(addr, base)
56 mem.near(U32.is_eq(W.W64.hi(off), 0), off, n, o)
57
58def mem.try(r: AcpiMemRegion, +addr: W.W64, +n: Nat) -> Maybe<&2, B.Octets>:
59 match r:
60 case AcpiMemRegion{+base, +o}:
61 mem.above(W.W64.is_le(base, addr), base, addr, n, o)
62
63def mem.find(rs: List<&2, AcpiMemRegion>, +addr: W.W64, +n: Nat) -> Maybe<&2, B.Octets>:
64 match rs:
65 case Nil{}:
66 None{}
67 case Con{h, t}:
68 Maybe.or(&2, B.Octets, mem.try(h, addr, n), mem.find(t, addr, n))
69
70def mem.done(m: Maybe<&2, B.Octets>, +addr: W.W64) -> Result<&2, &2, E.AcpiError, B.Octets>:
71 match m:
72 case None{}:
73 Fail{E.AcpiNotMapped{addr}}
74 case Some{o}:
75 Done{o}
76
77
78def mem.read(m: AcpiMemImage, +addr: W.W64, +n: Nat) -> Result<&2, &2, E.AcpiError, B.Octets>:
79 match m:
80 case AcpiMemImage{rs}:
81 mem.done(mem.find(rs, addr, n), addr)
82
83
84def AcpiMemImage.read(m: AcpiMemImage, addr: W.W64, n: Nat) -> Result<&2, &2, E.AcpiError, B.Octets>:
85 mem.read(m, addr, n)
86
87def AcpiMemImage.of_list(rs: List<&2, AcpiMemRegion>) -> AcpiMemImage:
88 AcpiMemImage{rs}
89
90
91
92type AcpiLoadOptions is Data:
93
94
95 AcpiLoadOptions{prefer_xsdt: Bool, registry: R.AcpiRegistry}
96
97def AcpiLoadOptions.default() -> AcpiLoadOptions:
98 AcpiLoadOptions{True{}, R.AcpiRegistry.default()}
99
100
101
102
103
104type AcpiLoaded<-X: Data> is Data:
105 AcpiLoaded{address: W.W64, table: Result<&2, &2, E.AcpiError, R.AcpiTable<X>>}
106
107type AcpiTableSet<-X: Data> is Data:
108 AcpiTableSet{rsdp: P.AcpiRsdp, root: S.AcpiSdtList, tables: List<&2, AcpiLoaded<X>>, facs: Maybe<&2, Result<&2, &2, E.AcpiError, FS.AcpiFacs>>}
109
110
111
112
113
114def ld.whole(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, +addr: W.W64, +head: B.Octets) -> Result<&2, &2, E.AcpiError, B.Octets>:
115 read(m, addr, U32.to_nat(Maybe.default(&2, U32, B.Octets.le32_at(head, 4n), 0)))
116
117def AcpiTables.read_table(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, +addr: W.W64) -> Result<&2, &2, E.AcpiError, B.Octets>:
118 do Result<&2, &2, E.AcpiError, B.Octets>:
119 head : B.Octets <- read(m, addr, 8n)
120 ld.whole(~M, ~read, m, addr, head)
121
122def ld.rsdp.pick(v1: Bool) -> Nat:
123 match v1:
124 case True{}:
125 20n
126 case False{}:
127 36n
128
129def ld.rsdp.len(+head: B.Octets) -> Nat:
130 ld.rsdp.pick(U32.is_lt(Maybe.default(&2, U32, B.Octets.at(head, 15n), 0), 2))
131
132def AcpiTables.read_rsdp(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, +addr: W.W64) -> Result<&2, &2, E.AcpiError, P.AcpiRsdp>:
133 do Result<&2, &2, E.AcpiError, P.AcpiRsdp>:
134 head : B.Octets <- read(m, addr, 20n)
135 o : B.Octets <- read(m, addr, ld.rsdp.len(head))
136 P.AcpiRsdp.parse(o)
137
138def ld.root.parse(xsdt: Bool, +o: B.Octets) -> Result<&2, &2, E.AcpiError, S.AcpiSdtList>:
139 match xsdt:
140 case True{}:
141 S.AcpiXsdt.parse(o)
142 case False{}:
143 S.AcpiRsdt.parse(o)
144
145def ld.root(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, +xsdt: Bool, +addr: W.W64) -> Result<&2, &2, E.AcpiError, S.AcpiSdtList>:
146 do Result<&2, &2, E.AcpiError, S.AcpiSdtList>:
147 o : B.Octets <- AcpiTables.read_table(~M, ~read, m, addr)
148 ld.root.parse(xsdt, o)
149
150def ld.one(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, ~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, +m: M, +reg: R.AcpiRegistry, +addr: W.W64) -> AcpiLoaded<X>:
151 AcpiLoaded{addr, Result.bind(&2, &2, E.AcpiError, B.Octets, R.AcpiTable<X>, AcpiTables.read_table(~M, ~read, m, addr), o => R.AcpiTable.parse_with(~X, ~ext, reg, o))}
152
153def ld.all(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, ~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, as: List<&2, W.W64>, +m: M, +reg: R.AcpiRegistry) -> List<&2, AcpiLoaded<X>>:
154 match as:
155 case Nil{}:
156 Nil{}
157 case Con{a, t}:
158 Con{ld.one(~M, ~read, ~X, ~ext, m, reg, a), ld.all(~M, ~read, ~X, ~ext, t, m, reg)}
159
160
161def ld.fadt(~X: Data, ts: List<&2, AcpiLoaded<X>>) -> Maybe<&2, F.AcpiFadt>:
162 match ts:
163 case Nil{}:
164 None{}
165 case Con{AcpiLoaded{a, Done{R.AcpiTFadt{f}}}, t}:
166 Some{f}
167 case Con{h, t}:
168 ld.fadt(~X, t)
169
170def ld.nz.pick(z: Bool, +a: W.W64) -> Maybe<&2, W.W64>:
171 match z:
172 case True{}:
173 None{}
174 case False{}:
175 Some{a}
176
177def ld.nz(+a: W.W64) -> Maybe<&2, W.W64>:
178 ld.nz.pick(W.W64.is_zero(a), a)
179
180def ld.list(m: Maybe<&2, W.W64>) -> List<&2, W.W64>:
181 match m:
182 case None{}:
183 Nil{}
184 case Some{a}:
185 [a]
186
187def ld.dsdt(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, ~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, f: Maybe<&2, F.AcpiFadt>, +m: M, +reg: R.AcpiRegistry) -> List<&2, AcpiLoaded<X>>:
188 match f:
189 case None{}:
190 Nil{}
191 case Some{+fa}:
192 ld.all(~M, ~read, ~X, ~ext, ld.list(ld.nz(F.AcpiFadt.dsdt_address(fa))), m, reg)
193
194def ld.facs.at(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, a: Maybe<&2, W.W64>) -> Maybe<&2, Result<&2, &2, E.AcpiError, FS.AcpiFacs>>:
195 match a:
196 case None{}:
197 None{}
198 case Some{+addr}:
199 Some{Result.bind(&2, &2, E.AcpiError, B.Octets, FS.AcpiFacs, read(m, addr, 64n), o => FS.AcpiFacs.parse(o))}
200
201def ld.facs(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, f: Maybe<&2, F.AcpiFadt>, +m: M) -> Maybe<&2, Result<&2, &2, E.AcpiError, FS.AcpiFacs>>:
202 match f:
203 case None{}:
204 None{}
205 case Some{+fa}:
206 ld.facs.at(~M, ~read, m, ld.nz(F.AcpiFadt.facs_address(fa)))
207
208def ld.use_x(prefer: Bool, +r: P.AcpiRsdp) -> Bool:
209 match prefer:
210 case True{}:
211 Bool.not(W.W64.is_zero(P.AcpiRsdp.xsdt_address(r)))
212 case False{}:
213 False{}
214
215def ld.root_addr(x: Bool, +r: P.AcpiRsdp) -> W.W64:
216 match x:
217 case True{}:
218 P.AcpiRsdp.xsdt_address(r)
219 case False{}:
220 W.W64.from_u32(P.AcpiRsdp.rsdt_address(r))
221
222def ld.finish(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, ~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, +m: M, +reg: R.AcpiRegistry, rsdp: P.AcpiRsdp, +root: S.AcpiSdtList) -> AcpiTableSet<X>:
223 +ts = ld.all(~M, ~read, ~X, ~ext, S.AcpiSdtList.entries(root), m, reg)
224 +f = ld.fadt(~X, ts)
225 AcpiTableSet{rsdp, root, List.append(&2, AcpiLoaded<X>, ts, ld.dsdt(~M, ~read, ~X, ~ext, f, m, reg)), ld.facs(~M, ~read, f, m)}
226
227def ld.opts(o: AcpiLoadOptions) -> Bool:
228 match o:
229 case AcpiLoadOptions{p, r}:
230 p
231
232def ld.reg(o: AcpiLoadOptions) -> R.AcpiRegistry:
233 match o:
234 case AcpiLoadOptions{p, r}:
235 r
236
237
238
239
240def AcpiTables.load_with(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, ~X: Data, ~ext: U32 -> H.AcpiSdt -> Result<&2, &2, E.AcpiError, X>, +opts: AcpiLoadOptions, +m: M, +rsdp_addr: W.W64) -> Result<&2, &2, E.AcpiError, AcpiTableSet<X>>:
241 do Result<&2, &2, E.AcpiError, AcpiTableSet<X>>:
242 +r : P.AcpiRsdp <- AcpiTables.read_rsdp(~M, ~read, m, rsdp_addr)
243 +x : Bool = ld.use_x(ld.opts(opts), r)
244 root : S.AcpiSdtList <- ld.root(~M, ~read, m, x, ld.root_addr(x, r))
245 return ld.finish(~M, ~read, ~X, ~ext, m, ld.reg(opts), r, root)
246
247def AcpiTables.load(~M: Data, ~read: M -> W.W64 -> Nat -> Result<&2, &2, E.AcpiError, B.Octets>, +m: M, +rsdp_addr: W.W64) -> Result<&2, &2, E.AcpiError, AcpiTableSet<R.AcpiNoExt>>:
248 AcpiTables.load_with(~M, ~read, ~R.AcpiNoExt, ~R.AcpiNoExt.parse, AcpiLoadOptions.default(), m, rsdp_addr)
249
250
251
252def AcpiTableSet.tables(~X: Data, s: AcpiTableSet<X>) -> List<&2, AcpiLoaded<X>>:
253 match s:
254 case AcpiTableSet{r, root, ts, f}:
255 ts
256
257def ld.find.pick(~X: Data, hit: Bool, t: R.AcpiTable<X>, rest: Maybe<&2, R.AcpiTable<X>>) -> Maybe<&2, R.AcpiTable<X>>:
258 match hit:
259 case True{}:
260 Some{t}
261 case False{}:
262 rest
263
264def ld.find(~X: Data, ts: List<&2, AcpiLoaded<X>>, +name: String) -> Maybe<&2, R.AcpiTable<X>>:
265 match ts:
266 case Nil{}:
267 None{}
268 case Con{AcpiLoaded{a, Done{+t}}, rest}:
269 ld.find.pick(~X, String.eq(R.AcpiTable.name(~X, t), name), t, ld.find(~X, rest, name))
270 case Con{h, rest}:
271 ld.find(~X, rest, name)
272
273
274
275def AcpiTableSet.find(~X: Data, s: AcpiTableSet<X>, +name: String) -> Maybe<&2, R.AcpiTable<X>>:
276 ld.find(~X, AcpiTableSet.tables(~X, s), name)