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. 15 import Base 16 import bend-osdev-word64@0.1.1.1/word64.bend as W 17 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 18 import ./aml_pkglength.bend as K 19 import ./aml_name.bend as N 20 21 type 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) 35 type 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 45 def tm.b(xs: List<&2, U32>) -> B.Octets: 46 B.Octets.of_list(xs) 47 48 def 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 75 def 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 80 def 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 85 def 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 102 def AmlT.encode1(t: AmlTerm) -> B.Octets: 103 AmlT.encode([t]) 104 105 def 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 118 def AmlT.int(v: W.W64) -> AmlTerm: 119 AmlTInt{v} 120 121 def AmlT.int32(v: U32) -> AmlTerm: 122 AmlTInt{W.W64.from_u32(v)} 123 124 def AmlT.zero() -> AmlTerm: 125 AmlTInt{W.W64.zero()} 126 127 def AmlT.one() -> AmlTerm: 128 AmlTInt{W.W64.one()} 129 130 def AmlT.ones() -> AmlTerm: 131 AmlTRaw{tm.b([255])} 132 133 def AmlT.str(s: String) -> AmlTerm: 134 AmlTStr{B.Octets.of_string(s)} 135 136 def AmlT.revision() -> AmlTerm: 137 AmlTRaw{tm.b([91, 48])} 138 139 # a Buffer of size bytes (a term), initialised from bytes 140 def 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 144 def AmlT.buf(+bytes: B.Octets) -> AmlTerm: 145 AmlT.buffer(AmlT.int(W.W64.from_nat(B.Octets.len(bytes))), bytes) 146 147 def AmlT.package(+elems: List<&2, AmlTerm>) -> AmlTerm: 148 AmlTPkg{tm.b([18]), tm.b([U32.from_nat(List.length(&2, AmlTerm, elems))]), elems} 149 150 def 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 155 def 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 166 def tm.hex(+c: U32) -> U32: 167 tm.hex.pick(U32.is_le(c, 57), U32.is_le(65, c), c) 168 169 def 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 178 def AmlT.eisaid_value(s: String) -> U32: 179 tm.eisa(B.of_string(s)) 180 181 def 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 186 def 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) 191 def AmlT.nm(s: String) -> AmlTerm: 192 AmlTRaw{tm.name(s)} 193 194 def AmlT.call(s: String, args: List<&2, AmlTerm>) -> AmlTerm: 195 AmlTOp{tm.name(s), args} 196 197 def AmlT.local(i: U32) -> AmlTerm: 198 AmlTRaw{tm.b([U32.add(96, U32.and(i, 7))])} 199 200 def AmlT.arg(i: U32) -> AmlTerm: 201 AmlTRaw{tm.b([U32.add(104, U32.min(i, 6))])} 202 203 def AmlT.debug() -> AmlTerm: 204 AmlTRaw{tm.b([91, 49])} 205 206 # NullName, the Target that discards a result 207 def AmlT.none() -> AmlTerm: 208 AmlTRaw{tm.b([0])} 209 210 # Named objects and scopes (20.2.5.1 to 20.2.5.2) 211 212 def AmlT.name(s: String, v: AmlTerm) -> AmlTerm: 213 AmlTOp{B.Octets.append(tm.b([8]), tm.name(s)), [v]} 214 215 def AmlT.scope(s: String, body: List<&2, AmlTerm>) -> AmlTerm: 216 AmlTPkg{tm.b([16]), tm.name(s), body} 217 218 def AmlT.device(s: String, body: List<&2, AmlTerm>) -> AmlTerm: 219 AmlTPkg{tm.b([91, 130]), tm.name(s), body} 220 221 def 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 229 def 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 232 def 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 235 def 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 238 def 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, ... 243 def 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 249 def 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 252 def 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 255 def 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 258 def AmlT.fnamed(s: String, bits: U32) -> AmlFieldElem: 259 AmlFNamed{N.AmlName.seg(s), bits} 260 261 def AmlT.mutex(s: String, sync: U32) -> AmlTerm: 262 AmlTRaw{B.Octets.concat([tm.b([91, 1]), tm.name(s), tm.b([sync])])} 263 264 def AmlT.event(s: String) -> AmlTerm: 265 AmlTRaw{B.Octets.append(tm.b([91, 2]), tm.name(s))} 266 267 def AmlT.alias(src: String, dst: String) -> AmlTerm: 268 AmlTRaw{B.Octets.concat([tm.b([6]), tm.name(src), tm.name(dst)])} 269 270 def 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 275 def AmlT.create_field(op: U32, src: AmlTerm, index: AmlTerm, s: String) -> AmlTerm: 276 AmlTOp{tm.b([op]), [src, index, AmlTRaw{tm.name(s)}]} 277 278 def 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 283 def AmlT.if_(pred: AmlTerm, body: List<&2, AmlTerm>) -> AmlTerm: 284 AmlTPkg{tm.b([160]), B.Octets.empty(), Con{pred, body}} 285 286 def 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 289 def AmlT.while_(pred: AmlTerm, body: List<&2, AmlTerm>) -> AmlTerm: 290 AmlTPkg{tm.b([162]), B.Octets.empty(), Con{pred, body}} 291 292 def AmlT.ret(v: AmlTerm) -> AmlTerm: 293 AmlTOp{tm.b([164]), [v]} 294 295 def AmlT.brk() -> AmlTerm: 296 AmlTRaw{tm.b([165])} 297 298 def AmlT.cont() -> AmlTerm: 299 AmlTRaw{tm.b([159])} 300 301 def AmlT.noop() -> AmlTerm: 302 AmlTRaw{tm.b([163])} 303 304 def AmlT.notify(obj: AmlTerm, v: AmlTerm) -> AmlTerm: 305 AmlTOp{tm.b([134]), [obj, v]} 306 307 def AmlT.sleep(ms: AmlTerm) -> AmlTerm: 308 AmlTOp{tm.b([91, 34]), [ms]} 309 310 def AmlT.stall(us: AmlTerm) -> AmlTerm: 311 AmlTOp{tm.b([91, 33]), [us]} 312 313 def AmlT.acquire(m: AmlTerm, timeout: U32) -> AmlTerm: 314 AmlTOp{tm.b([91, 35]), [m, AmlTRaw{B.Octets.le16(timeout)}]} 315 316 def 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 322 def AmlT.op(op: U32, args: List<&2, AmlTerm>) -> AmlTerm: 323 AmlTOp{tm.b([op]), args} 324 325 def AmlT.store(v: AmlTerm, target: AmlTerm) -> AmlTerm: 326 AmlT.op(112, [v, target]) 327 328 def AmlT.copy_object(v: AmlTerm, target: AmlTerm) -> AmlTerm: 329 AmlT.op(157, [v, target]) 330 331 def AmlT.add(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 332 AmlT.op(114, [a, b, t]) 333 334 def AmlT.subtract(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 335 AmlT.op(116, [a, b, t]) 336 337 def 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) 341 def AmlT.divide(a: AmlTerm, b: AmlTerm, rem: AmlTerm, quo: AmlTerm) -> AmlTerm: 342 AmlT.op(120, [a, b, rem, quo]) 343 344 def AmlT.mod(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 345 AmlT.op(133, [a, b, t]) 346 347 def AmlT.shift_left(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 348 AmlT.op(121, [a, b, t]) 349 350 def AmlT.shift_right(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 351 AmlT.op(122, [a, b, t]) 352 353 def AmlT.and(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 354 AmlT.op(123, [a, b, t]) 355 356 def AmlT.nand(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 357 AmlT.op(124, [a, b, t]) 358 359 def AmlT.or(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 360 AmlT.op(125, [a, b, t]) 361 362 def AmlT.nor(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 363 AmlT.op(126, [a, b, t]) 364 365 def AmlT.xor(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 366 AmlT.op(127, [a, b, t]) 367 368 def AmlT.not(a: AmlTerm, t: AmlTerm) -> AmlTerm: 369 AmlT.op(128, [a, t]) 370 371 def AmlT.find_set_left_bit(a: AmlTerm, t: AmlTerm) -> AmlTerm: 372 AmlT.op(129, [a, t]) 373 374 def AmlT.find_set_right_bit(a: AmlTerm, t: AmlTerm) -> AmlTerm: 375 AmlT.op(130, [a, t]) 376 377 def AmlT.increment(t: AmlTerm) -> AmlTerm: 378 AmlT.op(117, [t]) 379 380 def AmlT.decrement(t: AmlTerm) -> AmlTerm: 381 AmlT.op(118, [t]) 382 383 def AmlT.concat(a: AmlTerm, b: AmlTerm, t: AmlTerm) -> AmlTerm: 384 AmlT.op(115, [a, b, t]) 385 386 def AmlT.land(a: AmlTerm, b: AmlTerm) -> AmlTerm: 387 AmlT.op(144, [a, b]) 388 389 def AmlT.lor(a: AmlTerm, b: AmlTerm) -> AmlTerm: 390 AmlT.op(145, [a, b]) 391 392 def AmlT.lnot(a: AmlTerm) -> AmlTerm: 393 AmlT.op(146, [a]) 394 395 def AmlT.lequal(a: AmlTerm, b: AmlTerm) -> AmlTerm: 396 AmlT.op(147, [a, b]) 397 398 def AmlT.lgreater(a: AmlTerm, b: AmlTerm) -> AmlTerm: 399 AmlT.op(148, [a, b]) 400 401 def AmlT.lless(a: AmlTerm, b: AmlTerm) -> AmlTerm: 402 AmlT.op(149, [a, b]) 403 404 # LNotEqual, LLessEqual, LGreaterEqual: LNot of LEqual, LGreater, LLess 405 def AmlT.lnot_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm: 406 AmlT.lnot(AmlT.lequal(a, b)) 407 408 def AmlT.lless_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm: 409 AmlT.lnot(AmlT.lgreater(a, b)) 410 411 def AmlT.lgreater_equal(a: AmlTerm, b: AmlTerm) -> AmlTerm: 412 AmlT.lnot(AmlT.lless(a, b)) 413 414 # References 415 416 def AmlT.ref_of(a: AmlTerm) -> AmlTerm: 417 AmlT.op(113, [a]) 418 419 def AmlT.deref_of(a: AmlTerm) -> AmlTerm: 420 AmlT.op(131, [a]) 421 422 def AmlT.index(a: AmlTerm, i: AmlTerm, t: AmlTerm) -> AmlTerm: 423 AmlT.op(136, [a, i, t]) 424 425 def AmlT.cond_ref_of(a: AmlTerm, t: AmlTerm) -> AmlTerm: 426 AmlTOp{tm.b([91, 18]), [a, t]} 427 428 def AmlT.size_of(a: AmlTerm) -> AmlTerm: 429 AmlT.op(135, [a]) 430 431 def AmlT.object_type(a: AmlTerm) -> AmlTerm: 432 AmlT.op(142, [a]) 433 434 # Conversions 435 436 def AmlT.to_integer(a: AmlTerm, t: AmlTerm) -> AmlTerm: 437 AmlT.op(153, [a, t]) 438 439 def AmlT.to_buffer(a: AmlTerm, t: AmlTerm) -> AmlTerm: 440 AmlT.op(150, [a, t])