PatchworkOS  2ca1c69
A non-POSIX operating system.
Loading...
Searching...
No Matches
namespace.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/utils/map.h>
5
6#include <kernel/defs.h>
7#include <stdint.h>
8#include <sys/list.h>
9
10/**
11 * @brief Namespace and Namespace Overlays
12 * @defgroup modules_acpi_aml_namespace Namespace
13 * @ingroup modules_acpi_aml
14 *
15 * We need this slightly complex system as when a method runs it can create named objects that should not be visible
16 * outside of the method, and when the method finishes these objects need to be removed. Additionally, if the method
17 * calls itself, the new invocation should not see the objects created by the previous invocation. Note that "outside of
18 * the method" means that if a inner method is defined inside another method the inner method will see the objects
19 * created by the outer method.
20 *
21 * This is complex enough to need a example, good luck.
22 * ```
23 * Name (GLOB, 0) // Creates global GLOB with value 0
24 *
25 * Method (FUNA, 0, NotSerialized)
26 * {
27 * Store(30, GLOB) // Updates global GLOB to 10
28 * // Store(0, _VAR) // Error, _VAR does not exist
29 * }
30 *
31 * Method (FUNB, 0, NotSerialized)
32 * {
33 * Name (_VAR, GLOB) // Creates _VAR and stores GLOB's value in it
34 * If (IsEqual(_VAR, 20)) // On the second call this will be true as GLOB was updated to 20 by FUNB
35 * {
36 * Return
37 * }
38 * Method (FUNC, 0, NotSerialized)
39 * {
40 * Store(0, _VAR) // Updates _VAR to 0
41 * Store(10, GLOB) // Updates global GLOB to 10
42 * }
43 * FUNC() // Calls inner FUNC
44 * Store(20, GLOB) // Updates global GLOB to 20
45 * FUNB() // Calls itself, will se its own _VAR which will contain the value in GLOB which is now 20
46 * FUNA() // Calls a outer method, cannot see _VAR and would error if it tried to access it
47 * // Method exists here, _VAR is removed
48 * }
49 * ```
50 *
51 * This example does not include the edge case where a inner function calls the functions its defined inside of, but
52 * it works the same way as calling a outer function.
53 *
54 * As far as i can tell, this does NOT apply to If, While, or other statements, only methods. So if you
55 * create a named object inside an If statement it will be visible outside of the If statement.
56 *
57 * To solve this we give the `aml_state_t` a `aml_overlay_t` where it can create its named objects. When
58 * looking up names we first look in the overlay of the current state and then in the parent overlay and so on until we
59 * reach a `NULL` overlay. The last overlay will always be the "global" overlay. When invoking a method it will be given
60 * its own `aml_state_t` and its own overlay, the parent of this overlay will be the "highest" overlay that contains the
61 * invoked method, so if a inner method is invoked its parent overlay will be the overlay of the outer method. If a
62 * outer method is invoked we move up the overlay chain until we find the overlay that contains the method and use that
63 * as the parent overlay.
64 *
65 * Its important to note that overlays are *not* directories they are maps that map a parents id and a childs name to
66 * the child object and that when combined form the complete heirarchy. Think of it like this, each overlay defines a
67 * incomplete heirarchy of named objects, for example one overlay might define an object `\_FOO._BAR` but the parent
68 * object `_FOO` is actually defined in the parent overlay.
69 *
70 * We also need the ability to commit any names created in a overlay to be globally visible if we are not
71 * executing a method but instead parsing a DSDT or SSDT table. This is done using `aml_overlay_commit()`
72 * which moves all the overlays objects to its parent overlay, which is usually the global overlay.
73 *
74 * Note that the term "namespace" in the ACPI specification does not refer to the entire "hierarchy" of named objects
75 * but instead to an object that contains named objects, for example a Device object. Yes this is confusing.
76 *
77 * @see Section 5.3 of the ACPI specification for more details.
78 *
79 * @{
80 */
81
82/**
83 * @brief Namespace overlay.
84 * @struct aml_overlay_t
85 */
86typedef struct aml_overlay
87{
88 map_t map; ///< Used to find the children of namespaces using their id and the name of the child.
89 list_t objects; ///< List of all objects in this namespace. Used for fast iteration.
90 struct aml_overlay* parent; ///< The parent overlay, or `NULL` if none.
92
93/**
94 * @brief Name type.
95 * @typedef aml_name_t
96 *
97 * In AML names are just 32-bit values, it just happens that each byte in this value is an ASCII character. So we can
98 * optimize things a bit by just treating this as a integer instead of pretending its a string, unless you want to
99 * print it for debugging purposes.
100 */
102
103/**
104 * @brief Macro to create an `aml_name_t` from 4 characters.
105 *
106 * @param a First character.
107 * @param b Second character.
108 * @param c Third character.
109 * @param d Fourth character.
110 * @return The aml_name_t value.
111 */
112#define AML_NAME(a, b, c, d) \
113 ((aml_name_t)((((aml_name_t)(a) & 0xFF)) | (((aml_name_t)(b) & 0xFF) << 8) | (((aml_name_t)(c) & 0xFF) << 16) | \
114 (((aml_name_t)(d) & 0xFF) << 24)))
115
116/**
117 * @brief Macro for an undefined name.
118 *
119 * Real AML never uses lower case letters in names, so we can use 'x' to represent an undefined name.
120 */
121#define AML_NAME_UNDEFINED AML_NAME('x', 'x', 'x', 'x')
122
123/**
124 * @brief Macro to convert an `aml_name_t` to a stack allocated string.
125 *
126 * @param name The aml_name_t value.
127 * @return A stack allocated string representation of the name.
128 */
129#define AML_NAME_TO_STRING(name) \
130 (char[]){((name)) & 0xFF, ((name) >> 8) & 0xFF, ((name) >> 16) & 0xFF, ((name) >> 24) & 0xFF, '\0'}
131
132/**
133 * @brief Initialize the namespace heirarchy.
134 *
135 * @param root The object to use as the root of the namespace heirarchy.
136 */
138
139/**
140 * @brief Expose the entire namespace heirarchy to sysfs.
141 *
142 * @return On success, `0`. On failure, `ERR`.
143 */
145
146/**
147 * @brief Get the root object of the namespace heirarchy.
148 *
149 * @return The root object.
150 */
152
153/**
154 * @brief Find a child object directly under a parent object in the namespace heirarchy.
155 *
156 * Will always traverse aliases.
157 *
158 * @param overlay The overlay to search in, if `NULL` only the global overlay is searched.
159 * @param parent The parent scope to search in.
160 * @param name The name of the child object to find.
161 * @return The object reference or `NULL` if it could not be found.
162 */
164
165/**
166 * @brief Find an object in the namespace heirarchy by name segments.
167 *
168 * Will always traverse aliases.
169 *
170 * If there is exactly one name segment, then additional search rules apply meaning that if the object is not found
171 * is the parent scope, then we recursively search the parent scope's parent, and so on until we reach the root or
172 * find the object.
173 *
174 * Example:
175 * ```c
176 * aml_namespace_find(NULL, parent, 2, AML_NAME('A', 'B', 'C', 'D'), AML_NAME('E', 'F', 'G', 'H'));
177 * ```
178 *
179 * @param overlay The overlay to search in, if `NULL` only the global overlay is searched.
180 * @param start The scope to start searching from, if `NULL` the search starts from the root object.
181 * @param nameCount The number of name segments following.
182 * @param ... The name segments of the object to find.
183 * @return The object reference or `NULL` if it could not be found.
184 */
186
187/**
188 * @brief Find an object in the namespace heirarchy by a name string.
189 *
190 * Will always traverse aliases.
191 *
192 * A search through the ACPI namespace follows these rules:
193 * - If the NameString starts with a root character (`\`), the search starts from the root object.
194 * - If the NameString starts with one or more parent prefix characters (`^`), the search starts from the parent of the
195 * `start` object, moving up one level for each `^`.
196 * - If the NameString does not start with a root or parent prefix character, the search starts from the `start` object.
197 * If `start` is `NULL`, the search starts from the root object.
198 * - Attempt to find a matching name in the current namespace scope (the `start` object and its children).
199 * - If there are no prefixes, only one name segment in the NameString and no match is found in the current scope,
200 * recursively search the parent scope, and so on.
201 * - If there are multiple name segments, then recursively searching parent scopes is not allowed. And we just continue
202 * searching the next segment in the current scope.
203 *
204 * @param overlay The overlay to search in, if `NULL` only the global overlay is searched.
205 * @param start The scope to start searching from, if `NULL` the search starts from the root object.
206 * @param nameString The name string of the object to find.
207 * @return The object reference or `NULL` if it could not be found.
208 */
210 const aml_name_string_t* nameString);
211
212/**
213 * @brief Find an object in the namespace heirarchy by a path string.
214 *
215 * Will always traverse aliases.
216 *
217 * The path string is a dot separated list of names, for example "ABCD.EFGH.IJKL". Additionally the path can start with
218 * a
219 * "\" to indicate that the search should start from the root object, or one or more "^" characters to indicate that the
220 * search should start from the parent of the `start` object, moving up one level for each "^".
221 *
222 * If the path does not start with a "\" or "^", the search starts from the `start` object. If `start` is `NULL`, the
223 * search starts from the root object.
224 *
225 * If there is exactly one name segment, then additional search rules apply meaning that if the object is not found
226 * is the parent scope, then we recursively search the parent scope's parent, and so on until we reach the root or
227 * find the object.
228 *
229 * @param overlay The overlay to search in, if `NULL` only the global overlay is searched.
230 * @param start The scope to start searching from, if `NULL` the search starts from the root object.
231 * @param path The path string of the object to find.
232 * @return The object reference or `NULL` if it could not be found.
233 */
235
236/**
237 * @brief Add an child to a parent in the namespace heirarchy.
238 *
239 * @param overlay The overlay to add the object to, if `NULL` the object is added to the global overlay.
240 * @param parent The parent scope to add the object to, if `NULL` the object is added to the root object.
241 * @param name The name to give the object.
242 * @param object The object to add to the namespace.
243 * @return On success, `0`. On failure, `ERR` and `errno` is set.
244 */
246
247/**
248 * @brief Add an object to the namespace heirarchy using a name string.
249 *
250 * @param overlay The overlay to add the object to, if `NULL` the object is added to the global overlay.
251 * @param start The scope to start searching from to resolve the name string, if `NULL` the search starts from the root
252 * object.
253 * @param nameString The name string to use to find the parent scope and name of the object.
254 * @param object The object to add to the namespace.
255 * @return On success, `0`. On failure, `ERR` and `errno` is set.
256 */
258 const aml_name_string_t* nameString, aml_object_t* object);
259
260/**
261 * @brief Remove an object from the namespace heirarchy it was added to.
262 *
263 * If the object is not found in the specified overlay or the global namespace heirarchy, nothing happens.
264 *
265 * The object is dereferenced, so if there are no other references to it, it will be freed.
266 *
267 * @param object The object to remove from the namespace.
268 */
270
271/**
272 * @brief Commit all names in a namespace overlay to the global namespace heirarchy.
273 *
274 * After this call the overlay will be empty.
275 *
276 * @param overlay The overlay to commit.
277 * @return On success, `0`. On failure, `ERR` and `errno` is set.
278 */
280
281/**
282 * @brief Initialize a namespace overlay.
283 *
284 * Its parent is set to the global overlay.
285 *
286 * @param overlay The overlay to initialize.
287 */
288void aml_overlay_init(aml_overlay_t* overlay);
289
290/**
291 * @brief Deinitialize a namespace overlay.
292 *
293 * @param overlay The overlay to deinitialize.
294 */
295void aml_overlay_deinit(aml_overlay_t* overlay);
296
297/**
298 * @brief Set the parent of a namespace overlay.
299 *
300 * @param overlay The overlay to set the parent of.
301 * @param parent The new parent overlay, or `NULL` to set no parent.
302 */
304
305/**
306 * @brief Search a overlay and its parents for the first overlay that contains the given object.
307 *
308 * @param overlay The overlay to check.
309 * @param object The object to check for.
310 * @return On success, the highest overlay that contains the object. On failure, `NULL`.
311 */
313
314/** @} */
uint64_t aml_namespace_add_child(aml_overlay_t *overlay, aml_object_t *parent, aml_name_t name, aml_object_t *object)
Add an child to a parent in the namespace heirarchy.
Definition namespace.c:395
aml_object_t * aml_namespace_find_by_path(aml_overlay_t *overlay, aml_object_t *start, const char *path)
Find an object in the namespace heirarchy by a path string.
Definition namespace.c:288
uint64_t aml_namespace_commit(aml_overlay_t *overlay)
Commit all names in a namespace overlay to the global namespace heirarchy.
Definition namespace.c:506
uint64_t aml_namespace_expose(void)
Expose the entire namespace heirarchy to sysfs.
Definition namespace.c:121
aml_overlay_t * aml_overlay_find_containing(aml_overlay_t *overlay, aml_object_t *object)
Search a overlay and its parents for the first overlay that contains the given object.
Definition namespace.c:577
void aml_namespace_init(aml_object_t *root)
Initialize the namespace heirarchy.
Definition namespace.c:74
aml_object_t * aml_namespace_find_by_name_string(aml_overlay_t *overlay, aml_object_t *start, const aml_name_string_t *nameString)
Find an object in the namespace heirarchy by a name string.
Definition namespace.c:237
void aml_namespace_remove(aml_object_t *object)
Remove an object from the namespace heirarchy it was added to.
Definition namespace.c:487
void aml_overlay_deinit(aml_overlay_t *overlay)
Deinitialize a namespace overlay.
Definition namespace.c:551
aml_object_t * aml_namespace_find_child(aml_overlay_t *overlay, aml_object_t *parent, aml_name_t name)
Find a child object directly under a parent object in the namespace heirarchy.
Definition namespace.c:154
void aml_overlay_init(aml_overlay_t *overlay)
Initialize a namespace overlay.
Definition namespace.c:539
uint32_t aml_name_t
Name type.
Definition namespace.h:101
aml_object_t * aml_namespace_get_root(void)
Get the root object of the namespace heirarchy.
Definition namespace.c:149
void aml_overlay_set_parent(aml_overlay_t *overlay, aml_overlay_t *parent)
Set the parent of a namespace overlay.
Definition namespace.c:567
aml_object_t * aml_namespace_find(aml_overlay_t *overlay, aml_object_t *start, uint64_t nameCount,...)
Find an object in the namespace heirarchy by name segments.
Definition namespace.c:192
uint64_t aml_namespace_add_by_name_string(aml_overlay_t *overlay, aml_object_t *start, const aml_name_string_t *nameString, aml_object_t *object)
Add an object to the namespace heirarchy using a name string.
Definition namespace.c:449
static void start()
Definition main.c:542
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
A NameString structure.
Definition name.h:87
ACPI object.
Definition object.h:447
Namespace overlay.
Definition namespace.h:87
list_t objects
List of all objects in this namespace. Used for fast iteration.
Definition namespace.h:89
struct aml_overlay * parent
The parent overlay, or NULL if none.
Definition namespace.h:90
map_t map
Used to find the children of namespaces using their id and the name of the child.
Definition namespace.h:88
A doubly linked list.
Definition list.h:47
Hash map structure.
Definition map.h:89