aml.bend
bend-osdev-acpi@0.1.2.0 · 214 lines · 0 definitions
1# bend-osdev-acpi, aml.bend: AML definition blocks loaded into a namespace,
2# and objects evaluated there (ACPI 6.5, sections 5.4, Definition Block
3# Encoding, and 5.5, Using the ACPI Control Method Source Language).
4#
5# A system is the namespace, the operation-region host, the integer width
6# (64 bits unless the DSDT's revision is below 2) and the options. Loading a
7# DSDT or SSDT runs its top-level terms (Name, Method, Device, Scope, ...)
8# into the namespace; evaluating a path runs a method with arguments, or
9# reads any other object. Both take a step bound (aml_interp.bend) and
10# answer an AmlOutcome: the result (AcpiAmlStepLimit when the bound ran
11# out), the namespace and host after, the steps used, the Notify calls and
12# the values stored to Debug.
13import Base
14import bend-osdev-word64@0.1.1.1/word64.bend as W
15import bend-osdev-bytes@0.1.1.1/bytes.bend as B
16import bend-osdev-acpi@0.1.2.0/error.bend as E
17import bend-osdev-acpi@0.1.2.0/dsdt.bend as D
18import bend-osdev-acpi@0.1.2.0/aml_value.bend as V
19import bend-osdev-acpi@0.1.2.0/aml_ns.bend as S
20import bend-osdev-acpi@0.1.2.0/aml_host.bend as Hs
21import bend-osdev-acpi@0.1.2.0/aml_interp.bend as I
22
23type AmlSystem<-H: Data> is Data:
24 AmlSystem{opts: I.AmlOptions, wide: Bool, ns: S.AmlNs, host: H}
25
26type AmlOutcome<-H: Data> is Data:
27 AmlOutcome{result: Result<&2, &2, E.AcpiError, V.AmlValue>, ns: S.AmlNs, host: H, steps: Nat, notes: List<&2, I.AmlNote>, debug: List<&2, V.AmlValue>}
28
29def AmlOutcome.result(-H: Data, o: AmlOutcome<H>) -> Result<&2, &2, E.AcpiError, V.AmlValue>:
30 match o:
31 case AmlOutcome{r, n, h, s, nt, d}:
32 r
33
34def AmlOutcome.steps(-H: Data, o: AmlOutcome<H>) -> Nat:
35 match o:
36 case AmlOutcome{r, n, h, s, nt, d}:
37 s
38
39def AmlOutcome.ns(-H: Data, o: AmlOutcome<H>) -> S.AmlNs:
40 match o:
41 case AmlOutcome{r, n, h, s, nt, d}:
42 n
43
44def AmlOutcome.host(-H: Data, o: AmlOutcome<H>) -> H:
45 match o:
46 case AmlOutcome{r, n, h, s, nt, d}:
47 h
48
49def AmlOutcome.notes(-H: Data, o: AmlOutcome<H>) -> List<&2, I.AmlNote>:
50 match o:
51 case AmlOutcome{r, n, h, s, nt, d}:
52 nt
53
54def AmlOutcome.debug(-H: Data, o: AmlOutcome<H>) -> List<&2, V.AmlValue>:
55 match o:
56 case AmlOutcome{r, n, h, s, nt, d}:
57 d
58
59# a system with the initial namespace (\_SB_, \_OSI, ...) and this host
60def AmlSystem.new(-H: Data, opts: I.AmlOptions, +wide: Bool, host: H) -> AmlSystem<H>:
61 match opts:
62 case I.AmlOptions{+osi, +os, +rev}:
63 AmlSystem{I.AmlOptions{osi, os, rev}, wide, S.AmlNs.initial(os, rev), host}
64
65def AmlSystem.ns(-H: Data, s: AmlSystem<H>) -> S.AmlNs:
66 match s:
67 case AmlSystem{o, w, n, h}:
68 n
69
70def AmlSystem.host(-H: Data, s: AmlSystem<H>) -> H:
71 match s:
72 case AmlSystem{o, w, n, h}:
73 h
74
75def AmlSystem.wide(-H: Data, s: AmlSystem<H>) -> Bool:
76 match s:
77 case AmlSystem{o, w, n, h}:
78 w
79
80# the system after an outcome: its namespace and host
81def AmlSystem.after(-H: Data, s: AmlSystem<H>, o: AmlOutcome<H>) -> AmlSystem<H>:
82 match s o:
83 case AmlSystem{op, w, n, h} AmlOutcome{r, n2, h2, st, nt, d}:
84 AmlSystem{op, w, n2, h2}
85
86def aml.rev.n(xs: List<&2, I.AmlNote>, acc: List<&2, I.AmlNote>) -> List<&2, I.AmlNote>:
87 match xs:
88 case Nil{}:
89 acc
90 case Con{x, t}:
91 aml.rev.n(t, Con{x, acc})
92
93def aml.rev.v(xs: List<&2, V.AmlValue>, acc: List<&2, V.AmlValue>) -> List<&2, V.AmlValue>:
94 match xs:
95 case Nil{}:
96 acc
97 case Con{x, t}:
98 aml.rev.v(t, Con{x, acc})
99
100def aml.result(md: I.AmlMode) -> Result<&2, &2, E.AcpiError, V.AmlValue>:
101 match md:
102 case I.AmlMDone{v}:
103 Done{v}
104 case I.AmlMFail{e}:
105 Fail{e}
106 case _:
107 Fail{E.AcpiAmlStepLimit{}}
108
109# what a run came to
110def AmlOutcome.of_run(-H: Data, r: I.AmlRun<H>) -> AmlOutcome<H>:
111 match r:
112 case I.AmlRun{I.AmlMachine{md, c, fs, I.AmlWorld{ctx, ns, h, I.AmlEnv{wd, o, nts, d, cl}}}, s}:
113 AmlOutcome{aml.result(md), ns, h, s, aml.rev.n(nts, Nil{}), aml.rev.v(d, Nil{})}
114
115def aml.env(+wide: Bool, opts: I.AmlOptions) -> I.AmlEnv:
116 I.AmlEnv{wide, opts, Nil{}, Nil{}, W.W64.zero()}
117
118def aml.ctx(+p: String, args: List<&2, V.AmlValue>) -> I.AmlCtx:
119 I.AmlCtx{p, args, I.in.locals(), Nil{}}
120
121# a machine at the start of a definition block, at the root
122def AmlSystem.loader(-H: Data, s: AmlSystem<H>, aml: B.Octets) -> I.AmlMachine<H>:
123 match s:
124 case AmlSystem{o, +wd, n, h}:
125 +code = B.Octets.to_list(aml)
126 I.AmlMachine{I.AmlMExec{}, I.AmlCur{code, B.len.fast(code)}, [I.AmlFTop{}], I.AmlWorld{aml.ctx("\\", Nil{}), n, h, aml.env(wd, o)}}
127
128def aml.read(-H: Data, r: Result<&2, &2, E.AcpiError, I.AmlRead<H>>, +w: I.AmlWorld<H>) -> I.AmlMachine<H>:
129 match r:
130 case Fail{e}:
131 I.AmlMachine{I.AmlMFail{e}, I.in.no.cur(), [I.AmlFTop{}], w}
132 case Done{I.AmlRead{w2, v}}:
133 I.AmlMachine{I.AmlMDone{v}, I.in.no.cur(), [I.AmlFTop{}], w2}
134
135def aml.start(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, o: Maybe<&2, S.AmlObject>, +p: String, args: List<&2, V.AmlValue>, +w: I.AmlWorld<H>) -> I.AmlMachine<H>:
136 match o:
137 case Some{S.AmlOMethod{n, f, +body}}:
138 +code = B.Octets.to_list(body)
139 I.AmlMachine{I.AmlMExec{}, I.AmlCur{code, B.len.fast(code)}, [I.AmlFTop{}], I.in.with_ctx(H, w, aml.ctx(p, args))}
140 case _:
141 aml.read(H, I.in.read_obj(~H, ~io, w, p, o), w)
142
143# arguments as the method sees them: Integers cut to 32 bits in a 32-bit
144# definition block
145def aml.fit.args(+wide: Bool, xs: List<&2, V.AmlValue>) -> List<&2, V.AmlValue>:
146 match xs:
147 case Nil{}:
148 Nil{}
149 case Con{V.AmlInt{x}, t}:
150 Con{V.AmlInt{V.AmlInt.fit(wide, x)}, aml.fit.args(wide, t)}
151 case Con{v, t}:
152 Con{v, aml.fit.args(wide, t)}
153
154# a machine about to evaluate the object at path p (a method is called
155# with args; any other object is read before the first step)
156def AmlSystem.caller(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, s: AmlSystem<H>, +p: String, args: List<&2, V.AmlValue>) -> I.AmlMachine<H>:
157 match s:
158 case AmlSystem{o, +wd, +n, h}:
159 +q = I.in.unalias(n, p)
160 aml.start(~H, ~io, S.AmlNs.get(n, q), q, aml.fit.args(wd, args), I.AmlWorld{aml.ctx("\\", Nil{}), n, h, aml.env(wd, o)})
161
162# a definition block run into the system's namespace, in at most n steps
163def Aml.load(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, s: AmlSystem<H>, aml: B.Octets, n: Nat) -> AmlOutcome<H>:
164 AmlOutcome.of_run(H, I.AmlM.run(~H, ~io, n, AmlSystem.loader(H, s, aml)))
165
166# the object at path p evaluated (a method called with args), in at most n
167# steps
168def Aml.eval(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, s: AmlSystem<H>, +p: String, args: List<&2, V.AmlValue>, n: Nat) -> AmlOutcome<H>:
169 AmlOutcome.of_run(H, I.AmlM.run(~H, ~io, n, AmlSystem.caller(~H, ~io, s, p, args)))
170
171def aml.boot.chk(-H: Data, r: Result<&2, &2, E.AcpiError, V.AmlValue>, s: AmlSystem<H>, o: AmlOutcome<H>) -> Result<&2, &2, E.AcpiError, AmlSystem<H>>:
172 match r:
173 case Fail{e}:
174 Fail{e}
175 case Done{v}:
176 Done{AmlSystem.after(H, s, o)}
177
178def aml.boot.res(-H: Data, s: AmlSystem<H>, +o: AmlOutcome<H>) -> Result<&2, &2, E.AcpiError, AmlSystem<H>>:
179 aml.boot.chk(H, AmlOutcome.result(H, o), s, o)
180
181def aml.boot.one(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, t: D.AcpiAml, +n: Nat, r: Result<&2, &2, E.AcpiError, AmlSystem<H>>) -> Result<&2, &2, E.AcpiError, AmlSystem<H>>:
182 match r:
183 case Fail{e}:
184 Fail{e}
185 case Done{+s}:
186 aml.boot.res(H, s, Aml.load(~H, ~io, s, D.AcpiAml.aml(t), n))
187
188def aml.boot.go(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, ts: List<&2, D.AcpiAml>, +n: Nat, r: Result<&2, &2, E.AcpiError, AmlSystem<H>>) -> Result<&2, &2, E.AcpiError, AmlSystem<H>>:
189 match ts:
190 case Nil{}:
191 r
192 case Con{t, rest}:
193 aml.boot.go(~H, ~io, rest, n, aml.boot.one(~H, ~io, t, n, r))
194
195# the namespace of a machine's tables: the DSDT, then each SSDT, each
196# loaded in at most n steps; the integer width is the DSDT's (the first
197# table's)
198def Aml.boot(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns<H>>, opts: I.AmlOptions, host: H, ts: List<&2, D.AcpiAml>, +n: Nat) -> Result<&2, &2, E.AcpiError, AmlSystem<H>>:
199 match ts:
200 case Nil{}:
201 Done{AmlSystem.new(H, opts, True{}, host)}
202 case Con{+t, rest}:
203 aml.boot.go(~H, ~io, Con{t, rest}, n, Done{AmlSystem.new(H, opts, D.AcpiAml.wide(t), host)})
204
205# The defaults: the in-memory host
206
207def Aml.mem_system(+wide: Bool) -> AmlSystem<Hs.AmlMemHost>:
208 AmlSystem.new(Hs.AmlMemHost, I.AmlOptions.default(), wide, Hs.AmlMemHost.new())
209
210def Aml.load_mem(s: AmlSystem<Hs.AmlMemHost>, aml: B.Octets, n: Nat) -> AmlOutcome<Hs.AmlMemHost>:
211 Aml.load(~Hs.AmlMemHost, ~Hs.AmlMemHost.io, s, aml, n)
212
213def Aml.eval_mem(s: AmlSystem<Hs.AmlMemHost>, +p: String, args: List<&2, V.AmlValue>, n: Nat) -> AmlOutcome<Hs.AmlMemHost>:
214 Aml.eval(~Hs.AmlMemHost, ~Hs.AmlMemHost.io, s, p, args, n)