aml_ns.bend

bend-osdev-acpi@0.1.1.0 · 247 lines · 29 definitions

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.
9import Base
10import bend-osdev-word64@0.1.1.0/word64.bend as W
11import bend-osdev-bytes@0.1.1.0/bytes.bend as B
12import bend-osdev-acpi@0.1.1.0/error.bend as E
13import bend-osdev-acpi@0.1.1.0/aml_name.bend as N
14import bend-osdev-acpi@0.1.1.0/aml_value.bend as V
15
16type 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
43type AmlNs is Data:
44  AmlNs{objs: Map<&2, AmlObject>}
45
46def 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
75def AmlPath.root() -> String:
76  "\\"
77
78def AmlPath.is_root(+p: String) -> Bool:
79  String.eq(p, "\\")
80
81def 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
88def 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
100def AmlPath.child(+scope: String, seg: String) -> String:
101  ns.child.pick(AmlPath.is_root(scope), scope, seg)
102
103def AmlPath.parent(+p: String) -> String:
104  ns.parent.pick(Nat.is_le(String.length(p), 5n), p)
105
106def AmlPath.last(+p: String) -> String:
107  String.drop(p, Nat.sub(String.length(p), 4n))
108
109def 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
116def 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
123def 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
135def 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
140def AmlNs.empty() -> AmlNs:
141  AmlNs{Map.new(&2, AmlObject)}
142
143def ns.snd.bool(r: Map<&2, AmlObject> & Bool) -> Bool:
144  (m, b) = r
145  b
146
147
148def ns.snd.obj(r: Map<&2, AmlObject> & AmlObject) -> AmlObject:
149  (m, o) = r
150  o
151
152
153def 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
162def 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
168def 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
173def 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
178def 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
184def 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
191def 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
207def 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
215def 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
226def 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
238def 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
243def 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})