1 # bend-osdev-acpi, aml_device.bend: the device objects OSPM reads most 2 # (ACPI 6.5, chapter 6, Device Configuration): _HID (6.1.5) and its EISA ID 3 # form (EISAID, chapter 19), _STA (6.3.7), _CRS (6.2.2, resource templates: 4 # aml_resource.bend) and _PRT (6.2.13, PCI interrupt routing), and the 5 # devices of a namespace. 6 import Base 7 import bend-osdev-word64@0.1.1.1/word64.bend as W 8 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 9 import ./error.bend as E 10 import ./aml_value.bend as V 11 import ./aml_ns.bend as S 12 import ./aml_host.bend as Hs 13 import ./aml_interp.bend as I 14 import ./aml.bend as A 15 import ./aml_resource.bend as R 16 17 # EISA IDs: a DWord holding three letters of five bits and four hex digits, 18 # most significant byte first in memory ("PNP0A03" is 0x030AD041) 19 20 def dv.hex.pick(lt: Bool, +d: U32) -> U32: 21 match lt: 22 case True{}: 23 U32.add(48, d) 24 case False{}: 25 U32.add(55, d) 26 27 def dv.hex(+d: U32) -> U32: 28 dv.hex.pick(U32.is_lt(d, 10), d) 29 30 def AmlEisaId.text(+v: U32) -> String: 31 +id = U32.or(U32.or(U32.shln(U32.and(v, 255), 24n), U32.shln(U32.and(U32.shrn(v, 8n), 255), 16n)), U32.or(U32.shln(U32.and(U32.shrn(v, 16n), 255), 8n), U32.and(U32.shrn(v, 24n), 255))) 32 B.to_string([U32.add(64, U32.and(U32.shrn(id, 26n), 31)), U32.add(64, U32.and(U32.shrn(id, 21n), 31)), U32.add(64, U32.and(U32.shrn(id, 16n), 31)), dv.hex(U32.and(U32.shrn(id, 12n), 15)), dv.hex(U32.and(U32.shrn(id, 8n), 15)), dv.hex(U32.and(U32.shrn(id, 4n), 15)), dv.hex(U32.and(id, 15))]) 33 34 # The objects of a device 35 36 def dv.get.pick(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, has: Bool, +s: A.AmlSystem, +p: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>: 37 match has: 38 case True{}: 39 Some{A.AmlOutcome.result(H, A.Aml.eval(~H, ~io, s, p, Nil{}, n))} 40 case False{}: 41 None{} 42 43 # an object of a device evaluated (a method run with no arguments), in at 44 # most n steps; None if the device has no such object 45 def AmlDevice.get(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, +s: A.AmlSystem, +dev: String, +seg: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>: 46 +p = S.AmlPath.child(dev, seg) 47 dv.get.pick(~H, ~io, S.AmlNs.has(A.AmlSystem.ns(H, s), p), s, p, n) 48 49 def dv.sta(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, W.W64>: 50 match m: 51 case None{}: 52 Done{W.W64.from_u32(15)} 53 case Some{Fail{e}}: 54 Fail{e} 55 case Some{Done{v}}: 56 V.AmlValue.to_int(True{}, v) 57 58 # _STA: bit 0 present, 1 enabled, 2 shown in the UI, 3 functioning, 59 # 4 battery present; a device without _STA is 0x0F (6.3.7) 60 def AmlDevice.status(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, +s: A.AmlSystem, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, W.W64>: 61 dv.sta(AmlDevice.get(~H, ~io, s, dev, "_STA", n)) 62 63 def dv.id(v: V.AmlValue) -> Result<&2, &2, E.AcpiError, String>: 64 match v: 65 case V.AmlInt{x}: 66 Done{AmlEisaId.text(W.W64.lo(x))} 67 case V.AmlStr{t}: 68 Done{B.Octets.to_string(t)} 69 case _: 70 Fail{E.AcpiAmlBadType{"_HID is not an integer or a string"}} 71 72 def dv.hid(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Maybe<&2, Result<&2, &2, E.AcpiError, String>>: 73 match m: 74 case None{}: 75 None{} 76 case Some{Fail{e}}: 77 Some{Fail{e}} 78 case Some{Done{v}}: 79 Some{dv.id(v)} 80 81 # _HID as text: an EISA ID ("PNP0A03") or the string itself ("ACPI0003") 82 def AmlDevice.hid(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, +s: A.AmlSystem, +dev: String, +n: Nat) -> Maybe<&2, Result<&2, &2, E.AcpiError, String>>: 83 dv.hid(AmlDevice.get(~H, ~io, s, dev, "_HID", n)) 84 85 def dv.crs(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, List<&2, R.AmlResource>>: 86 match m: 87 case None{}: 88 Done{Nil{}} 89 case Some{Fail{e}}: 90 Fail{e} 91 case Some{Done{V.AmlBuf{b}}}: 92 R.AmlResource.parse(b) 93 case Some{Done{v}}: 94 Fail{E.AcpiAmlBadType{"_CRS is not a buffer"}} 95 96 # _CRS: the resources the device uses (none if it has no _CRS) 97 def AmlDevice.crs(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, +s: A.AmlSystem, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, List<&2, R.AmlResource>>: 98 dv.crs(AmlDevice.get(~H, ~io, s, dev, "_CRS", n)) 99 100 # _PRT entries (6.2.13): the device's address (high word: device, low word: 101 # 0xFFFF for any function), the PCI pin (0 INTA to 3 INTD), and the source: 102 # the path of a link device and its index, or an empty path and the global 103 # system interrupt in index 104 type AmlPrtEntry is Data: 105 AmlPrtEntry{address: W.W64, pin: U32, source: String, index: U32} 106 107 def dv.prt.src(v: V.AmlValue) -> String: 108 match v: 109 case V.AmlRef{V.AmlLName{p}}: 110 p 111 case V.AmlStr{t}: 112 B.Octets.to_string(t) 113 case _: 114 "" 115 116 def dv.prt.one(v: V.AmlValue) -> Result<&2, &2, E.AcpiError, AmlPrtEntry>: 117 match v: 118 case V.AmlPkg{[V.AmlInt{a}, V.AmlInt{p}, src, V.AmlInt{i}]}: 119 Done{AmlPrtEntry{a, W.W64.lo(p), dv.prt.src(src), W.W64.lo(i)}} 120 case _: 121 Fail{E.AcpiAmlBadType{"a _PRT entry is not a package of four"}} 122 123 def dv.prt.cons(r: Result<&2, &2, E.AcpiError, AmlPrtEntry>, rs: Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>: 124 match r rs: 125 case Done{e} Done{es}: 126 Done{Con{e, es}} 127 case Fail{e} _: 128 Fail{e} 129 case Done{e} Fail{x}: 130 Fail{x} 131 132 def dv.prt.all(xs: List<&2, V.AmlValue>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>: 133 match xs: 134 case Nil{}: 135 Done{Nil{}} 136 case Con{x, t}: 137 dv.prt.cons(dv.prt.one(x), dv.prt.all(t)) 138 139 def dv.prt(m: Maybe<&2, Result<&2, &2, E.AcpiError, V.AmlValue>>) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>: 140 match m: 141 case None{}: 142 Done{Nil{}} 143 case Some{Fail{e}}: 144 Fail{e} 145 case Some{Done{V.AmlPkg{xs}}}: 146 dv.prt.all(xs) 147 case Some{Done{v}}: 148 Fail{E.AcpiAmlBadType{"_PRT is not a package"}} 149 150 # _PRT of a PCI bridge (none if it has no _PRT) 151 def AmlDevice.prt(~H: Data, ~io: H -> Hs.AmlHostOp -> Result<&2, &2, E.AcpiError, Hs.AmlHostAns>, +s: A.AmlSystem, +dev: String, +n: Nat) -> Result<&2, &2, E.AcpiError, List<&2, AmlPrtEntry>>: 152 dv.prt(AmlDevice.get(~H, ~io, s, dev, "_PRT", n)) 153 154 def dv.kind(o: Maybe<&2, S.AmlObject>) -> U32: 155 match o: 156 case Some{x}: 157 S.AmlObject.type(x) 158 case None{}: 159 0 160 161 def dv.devs.pick(dev: Bool, p: String, rest: List<&2, String>) -> List<&2, String>: 162 match dev: 163 case True{}: 164 Con{p, rest} 165 case False{}: 166 rest 167 168 def dv.devs(ps: List<&2, String>, +ns: S.AmlNs) -> List<&2, String>: 169 match ps: 170 case Nil{}: 171 Nil{} 172 case Con{+p, t}: 173 dv.devs.pick(U32.is_eq(dv.kind(S.AmlNs.get(ns, p)), 6), p, dv.devs(t, ns)) 174 175 # every Device (and \_SB_) of a namespace, in path order 176 def AmlDevice.list(+ns: S.AmlNs) -> List<&2, String>: 177 dv.devs(S.AmlNs.paths(ns), ns)