1 # bend-osdev-acpi, aml_ns.bend: the ACPI namespace (ACPI 6.5, section 5.3): 2 # named objects by absolute path, the predefined root scopes (5.3.1), and 3 # the search rules for names (5.3: a name of one NameSeg with no prefix is 4 # looked up in the current scope and then in each enclosing scope up to the 5 # root; any other name is taken as it stands). 6 # 7 # Paths are strings: "\" for the root, "\_SB_.PCI0" below it, every 8 # segment four characters. 9 import Base 10 import bend-osdev-word64@0.1.1.1/word64.bend as W 11 import bend-osdev-bytes@0.1.1.1/bytes.bend as B 12 import ./error.bend as E 13 import ./aml_name.bend as N 14 import ./aml_value.bend as V 15 16 type AmlObject is Data: 17 # Name(): a data object 18 AmlOData{v: V.AmlValue} 19 # Method(): its argument count, its flags byte and its body (AML bytes) 20 AmlOMethod{nargs: Nat, flags: U32, body: B.Octets} 21 # Scope, Device, Processor, PowerResource, ThermalZone: the ObjectType 22 # code (0 for a plain scope) 23 AmlOScope{kind: U32} 24 # OperationRegion(): address space, offset, length; parent: the scope 25 # that holds it (its device's _ADR gives a PCI region its function) 26 AmlORegion{space: U32, offset: W.W64, length: W.W64, parent: String} 27 # a field unit of a region: bit offset and width, the field's flags 28 # (access type, lock rule, update rule) and access attribute 29 AmlOField{region: String, bit_off: Nat, bits: Nat, flags: U32} 30 # a field unit reached through an index register and a data register 31 AmlOIndexField{index: String, data: String, bit_off: Nat, bits: Nat, flags: U32} 32 # a field of a buffer (CreateBitField and the others): the buffer's 33 # location, bit offset and width 34 AmlOBufField{buf: V.AmlLoc, bit_off: Nat, bits: Nat} 35 AmlOMutex{sync: U32} 36 AmlOEvent{} 37 AmlOAlias{target: String} 38 # an object the interpreter provides: 1 is \_OSI 39 AmlOBuiltin{id: U32} 40 # declared by External, not defined in the tables read 41 AmlOExternal{kind: U32} 42 43 type AmlNs is Data: 44 AmlNs{objs: Map<&2, AmlObject>} 45 46 def AmlObject.type(o: AmlObject) -> U32: 47 match o: 48 case AmlOData{v}: 49 V.AmlValue.type(v) 50 case AmlOMethod{n, f, b}: 51 8 52 case AmlOScope{k}: 53 k 54 case AmlORegion{s, off, l, p}: 55 10 56 case AmlOField{r, o2, n, f}: 57 5 58 case AmlOIndexField{i, d, o2, n, f}: 59 5 60 case AmlOBufField{b, o2, n}: 61 14 62 case AmlOMutex{s}: 63 9 64 case AmlOEvent{}: 65 7 66 case AmlOAlias{t}: 67 0 68 case AmlOBuiltin{i}: 69 8 70 case AmlOExternal{k}: 71 k 72 73 # Paths 74 75 def AmlPath.root() -> String: 76 "\\" 77 78 def AmlPath.is_root(+p: String) -> Bool: 79 String.eq(p, "\\") 80 81 def ns.child.pick(root: Bool, scope: String, seg: String) -> String: 82 match root: 83 case True{}: 84 "\\" ++ seg 85 case False{}: 86 scope ++ "." ++ seg 87 88 def ns.parent.pick(top: Bool, +p: String) -> String: 89 match top: 90 case True{}: 91 "\\" 92 case False{}: 93 String.take(p, Nat.sub(String.length(p), 5n)) 94 95 # the last segment of a path ("" for the root) 96 97 # the enclosing scope (the root's is the root) 98 99 # a segment (4 characters) below a scope 100 def AmlPath.child(+scope: String, seg: String) -> String: 101 ns.child.pick(AmlPath.is_root(scope), scope, seg) 102 103 def AmlPath.parent(+p: String) -> String: 104 ns.parent.pick(Nat.is_le(String.length(p), 5n), p) 105 106 def AmlPath.last(+p: String) -> String: 107 String.drop(p, Nat.sub(String.length(p), 4n)) 108 109 def ns.ups(n: Nat, +p: String) -> String: 110 match n: 111 case 0n: 112 p 113 case 1n+k: 114 ns.ups(k, AmlPath.parent(p)) 115 116 def ns.segs(ss: List<&2, B.Octets>, +p: String) -> String: 117 match ss: 118 case Nil{}: 119 p 120 case Con{s, t}: 121 ns.segs(t, AmlPath.child(p, B.Octets.to_string(s))) 122 123 def ns.of_name.pick(root: Bool, u: Nat, +scope: String, ss: List<&2, B.Octets>) -> String: 124 match root: 125 case True{}: 126 ns.segs(ss, "\\") 127 case False{}: 128 ns.segs(ss, ns.ups(u, scope)) 129 130 # Objects 131 132 133 # a name taken as it stands, from a scope (no search): where Name, Method 134 # and the other definitions create their object 135 def AmlPath.of_name(+scope: String, n: N.AmlName) -> String: 136 match n: 137 case N.AmlName{r, u, ss}: 138 ns.of_name.pick(r, u, scope, ss) 139 140 def AmlNs.empty() -> AmlNs: 141 AmlNs{Map.new(&2, AmlObject)} 142 143 def ns.snd.bool(r: Map<&2, AmlObject> & Bool) -> Bool: 144 (m, b) = r 145 b 146 147 148 def ns.snd.obj(r: Map<&2, AmlObject> & AmlObject) -> AmlObject: 149 (m, o) = r 150 o 151 152 153 def ns.got(has: Bool, +m: Map<&2, AmlObject>, +p: String) -> Maybe<&2, AmlObject>: 154 match has: 155 case True{}: 156 Some{ns.snd.obj(Map.get(AmlObject, AmlOEvent{}, m, p))} 157 case False{}: 158 None{} 159 160 # the object at a path 161 162 def AmlNs.has(ns: AmlNs, +p: String) -> Bool: 163 match ns: 164 case AmlNs{m}: 165 ns.snd.bool(Map.has(&2, AmlObject, m, p)) 166 167 # the object at a path 168 def AmlNs.get(ns: AmlNs, +p: String) -> Maybe<&2, AmlObject>: 169 match ns: 170 case AmlNs{+m}: 171 ns.got(ns.snd.bool(Map.has(&2, AmlObject, m, p)), m, p) 172 173 def AmlNs.set(ns: AmlNs, p: String, o: AmlObject) -> AmlNs: 174 match ns: 175 case AmlNs{m}: 176 AmlNs{Map.set(&2, AmlObject, m, p, o)} 177 178 def AmlNs.remove(ns: AmlNs, p: String) -> AmlNs: 179 match ns: 180 case AmlNs{m}: 181 AmlNs{Map.del(&2, AmlObject, m, p)} 182 183 # every path, sorted 184 def AmlNs.paths(ns: AmlNs) -> List<&2, String>: 185 match ns: 186 case AmlNs{m}: 187 List.sort(~String, ~String.is_le, Map.keys(&2, AmlObject, m)) 188 189 # the search for a NameSeg from a scope outward; hit: it is in this scope; 190 # top: this scope is the root 191 def ns.search.go(n: Nat, hit: Bool, top: Bool, +ns: AmlNs, +scope: String, +seg: String) -> Maybe<&2, String>: 192 match n: 193 case 0n: 194 None{} 195 case 1n+k: 196 match hit: 197 case True{}: 198 Some{AmlPath.child(scope, seg)} 199 case False{}: 200 match top: 201 case True{}: 202 None{} 203 case False{}: 204 +up = AmlPath.parent(scope) 205 ns.search.go(k, AmlNs.has(ns, AmlPath.child(up, seg)), AmlPath.is_root(up), ns, up, seg) 206 207 def ns.single(ss: List<&2, B.Octets>) -> String: 208 match ss: 209 case Con{s, t}: 210 B.Octets.to_string(s) 211 case Nil{}: 212 "" 213 214 215 def ns.exists(hit: Bool, p: String) -> Maybe<&2, String>: 216 match hit: 217 case True{}: 218 Some{p} 219 case False{}: 220 None{} 221 222 # The namespace OSPM starts with (5.3.1, 5.7): the root scopes _GPE, _PR_, 223 # _SB_, _SI_ and _TZ_, _OS_ (the operating system's name), _REV and the 224 # _OSI method 225 226 def ns.resolve.pick(single: Bool, +ns: AmlNs, +scope: String, +n: N.AmlName) -> Maybe<&2, String>: 227 match single: 228 case True{}: 229 +seg = ns.single(N.AmlName.segs(n)) 230 ns.search.go(String.length(scope), AmlNs.has(ns, AmlPath.child(scope, seg)), AmlPath.is_root(scope), ns, scope, seg) 231 case False{}: 232 +p = AmlPath.of_name(scope, n) 233 ns.exists(AmlNs.has(ns, p), p) 234 235 236 # the object a name refers to, from a scope: a single NameSeg is searched 237 # for outward (5.3); None if it is not defined 238 def AmlNs.resolve(+ns: AmlNs, +scope: String, +n: N.AmlName) -> Maybe<&2, String>: 239 match n: 240 case N.AmlName{r, u, +ss}: 241 ns.resolve.pick(Bool.and(Bool.not(r), Bool.and(Nat.is_eq(u, 0n), Nat.is_eq(List.length(&2, B.Octets, ss), 1n))), ns, scope, N.AmlName{r, u, ss}) 242 243 def AmlNs.initial(os: String, rev: U32) -> AmlNs: 244 +a = AmlNs.set(AmlNs.empty(), "\\", AmlOScope{0}) 245 +b = AmlNs.set(AmlNs.set(AmlNs.set(a, "\\_GPE", AmlOScope{0}), "\\_PR_", AmlOScope{0}), "\\_SB_", AmlOScope{6}) 246 +c = AmlNs.set(AmlNs.set(b, "\\_SI_", AmlOScope{0}), "\\_TZ_", AmlOScope{0}) 247 AmlNs.set(AmlNs.set(AmlNs.set(c, "\\_OS_", AmlOData{V.AmlStr{B.Octets.of_string(os)}}), "\\_REV", AmlOData{V.AmlInt{W.W64.from_u32(rev)}}), "\\_OSI", AmlOBuiltin{1})