aml.bend

bend-osdev-acpi@0.1.0.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.0.0/word64.bend as W
15import bend-osdev-bytes@0.1.0.0/bytes.bend as B
16import bend-osdev-acpi@0.1.0.0/error.bend as E
17import bend-osdev-acpi@0.1.0.0/dsdt.bend as D
18import bend-osdev-acpi@0.1.0.0/aml_value.bend as V
19import bend-osdev-acpi@0.1.0.0/aml_ns.bend as S
20import bend-osdev-acpi@0.1.0.0/aml_host.bend as Hs
21import bend-osdev-acpi@0.1.0.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)