aml_term.bend

bend-osdev-acpi@0.1.0.0 · 440 lines · 0 definitions

1# bend-osdev-acpi, aml_term.bend: building AML (ACPI 6.5, chapter 20, AML
2# Specification): terms and their encoding, with a constructor for each
3# ASL operator this package uses (chapter 19 names them), so that a
4# definition block can be written in Bend:
5#
6#   AmlT.scope("\\_SB", [AmlT.device("PCI0", [
7#     AmlT.name("_HID", AmlT.eisaid("PNP0A03")),
8#     AmlT.method("_STA", 0n, False{}, [AmlT.ret(AmlT.int32(15))])])])
9#
10# A term is a number, a string, raw bytes, an opcode with operands, or a
11# package (an opcode, then a PkgLength covering a head and a body), which
12# is enough for every encoding in chapter 20: the constructors below fill
13# them in. Operands are lists, so that encoding is one structural
14# recursion.
15import Base
16import bend-osdev-word64@0.1.0.0/word64.bend as W
17import bend-osdev-bytes@0.1.0.0/bytes.bend as B
18import bend-osdev-acpi@0.1.0.0/aml_pkglength.bend as K
19import bend-osdev-acpi@0.1.0.0/aml_name.bend as N
20
21type AmlTerm is Data:
22  # an integer, in its shortest encoding: ZeroOp, OneOp, OnesOp (all 64
23  # bits set), or the Byte, Word, DWord or QWord prefix
24  AmlTInt{v: W.W64}
25  # a String (AsciiCharList, then the NUL the encoder adds)
26  AmlTStr{s: B.Octets}
27  # bytes as they are: a NameString, Local0, Debug, ...
28  AmlTRaw{bytes: B.Octets}
29  # an opcode (or a NameString, for a method call) followed by operands
30  AmlTOp{code: B.Octets, args: List<&2, AmlTerm>}
31  # an opcode, then a PkgLength covering head and body
32  AmlTPkg{code: B.Octets, head: B.Octets, body: List<&2, AmlTerm>}
33
34# Field elements (20.2.5.2, FieldList)
35type AmlFieldElem is Data:
36  # NamedField: a NameSeg and its width in bits
37  AmlFNamed{seg: B.Octets, bits: U32}
38  # ReservedField (ASL Offset): bits skipped
39  AmlFReserved{bits: U32}
40  # AccessField: access type and attribute from here on
41  AmlFAccess{access_type: U32, attrib: U32}
42
43# Encoding
44
45def tm.b(xs: List<&2, U32>) -> B.Octets:
46  B.Octets.of_list(xs)
47
48def tm.int.pick(z: Bool, o: Bool, m: Bool, b8: Bool, b16: Bool, b32: Bool, +v: W.W64) -> B.Octets:
49  match z:
50    case True{}:
51      tm.b([0])
52    case False{}:
53      match o:
54        case True{}:
55          tm.b([1])
56        case False{}:
57          match m:
58            case True{}:
59              tm.b([255])
60            case False{}:
61              match b8:
62                case True{}:
63                  tm.b([10, W.W64.lo(v)])
64                case False{}:
65                  match b16:
66                    case True{}:
67                      B.Octets.append(tm.b([11]), B.Octets.le16(W.W64.lo(v)))
68                    case False{}:
69                      match b32:
70                        case True{}:
71                          B.Octets.append(tm.b([12]), B.Octets.le32(W.W64.lo(v)))
72                        case False{}:
73                          B.Octets.append(tm.b([14]), B.Octets.le64(v))
74
75def tm.int(+v: W.W64) -> B.Octets:
76  +lo = W.W64.lo(v)
77  +small = U32.is_eq(W.W64.hi(v), 0)
78  tm.int.pick(W.W64.is_zero(v), W.W64.is_eq(v, W.W64.one()), W.W64.is_eq(v, W.W64.max()), Bool.and(small, U32.is_lt(lo, 256)), Bool.and(small, U32.is_lt(lo, 65536)), small, v)
79
80def tm.str(+s: B.Octets) -> B.Octets:
81  B.Octets.concat([tm.b([13]), s, tm.b([0])])
82
83# a term list; every term's operands and body are sublists, so this is one
84# structural recursion
85def AmlT.encode(ts: List<&2, AmlTerm>) -> B.Octets:
86  match ts:
87    case Nil{}:
88      B.Octets.empty()
89    case Con{t, rest}:
90      match t:
91        case AmlTInt{v}:
92          B.Octets.append(tm.int(v), AmlT.encode(rest))
93        case AmlTStr{s}:
94          B.Octets.append(tm.str(s), AmlT.encode(rest))
95        case AmlTRaw{bs}:
96          B.Octets.append(bs, AmlT.encode(rest))
97        case AmlTOp{c, args}:
98          B.Octets.concat([c, AmlT.encode(args), AmlT.encode(rest)])
99        case AmlTPkg{c, h, body}:
100          B.Octets.concat([c, K.AmlPkgLength.wrap(B.Octets.append(h, AmlT.encode(body))), AmlT.encode(rest)])
101
102def AmlT.encode1(t: AmlTerm) -> B.Octets:
103  AmlT.encode([t])
104
105def tm.field.enc(es: List<&2, AmlFieldElem>) -> B.Octets:
106  match es:
107    case Nil{}:
108      B.Octets.empty()
109    case Con{AmlFNamed{s, n}, t}:
110      B.Octets.concat([s, K.AmlPkgLength.encode(n), tm.field.enc(t)])
111    case Con{AmlFReserved{n}, t}:
112      B.Octets.concat([tm.b([0]), K.AmlPkgLength.encode(n), tm.field.enc(t)])
113    case Con{AmlFAccess{a, b}, t}:
114      B.Octets.append(tm.b([1, a, b]), tm.field.enc(t))
115
116# Data objects (20.2.3)
117
118def AmlT.int(v: W.W64) -> AmlTerm:
119  AmlTInt{v}
120
121def AmlT.int32(v: U32) -> AmlTerm:
122  AmlTInt{W.W64.from_u32(v)}
123
124def AmlT.zero() -> AmlTerm:
125  AmlTInt{W.W64.zero()}
126
127def AmlT.one() -> AmlTerm:
128  AmlTInt{W.W64.one()}
129
130def AmlT.ones() -> AmlTerm:
131  AmlTRaw{tm.b([255])}
132
133def AmlT.str(s: String) -> AmlTerm:
134  AmlTStr{B.Octets.of_string(s)}
135
136def AmlT.revision() -> AmlTerm:
137  AmlTRaw{tm.b([91, 48])}
138
139# a Buffer of size bytes (a term), initialised from bytes
140def AmlT.buffer(size: AmlTerm, bytes: B.Octets) -> AmlTerm:
141  AmlTPkg{tm.b([17]), B.Octets.empty(), [size, AmlTRaw{bytes}]}
142
143# a Buffer holding exactly these bytes
144def AmlT.buf(+bytes: B.Octets) -> AmlTerm:
145  AmlT.buffer(AmlT.int(W.W64.from_nat(B.Octets.len(bytes))), bytes)
146
147def AmlT.package(+elems: List<&2, AmlTerm>) -> AmlTerm:
148  AmlTPkg{tm.b([18]), tm.b([U32.from_nat(List.length(&2, AmlTerm, elems))]), elems}
149
150def AmlT.var_package(count: AmlTerm, elems: List<&2, AmlTerm>) -> AmlTerm:
151  AmlTPkg{tm.b([19]), B.Octets.empty(), Con{count, elems}}
152
153# EISAID("PNP0A03") (chapter 19, EISAID): three letters of five bits each and four hex
154# digits, stored most significant byte first, as a DWord
155def tm.hex.pick(digit: Bool, upper: Bool, +c: U32) -> U32:
156  match digit:
157    case True{}:
158      U32.sub(c, 48)
159    case False{}:
160      match upper:
161        case True{}:
162          U32.and(U32.sub(c, 55), 15)
163        case False{}:
164          U32.and(U32.sub(c, 87), 15)
165
166def tm.hex(+c: U32) -> U32:
167  tm.hex.pick(U32.is_le(c, 57), U32.is_le(65, c), c)
168
169def tm.eisa(xs: List<&2, U32>) -> U32:
170  match xs:
171    case Con{a, Con{b, Con{c, Con{d0, Con{d1, Con{d2, Con{d3, t}}}}}}}:
172      +hi = U32.or(U32.shln(U32.and(U32.sub(a, 64), 31), 10n), U32.or(U32.shln(U32.and(U32.sub(b, 64), 31), 5n), U32.and(U32.sub(c, 64), 31)))
173      +lo = U32.or(U32.shln(tm.hex(d0), 12n), U32.or(U32.shln(tm.hex(d1), 8n), U32.or(U32.shln(tm.hex(d2), 4n), tm.hex(d3))))
174      U32.or(U32.or(U32.shrn(hi, 8n), U32.shln(U32.and(hi, 255), 8n)), U32.or(U32.shln(U32.shrn(lo, 8n), 16n), U32.shln(U32.and(lo, 255), 24n)))
175    case _:
176      0
177
178def AmlT.eisaid_value(s: String) -> U32:
179  tm.eisa(B.of_string(s))
180
181def AmlT.eisaid(s: String) -> AmlTerm:
182  AmlT.int32(AmlT.eisaid_value(s))
183
184# Names (20.2.2): a name as an operand, a method call, Local and Arg
185
186def tm.name(s: String) -> B.Octets:
187  N.AmlName.encode(N.AmlName.of_text(s))
188
189# a name as a term (its value, a reference to it in a package, or a call
190# of a method that takes no arguments)
191def AmlT.nm(s: String) -> AmlTerm:
192  AmlTRaw{tm.name(s)}
193
194def AmlT.call(s: String, args: List<&2, AmlTerm>) -> AmlTerm:
195  AmlTOp{tm.name(s), args}
196
197def AmlT.local(i: U32) -> AmlTerm:
198  AmlTRaw{tm.b([U32.add(96, U32.and(i, 7))])}
199
200def AmlT.arg(i: U32) -> AmlTerm:
201  AmlTRaw{tm.b([U32.add(104, U32.min(i, 6))])}
202
203def AmlT.debug() -> AmlTerm:
204  AmlTRaw{tm.b([91, 49])}
205
206# NullName, the Target that discards a result
207def AmlT.none() -> AmlTerm:
208  AmlTRaw{tm.b([0])}
209
210# Named objects and scopes (20.2.5.1 to 20.2.5.2)
211
212def AmlT.name(s: String, v: AmlTerm) -> AmlTerm:
213  AmlTOp{B.Octets.append(tm.b([8]), tm.name(s)), [v]}
214
215def AmlT.scope(s: String, body: List<&2, AmlTerm>) -> AmlTerm:
216  AmlTPkg{tm.b([16]), tm.name(s), body}
217
218def AmlT.device(s: String, body: List<&2, AmlTerm>) -> AmlTerm:
219  AmlTPkg{tm.b([91, 130]), tm.name(s), body}
220
221def tm.bit(b: Bool, v: U32) -> U32:
222  match b:
223    case True{}:
224      v
225    case False{}:
226      0
227
228# a method of nargs arguments (0 to 7), serialized or not, sync level 0
229def AmlT.method(s: String, nargs: Nat, ser: Bool, body: List<&2, AmlTerm>) -> AmlTerm:
230  AmlTPkg{tm.b([20]), B.Octets.append(tm.name(s), tm.b([U32.or(U32.and(U32.from_nat(nargs), 7), tm.bit(ser, 8))])), body}
231
232def AmlT.processor(s: String, id: U32, pblk: U32, plen: U32, body: List<&2, AmlTerm>) -> AmlTerm:
233  AmlTPkg{tm.b([91, 131]), B.Octets.concat([tm.name(s), tm.b([id]), B.Octets.le32(pblk), tm.b([plen])]), body}
234
235def AmlT.power_resource(s: String, level: U32, order: U32, body: List<&2, AmlTerm>) -> AmlTerm:
236  AmlTPkg{tm.b([91, 132]), B.Octets.concat([tm.name(s), tm.b([level]), B.Octets.le16(order)]), body}
237
238def AmlT.thermal_zone(s: String, body: List<&2, AmlTerm>) -> AmlTerm:
239  AmlTPkg{tm.b([91, 133]), tm.name(s), body}
240
241# OperationRegion(name, space, offset, length): space 0 SystemMemory,
242# 1 SystemIO, 2 PCI_Config, 3 EmbeddedControl, ...
243def AmlT.region(s: String, space: U32, off: AmlTerm, len: AmlTerm) -> AmlTerm:
244  AmlTOp{B.Octets.concat([tm.b([91, 128]), tm.name(s), tm.b([space])]), [off, len]}
245
246# FieldFlags (20.2.5.2): access type 0 AnyAcc, 1 ByteAcc, 2 WordAcc,
247# 3 DWordAcc, 4 QWordAcc, 5 BufferAcc; lock; update rule 0 Preserve,
248# 1 WriteAsOnes, 2 WriteAsZeros
249def AmlT.field_flags(access: U32, lock: Bool, update: U32) -> U32:
250  U32.or(U32.and(access, 15), U32.or(tm.bit(lock, 16), U32.shln(U32.and(update, 3), 5n)))
251
252def AmlT.field(region: String, flags: U32, es: List<&2, AmlFieldElem>) -> AmlTerm:
253  AmlTPkg{tm.b([91, 129]), B.Octets.append(tm.name(region), tm.b([flags])), [AmlTRaw{tm.field.enc(es)}]}
254
255def AmlT.index_field(index: String, data: String, flags: U32, es: List<&2, AmlFieldElem>) -> AmlTerm:
256  AmlTPkg{tm.b([91, 134]), B.Octets.concat([tm.name(index), tm.name(data), tm.b([flags])]), [AmlTRaw{tm.field.enc(es)}]}
257
258def AmlT.fnamed(s: String, bits: U32) -> AmlFieldElem:
259  AmlFNamed{N.AmlName.seg(s), bits}
260
261def AmlT.mutex(s: String, sync: U32) -> AmlTerm:
262  AmlTRaw{B.Octets.concat([tm.b([91, 1]), tm.name(s), tm.b([sync])])}
263
264def AmlT.event(s: String) -> AmlTerm:
265  AmlTRaw{B.Octets.append(tm.b([91, 2]), tm.name(s))}
266
267def AmlT.alias(src: String, dst: String) -> AmlTerm:
268  AmlTRaw{B.Octets.concat([tm.b([6]), tm.name(src), tm.name(dst)])}
269
270def AmlT.external(s: String, kind: U32, nargs: U32) -> AmlTerm:
271  AmlTRaw{B.Octets.concat([tm.b([21]), tm.name(s), tm.b([kind, nargs])])}
272
273# CreateBitField, CreateByteField, CreateWordField, CreateDWordField,
274# CreateQWordField (op 141, 140, 139, 138, 143): a field of a buffer
275def AmlT.create_field(op: U32, src: AmlTerm, index: AmlTerm, s: String) -> AmlTerm:
276  AmlTOp{tm.b([op]), [src, index, AmlTRaw{tm.name(s)}]}
277
278def AmlT.create_dword_field(src: AmlTerm, index: AmlTerm, s: String) -> AmlTerm:
279  AmlT.create_field(138, src, index, s)
280
281# Statements (20.2.5.3)
282
283def AmlT.if_(pred: AmlTerm, body: List<&2, AmlTerm>) -> AmlTerm:
284  AmlTPkg{tm.b([160]), B.Octets.empty(), Con{pred, body}}
285
286def AmlT.if_else(pred: AmlTerm, body: List<&2, AmlTerm>, els: List<&2, AmlTerm>) -> AmlTerm:
287  AmlTOp{B.Octets.empty(), [AmlT.if_(pred, body), AmlTPkg{tm.b([161]), B.Octets.empty(), els}]}
288
289def AmlT.while_(pred: AmlTerm, body: List<&2, AmlTerm>) -> AmlTerm:
290  AmlTPkg{tm.b([162]), B.Octets.empty(), Con{pred, body}}
291
292def AmlT.ret(v: AmlTerm) -> AmlTerm:
293  AmlTOp{tm.b([164]), [v]}
294
295def AmlT.brk() -> AmlTerm:
296  AmlTRaw{tm.b([165])}
297
298def AmlT.cont() -> AmlTerm:
299  AmlTRaw{tm.b([159])}
300
301def AmlT.noop() -> AmlTerm:
302  AmlTRaw{tm.b([163])}
303
304def AmlT.notify(obj: AmlTerm, v: AmlTerm) -> AmlTerm:
305  AmlTOp{tm.b([134]), [obj, v]}
306
307def AmlT.sleep(ms: AmlTerm) -> AmlTerm:
308  AmlTOp{tm.b([91, 34]), [ms]}
309
310def AmlT.stall(us: AmlTerm) -> AmlTerm:
311  AmlTOp{tm.b([91, 33]), [us]}
312
313def AmlT.acquire(m: AmlTerm, timeout: U32) -> AmlTerm:
314  AmlTOp{tm.b([91, 35]), [m, AmlTRaw{B.Octets.le16(timeout)}]}
315
316def AmlT.release(m: AmlTerm) -> AmlTerm:
317  AmlTOp{tm.b([91, 39]), [m]}
318
319# Expressions (20.2.5.4): opcode, operands, then the Target (a name, a
320# Local, Debug, or AmlT.none())
321
322def AmlT.op(op: U32, args: List<&2, AmlTerm>) -> AmlTerm:
323  AmlTOp{tm.b([op]), args}
324
325def AmlT.store(v: AmlTerm, target: AmlTerm) -> AmlTerm:
326  AmlT.op(112, [v, target])
327
328def AmlT.copy_object(v: AmlTerm, target: AmlTerm) -> AmlTerm:
329  AmlT.op(157, [v, target])
330
331def AmlT.add(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
332  AmlT.op(114, [a, b, t])
333
334def AmlT.subtract(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
335  AmlT.op(116, [a, b, t])
336
337def AmlT.multiply(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
338  AmlT.op(119, [a, b, t])
339
340# Divide(dividend, divisor, remainder target, quotient target)
341def AmlT.divide(a: AmlTerm, b: AmlTerm, rem: AmlTerm, quo: AmlTerm) -> AmlTerm:
342  AmlT.op(120, [a, b, rem, quo])
343
344def AmlT.mod(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
345  AmlT.op(133, [a, b, t])
346
347def AmlT.shift_left(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
348  AmlT.op(121, [a, b, t])
349
350def AmlT.shift_right(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
351  AmlT.op(122, [a, b, t])
352
353def AmlT.and(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
354  AmlT.op(123, [a, b, t])
355
356def AmlT.nand(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
357  AmlT.op(124, [a, b, t])
358
359def AmlT.or(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
360  AmlT.op(125, [a, b, t])
361
362def AmlT.nor(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
363  AmlT.op(126, [a, b, t])
364
365def AmlT.xor(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
366  AmlT.op(127, [a, b, t])
367
368def AmlT.not(a: AmlTerm, t: AmlTerm) -> AmlTerm:
369  AmlT.op(128, [a, t])
370
371def AmlT.find_set_left_bit(a: AmlTerm, t: AmlTerm) -> AmlTerm:
372  AmlT.op(129, [a, t])
373
374def AmlT.find_set_right_bit(a: AmlTerm, t: AmlTerm) -> AmlTerm:
375  AmlT.op(130, [a, t])
376
377def AmlT.increment(t: AmlTerm) -> AmlTerm:
378  AmlT.op(117, [t])
379
380def AmlT.decrement(t: AmlTerm) -> AmlTerm:
381  AmlT.op(118, [t])
382
383def AmlT.concat(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm:
384  AmlT.op(115, [a, b, t])
385
386def AmlT.land(a: AmlTerm, b: AmlTerm) -> AmlTerm:
387  AmlT.op(144, [a, b])
388
389def AmlT.lor(a: AmlTerm, b: AmlTerm) -> AmlTerm:
390  AmlT.op(145, [a, b])
391
392def AmlT.lnot(a: AmlTerm) -> AmlTerm:
393  AmlT.op(146, [a])
394
395def AmlT.lequal(a: AmlTerm, b: AmlTerm) -> AmlTerm:
396  AmlT.op(147, [a, b])
397
398def AmlT.lgreater(a: AmlTerm, b: AmlTerm) -> AmlTerm:
399  AmlT.op(148, [a, b])
400
401def AmlT.lless(a: AmlTerm, b: AmlTerm) -> AmlTerm:
402  AmlT.op(149, [a, b])
403
404# LNotEqual, LLessEqual, LGreaterEqual: LNot of LEqual, LGreater, LLess
405def AmlT.lnot_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm:
406  AmlT.lnot(AmlT.lequal(a, b))
407
408def AmlT.lless_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm:
409  AmlT.lnot(AmlT.lgreater(a, b))
410
411def AmlT.lgreater_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm:
412  AmlT.lnot(AmlT.lless(a, b))
413
414# References
415
416def AmlT.ref_of(a: AmlTerm) -> AmlTerm:
417  AmlT.op(113, [a])
418
419def AmlT.deref_of(a: AmlTerm) -> AmlTerm:
420  AmlT.op(131, [a])
421
422def AmlT.index(a: AmlTerm, i: AmlTerm, t: AmlTerm) -> AmlTerm:
423  AmlT.op(136, [a, i, t])
424
425def AmlT.cond_ref_of(a: AmlTerm, t: AmlTerm) -> AmlTerm:
426  AmlTOp{tm.b([91, 18]), [a, t]}
427
428def AmlT.size_of(a: AmlTerm) -> AmlTerm:
429  AmlT.op(135, [a])
430
431def AmlT.object_type(a: AmlTerm) -> AmlTerm:
432  AmlT.op(142, [a])
433
434# Conversions
435
436def AmlT.to_integer(a: AmlTerm, t: AmlTerm) -> AmlTerm:
437  AmlT.op(153, [a, t])
438
439def AmlT.to_buffer(a: AmlTerm, t: AmlTerm) -> AmlTerm:
440  AmlT.op(150, [a, t])