aml_value.bend

bend-osdev-acpi@0.1.2.0 · 388 lines · 0 definitions

1# bend-osdev-acpi, aml_value.bend: the values AML computes with (ACPI 6.5,
2# section 19.3.5, ASL Data Types, and 19.3.5.7, Data Type Conversion
3# Rules): integers (64 bits, or 32 in a definition block of revision
4# below 2), strings, buffers, packages, and object references.
5import Base
6import bend-osdev-word64@0.1.1.1/word64.bend as W
7import bend-osdev-bytes@0.1.1.1/bytes.bend as B
8import bend-osdev-acpi@0.1.2.0/error.bend as E
9
10# Where a value lives, for Store, RefOf and Index
11type AmlLoc is Data:
12  # a named object, by its absolute path ("\_SB_.PCI0.FOO_")
13  AmlLName{path: String}
14  AmlLLocal{i: Nat}
15  AmlLArg{i: Nat}
16  # element i of the buffer, string or package at a location
17  AmlLIndex{base: AmlLoc, i: Nat}
18  # element i of a value that has no location (Index of a temporary)
19  AmlLElem{v: AmlValue, i: Nat}
20  AmlLDebug{}
21  # the NullName target: results stored there are dropped
22  AmlLNone{}
23
24type AmlValue is Data:
25  AmlUninit{}
26  AmlInt{v: W.W64}
27  # a String (without its NUL)
28  AmlStr{s: B.Octets}
29  AmlBuf{b: B.Octets}
30  AmlPkg{xs: List<&2, AmlValue>}
31  # an object reference: RefOf, Index, or a name inside a package
32  AmlRef{loc: AmlLoc}
33  # a named object that holds no data (a device, a method, a region, ...)
34  # used as an operand: its path and ObjectType code
35  AmlObj{path: String, kind: U32}
36
37# ObjectType codes (chapter 19, ObjectType): 0 uninitialized, 1 integer,
38# 2 string, 3 buffer, 4 package, 5 field unit, 6 device, 7 event, 8 method,
39# 9 mutex, 10 operation region, 11 power resource, 12 processor, 13 thermal
40# zone, 14 buffer field, 16 debug object
41def AmlValue.type(v: AmlValue) -> U32:
42  match v:
43    case AmlUninit{}:
44      0
45    case AmlInt{x}:
46      1
47    case AmlStr{s}:
48      2
49    case AmlBuf{b}:
50      3
51    case AmlPkg{xs}:
52      4
53    case AmlRef{l}:
54      0
55    case AmlObj{p, k}:
56      k
57
58# Integers of the definition block's width
59
60# the low 32 bits only, when the block is 32-bit
61def AmlInt.fit(wide: Bool, +v: W.W64) -> W.W64:
62  match wide:
63    case True{}:
64      v
65    case False{}:
66      W.W64.from_u32(W.W64.lo(v))
67
68def AmlInt.ones(wide: Bool) -> W.W64:
69  AmlInt.fit(wide, W.W64.max())
70
71# AML's True is Ones, False is Zero
72def AmlInt.of_bool(+wide: Bool, b: Bool) -> W.W64:
73  match b:
74    case True{}:
75      AmlInt.ones(wide)
76    case False{}:
77      W.W64.zero()
78
79def AmlInt.width_bytes(wide: Bool) -> Nat:
80  match wide:
81    case True{}:
82      8n
83    case False{}:
84      4n
85
86# Conversions (19.3.5.7)
87
88# up to n bytes, little-endian
89def val.le.go(n: Nat, xs: List<&2, U32>, +sh: Nat, acc: W.W64) -> W.W64:
90  match n:
91    case 0n:
92      acc
93    case 1n+p:
94      match xs:
95        case Nil{}:
96          acc
97        case Con{h, t}:
98          val.le.go(p, t, Nat.add(sh, 8n), W.W64.or(acc, W.W64.shl(W.W64.from_u32(U32.and(h, 255)), sh)))
99
100def val.hexdig.pick(d: Bool, u: Bool, l: Bool, +c: U32) -> Maybe<&2, U32>:
101  match d:
102    case True{}:
103      Some{U32.sub(c, 48)}
104    case False{}:
105      match u:
106        case True{}:
107          Some{U32.sub(c, 55)}
108        case False{}:
109          match l:
110            case True{}:
111              Some{U32.sub(c, 87)}
112            case False{}:
113              None{}
114
115def val.hexdig(+c: U32) -> Maybe<&2, U32>:
116  val.hexdig.pick(Bool.and(U32.is_le(48, c), U32.is_le(c, 57)), Bool.and(U32.is_le(65, c), U32.is_le(c, 70)), Bool.and(U32.is_le(97, c), U32.is_le(c, 102)), c)
117
118def val.decdig(+c: U32) -> Maybe<&2, U32>:
119  val.hexdig.pick(Bool.and(U32.is_le(48, c), U32.is_le(c, 57)), False{}, False{}, c)
120
121def val.dig.head(hex: Bool, xs: List<&2, U32>) -> Maybe<&2, U32>:
122  match hex xs:
123    case _ Nil{}:
124      None{}
125    case True{} Con{+h, t}:
126      val.hexdig(h)
127    case False{} Con{+h, t}:
128      val.decdig(h)
129
130def val.base(hex: Bool) -> W.W64:
131  match hex:
132    case True{}:
133      W.W64.from_u32(16)
134    case False{}:
135      W.W64.from_u32(10)
136
137
138# digits from the front of a string, up to the first other character or
139# n digits; m: the first character's digit value
140def val.digits(n: Nat, xs: List<&2, U32>, m: Maybe<&2, U32>, acc: W.W64, +hex: Bool) -> W.W64:
141  match n:
142    case 0n:
143      acc
144    case 1n+p:
145      match xs:
146        case Nil{}:
147          acc
148        case Con{h, +t}:
149          match m:
150            case None{}:
151              acc
152            case Some{d}:
153              val.digits(p, t, val.dig.head(hex, t), W.W64.add(W.W64.mul(acc, val.base(hex)), W.W64.from_u32(d)), hex)
154
155def val.hex.parse(+wide: Bool, +xs: List<&2, U32>) -> W.W64:
156  val.digits(Nat.mul(2n, AmlInt.width_bytes(wide)), xs, val.dig.head(True{}, xs), W.W64.zero(), True{})
157
158def val.has0x(xs: List<&2, U32>) -> Bool:
159  match xs:
160    case Con{a, Con{+b, t}}:
161      Bool.and(U32.is_eq(a, 48), Bool.or(U32.is_eq(b, 120), U32.is_eq(b, 88)))
162    case _:
163      False{}
164
165def val.parse_int.pick(hex: Bool, +wide: Bool, +xs: List<&2, U32>) -> W.W64:
166  match hex:
167    case True{}:
168      AmlInt.fit(wide, val.hex.parse(wide, B.drop(2n, xs)))
169    case False{}:
170      AmlInt.fit(wide, val.digits(20n, xs, val.dig.head(False{}, xs), W.W64.zero(), False{}))
171
172# the implicit conversion to Integer: a buffer's first 8 (or 4) bytes,
173# little-endian; a string's leading hexadecimal digits
174
175# a String as an Integer, as ToInteger reads it: hexadecimal after 0x,
176# decimal otherwise
177def AmlValue.parse_int(+wide: Bool, +xs: List<&2, U32>) -> W.W64:
178  val.parse_int.pick(val.has0x(xs), wide, xs)
179
180def AmlValue.to_int(+wide: Bool, v: AmlValue) -> Result<&2, &2, E.AcpiError, W.W64>:
181  match v:
182    case AmlInt{x}:
183      Done{AmlInt.fit(wide, x)}
184    case AmlBuf{b}:
185      Done{val.le.go(AmlInt.width_bytes(wide), B.Octets.to_list(b), 0n, W.W64.zero())}
186    case AmlStr{s}:
187      Done{val.hex.parse(wide, B.Octets.to_list(s))}
188    case AmlUninit{}:
189      Fail{E.AcpiAmlBadType{"uninitialized value used as an integer"}}
190    case AmlPkg{xs}:
191      Fail{E.AcpiAmlBadType{"package used as an integer"}}
192    case AmlRef{l}:
193      Fail{E.AcpiAmlBadType{"reference used as an integer"}}
194    case AmlObj{p, k}:
195      Fail{E.AcpiAmlBadType{"object used as an integer"}}
196
197def val.int.bytes(wide: Bool, +x: W.W64) -> B.Octets:
198  match wide:
199    case True{}:
200      B.Octets.le64(x)
201    case False{}:
202      B.Octets.le32(W.W64.lo(x))
203
204# the implicit conversion to Buffer: an integer's 8 (or 4) bytes,
205# little-endian; a string's bytes and its NUL
206def AmlValue.to_buf(+wide: Bool, v: AmlValue) -> Result<&2, &2, E.AcpiError, B.Octets>:
207  match v:
208    case AmlInt{x}:
209      Done{val.int.bytes(wide, x)}
210    case AmlBuf{b}:
211      Done{b}
212    case AmlStr{s}:
213      Done{B.Octets.append(s, B.Octets.of_list([0]))}
214    case _:
215      Fail{E.AcpiAmlBadType{"cannot convert to a buffer"}}
216
217def val.hex.digit.pick(lt: Bool, +d: U32) -> U32:
218  match lt:
219    case True{}:
220      U32.add(48, d)
221    case False{}:
222      U32.add(55, d)
223
224# n hex digits of x, most significant first, upper case
225
226def val.hex.digit(+d: U32) -> U32:
227  val.hex.digit.pick(U32.is_lt(d, 10), d)
228
229def val.hex.text(n: Nat, +x: W.W64, acc: List<&2, U32>) -> List<&2, U32>:
230  match n:
231    case 0n:
232      acc
233    case 1n+p:
234      val.hex.text(p, W.W64.shr(x, 4n), Con{val.hex.digit(U32.and(W.W64.lo(x), 15)), acc})
235
236def val.buf.text(xs: List<&2, U32>, first: Bool) -> List<&2, U32>:
237  match xs:
238    case Nil{}:
239      Nil{}
240    case Con{+h, t}:
241      match first:
242        case True{}:
243          Con{val.hex.digit(U32.shrn(h, 4n)), Con{val.hex.digit(U32.and(h, 15)), val.buf.text(t, False{})}}
244        case False{}:
245          Con{32, Con{val.hex.digit(U32.shrn(h, 4n)), Con{val.hex.digit(U32.and(h, 15)), val.buf.text(t, False{})}}}
246
247# the implicit conversion to String: an integer as 16 (or 8) hex digits; a
248# buffer as two hex digits per byte, separated by spaces
249def AmlValue.to_str(+wide: Bool, v: AmlValue) -> Result<&2, &2, E.AcpiError, B.Octets>:
250  match v:
251    case AmlInt{x}:
252      Done{B.Octets.of_list(val.hex.text(Nat.mul(2n, AmlInt.width_bytes(wide)), x, Nil{}))}
253    case AmlStr{s}:
254      Done{s}
255    case AmlBuf{b}:
256      Done{B.Octets.of_list(val.buf.text(B.Octets.to_list(b), True{}))}
257    case _:
258      Fail{E.AcpiAmlBadType{"cannot convert to a string"}}
259
260# Comparison (chapter 19, LEqual, LGreater, LLess): integers as
261# unsigned numbers; strings and buffers byte by byte, a prefix first
262
263def val.cmp.then(prev: Cmp, c: Cmp) -> Cmp:
264  match prev:
265    case EQ{}:
266      c
267    case LT{}:
268      LT{}
269    case GT{}:
270      GT{}
271
272def val.cmp.go(xs: List<&2, U32>, ys: List<&2, U32>, prev: Cmp) -> Cmp:
273  match xs ys:
274    case Nil{} Nil{}:
275      prev
276    case Nil{} Con{y, t}:
277      val.cmp.then(prev, LT{})
278    case Con{x, t} Nil{}:
279      val.cmp.then(prev, GT{})
280    case Con{+x, xt} Con{+y, yt}:
281      val.cmp.go(xt, yt, val.cmp.then(prev, U32.cmp(x, y)))
282
283def val.bytes.cmp(xs: List<&2, U32>, ys: List<&2, U32>) -> Cmp:
284  val.cmp.go(xs, ys, EQ{})
285
286# the comparison of a with b, b converted to a's type
287def AmlValue.compare(+wide: Bool, a: AmlValue, +b: AmlValue) -> Result<&2, &2, E.AcpiError, Cmp>:
288  match a:
289    case AmlInt{x}:
290      Result.map(&2, &2, E.AcpiError, W.W64, Cmp, y => W.W64.cmp(AmlInt.fit(wide, x), y), AmlValue.to_int(wide, b))
291    case AmlStr{s}:
292      Result.map(&2, &2, E.AcpiError, B.Octets, Cmp, t => val.bytes.cmp(B.Octets.to_list(s), B.Octets.to_list(t)), AmlValue.to_str(wide, b))
293    case AmlBuf{s}:
294      Result.map(&2, &2, E.AcpiError, B.Octets, Cmp, t => val.bytes.cmp(B.Octets.to_list(s), B.Octets.to_list(t)), AmlValue.to_buf(wide, b))
295    case _:
296      Fail{E.AcpiAmlBadType{"cannot compare"}}
297
298# Text, for tests and debugging: integers in hex ("0x1f"), strings quoted,
299# buffers as "buf[01 ab]", packages as "{a, b}", references as "ref"
300
301def val.lz.z(xs: List<&2, U32>) -> Bool:
302  match xs:
303    case Nil{}:
304      False{}
305    case Con{+h, +t}:
306      Bool.and(U32.is_eq(h, 48), Bool.not(List.is_empty(&2, U32, t)))
307
308# leading zeros dropped (one kept); z: the head is a zero with more after it
309def val.lz(xs: List<&2, U32>, still: Bool, z: Bool) -> List<&2, U32>:
310  match xs:
311    case Nil{}:
312      Nil{}
313    case Con{h, +t}:
314      match still:
315        case True{}:
316          match z:
317            case True{}:
318              val.lz(t, True{}, val.lz.z(t))
319            case False{}:
320              Con{h, val.lz(t, False{}, False{})}
321        case False{}:
322          Con{h, val.lz(t, False{}, False{})}
323
324def val.lower.pick(up: Bool, +h: U32) -> U32:
325  match up:
326    case True{}:
327      U32.add(h, 32)
328    case False{}:
329      h
330
331def val.lower(xs: List<&2, U32>) -> List<&2, U32>:
332  match xs:
333    case Nil{}:
334      Nil{}
335    case Con{+h, t}:
336      Con{val.lower.pick(U32.is_le(65, h), h), val.lower(t)}
337
338def AmlValue.show_int(+x: W.W64) -> String:
339  +ds = val.hex.text(16n, x, Nil{})
340  "0x" ++ B.to_string(val.lower(val.lz(ds, True{}, val.lz.z(ds))))
341
342def val.sep(first: Bool) -> String:
343  match first:
344    case True{}:
345      ""
346    case False{}:
347      ", "
348
349def val.ref.show(l: AmlLoc) -> String:
350  match l:
351    case AmlLName{p}:
352      "ref " ++ p
353    case AmlLLocal{i}:
354      "ref Local" ++ Nat.show(i)
355    case AmlLArg{i}:
356      "ref Arg" ++ Nat.show(i)
357    case AmlLIndex{b, i}:
358      "ref index " ++ Nat.show(i)
359    case AmlLElem{v, i}:
360      "ref element " ++ Nat.show(i)
361    case AmlLDebug{}:
362      "ref Debug"
363    case AmlLNone{}:
364      "ref none"
365
366def val.show.list(vs: List<&2, AmlValue>, +first: Bool) -> String:
367  match vs:
368    case Nil{}:
369      ""
370    case Con{v, rest}:
371      match v:
372        case AmlPkg{xs}:
373          val.sep(first) ++ "{" ++ val.show.list(xs, True{}) ++ "}" ++ val.show.list(rest, False{})
374        case AmlUninit{}:
375          val.sep(first) ++ "uninit" ++ val.show.list(rest, False{})
376        case AmlInt{x}:
377          val.sep(first) ++ AmlValue.show_int(x) ++ val.show.list(rest, False{})
378        case AmlStr{t}:
379          val.sep(first) ++ "\"" ++ B.Octets.to_string(t) ++ "\"" ++ val.show.list(rest, False{})
380        case AmlBuf{b}:
381          val.sep(first) ++ "buf[" ++ B.to_string(val.lower(val.buf.text(B.Octets.to_list(b), True{}))) ++ "]" ++ val.show.list(rest, False{})
382        case AmlRef{l}:
383          val.sep(first) ++ val.ref.show(l) ++ val.show.list(rest, False{})
384        case AmlObj{p, k}:
385          val.sep(first) ++ "object " ++ p ++ val.show.list(rest, False{})
386
387def AmlValue.show(v: AmlValue) -> String:
388  val.show.list([v], True{})