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{})