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. 5 import Base 6 import bend-osdev-word64@0.1.1.1/word64.bend as W 7 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 8 import ./error.bend as E 9 10 # Where a value lives, for Store, RefOf and Index 11 type 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 24 type 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 41 def 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 61 def 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 68 def AmlInt.ones(wide: Bool) -> W.W64: 69 AmlInt.fit(wide, W.W64.max()) 70 71 # AML's True is Ones, False is Zero 72 def 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 79 def 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 89 def 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 100 def 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 115 def 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 118 def 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 121 def 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 130 def 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 140 def 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 155 def 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 158 def 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 165 def 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 177 def AmlValue.parse_int(+wide: Bool, +xs: List<&2, U32>) -> W.W64: 178 val.parse_int.pick(val.has0x(xs), wide, xs) 179 180 def 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 197 def 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 206 def 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 217 def 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 226 def val.hex.digit(+d: U32) -> U32: 227 val.hex.digit.pick(U32.is_lt(d, 10), d) 228 229 def 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 236 def 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 249 def 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 263 def 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 272 def 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 283 def 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 287 def 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 301 def 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 309 def 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 324 def 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 331 def 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 338 def 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 342 def val.sep(first: Bool) -> String: 343 match first: 344 case True{}: 345 "" 346 case False{}: 347 ", " 348 349 def 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 366 def 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 387 def AmlValue.show(v: AmlValue) -> String: 388 val.show.list([v], True{})