PatchworkOS
Loading...
Searching...
No Matches
namespace.c
Go to the documentation of this file.
2
6#include <kernel/log/log.h>
7
8#include <errno.h>
9
11
13
15{
16 // Pack the parentId and name into a single buffer for the map key
17 struct PACKED
18 {
19 aml_object_id_t parentId;
20 aml_name_t name;
21 } buffer;
22 buffer.parentId = parentId;
23 buffer.name = name;
24 return map_key_buffer(&buffer, sizeof(buffer));
25}
26
28{
29 for (uint64_t i = 0; i < depth; i++)
30 {
31 if (current == NULL || current->parent == NULL)
32 {
33 DEREF(current);
34 return NULL;
35 }
36 aml_object_t* parent = REF(current->parent);
37 DEREF(current);
38 current = parent;
39 }
40 return current;
41}
42
44 aml_name_t name)
45{
46 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
47
48 if (next == NULL)
49 {
50 while (current->parent != NULL)
51 {
52 aml_object_t* parent = REF(current->parent);
53 DEREF(current);
54 current = parent;
55
56 next = aml_namespace_find_child(overlay, current, name);
57 if (next != NULL)
58 {
59 break;
60 }
61 }
62 }
63
64 DEREF(current);
65 return next;
66}
67
69{
71 {
72 return ERR;
73 }
74 root->flags |= AML_OBJECT_NAMED | AML_OBJECT_ROOT;
75 root->name = AML_NAME('\\', '_', '_', '_');
76 namespaceRoot = REF(root);
77 return 0;
78}
79
81{
82 // TODO: Expose ACPI namespace via sysfs
83 return 0;
84}
85
90
92{
93 if (parent == NULL || !(parent->flags & AML_OBJECT_NAMED))
94 {
95 return NULL;
96 }
97
98 if (overlay == NULL)
99 {
100 overlay = &globalOverlay;
101 }
102
103 map_key_t key = aml_object_map_key(parent->id, name);
104 aml_object_t* child = NULL;
105 while (overlay != NULL)
106 {
107 child = CONTAINER_OF_SAFE(map_get(&overlay->map, &key), aml_object_t, mapEntry);
108 if (child != NULL)
109 {
110 break;
111 }
112
113 overlay = overlay->parent;
114 }
115
116 if (child == NULL)
117 {
118 return NULL;
119 }
120
121 if (child->type == AML_ALIAS)
122 {
123 return aml_alias_obj_traverse(&child->alias);
124 }
125
126 return REF(child);
127}
128
130{
131 if (nameCount == 0)
132 {
133 return NULL;
134 }
135
136 aml_object_t* current = start != NULL ? REF(start) : REF(namespaceRoot);
137 if (current == NULL || !(current->flags & AML_OBJECT_NAMED))
138 {
139 DEREF(current);
140 return NULL;
141 }
142
143 if (nameCount == 1)
144 {
145 va_list args;
146 va_start(args, nameCount);
147 aml_name_t name = va_arg(args, aml_name_t);
148 va_end(args);
149
150 return aml_namespace_search_single_name(overlay, current, name);
151 }
152
153 va_list args;
154 va_start(args, nameCount);
155 for (uint64_t i = 0; i < nameCount; i++)
156 {
157 aml_name_t name = va_arg(args, aml_name_t);
158 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
159
160 if (next == NULL)
161 {
162 DEREF(current);
163 va_end(args);
164 return NULL;
165 }
166
167 DEREF(current);
168 current = next;
169 }
170 va_end(args);
171 return current; // Transfer ownership
172}
173
175 const aml_name_string_t* nameString)
176{
177 if (nameString == NULL)
178 {
179 return NULL;
180 }
181
182 aml_object_t* current = (start == NULL || nameString->rootChar.present) ? REF(namespaceRoot) : REF(start);
183 if (!(current->flags & AML_OBJECT_NAMED))
184 {
185 DEREF(current);
186 return NULL;
187 }
188
189 current = aml_namespace_traverse_parents(current, nameString->prefixPath.depth);
190 if (current == NULL)
191 {
192 return NULL;
193 }
194
195 if (!nameString->rootChar.present && nameString->prefixPath.depth == 0 && nameString->namePath.segmentCount == 1)
196 {
197 aml_name_t name = nameString->namePath.segments[0];
198 return aml_namespace_search_single_name(overlay, current, name);
199 }
200
201 for (uint64_t i = 0; i < nameString->namePath.segmentCount; i++)
202 {
203 if (!(current->flags & AML_OBJECT_NAMED))
204 {
205 DEREF(current);
206 return NULL;
207 }
208
209 aml_name_t name = nameString->namePath.segments[i];
210 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
211
212 if (next == NULL)
213 {
214 DEREF(current);
215 return NULL;
216 }
217
218 DEREF(current);
219 current = next;
220 }
221
222 return current; // Transfer ownership
223}
224
226{
227 if (path == NULL || path[0] == '\0')
228 {
229 errno = EINVAL;
230 return NULL;
231 }
232
233 aml_object_t* current = NULL;
234 const char* p = path;
235 if (p[0] == '\\')
236 {
237 current = REF(namespaceRoot);
238 p++;
239 }
240 else if (p[0] == '^')
241 {
242 if (start == NULL)
243 {
244 errno = EINVAL;
245 return NULL;
246 }
247
248 uint64_t depth = 0;
249 while (p[0] == '^')
250 {
251 depth++;
252 p++;
253 }
254
255 current = aml_namespace_traverse_parents(REF(start), depth);
256 }
257 else
258 {
259 current = start != NULL ? REF(start) : REF(namespaceRoot);
260 }
261
262 if (current == NULL || !(current->flags & AML_OBJECT_NAMED))
263 {
264 DEREF(current);
265 return NULL;
266 }
267
268 if (*p == '\0')
269 {
270 return current; // Transfer ownership
271 }
272
273 uint64_t segmentCount = 0;
274 while (*p != '\0')
275 {
276 const char* segmentStart = p;
277 while (*p != '.' && *p != '\0')
278 {
279 p++;
280 }
281
282 uint64_t segmentLength = p - segmentStart;
283 if (segmentLength > sizeof(aml_name_t))
284 {
285 DEREF(current);
286 return NULL;
287 }
288
289 aml_name_t segment = 0;
290 for (uint64_t i = 0; i < segmentLength; i++)
291 {
292 segment |= ((aml_name_t)(uint8_t)segmentStart[i]) << (i * 8);
293 }
294
295 segmentCount++;
296
297 if (*p == '.')
298 {
299 p++;
300 }
301
302 aml_object_t* next = aml_namespace_find_child(overlay, current, segment);
303 if (next == NULL && segmentCount == 1 && *p == '\0')
304 {
305 while (current->parent != NULL)
306 {
307 aml_object_t* parent = REF(current->parent);
308 DEREF(current);
309 current = parent;
310
311 next = aml_namespace_find_child(overlay, current, segment);
312 if (next != NULL)
313 {
314 break;
315 }
316 }
317 }
318
319 if (next == NULL)
320 {
321 DEREF(current);
322 return NULL;
323 }
324
325 DEREF(current);
326 current = next;
327 }
328
329 return current; // Transfer ownership
330}
331
333 aml_object_t* object)
334{
335 if (object == NULL)
336 {
337 errno = EINVAL;
338 return ERR;
339 }
340
341 parent = parent != NULL ? parent : namespaceRoot;
342 if (!(parent->flags & AML_OBJECT_NAMED) || (object->flags & AML_OBJECT_NAMED))
343 {
344 errno = EINVAL;
345 return ERR;
346 }
347
348 if (overlay == NULL)
349 {
350 overlay = &globalOverlay;
351 }
352
353 map_key_t key = aml_object_map_key(parent->id, name);
354 aml_namespace_overlay_t* currentOverlay = overlay;
355 while (currentOverlay != NULL)
356 {
357 if (map_get(&currentOverlay->map, &key) != NULL)
358 {
359 errno = EEXIST;
360 return ERR;
361 }
362 currentOverlay = currentOverlay->parent;
363 }
364
365 if (map_insert(&overlay->map, &key, &object->mapEntry) == ERR)
366 {
367 return ERR;
368 }
369 list_push(&overlay->objects, &object->listEntry);
370 list_push(&parent->children, &object->siblingsEntry);
371
372 object->flags |= AML_OBJECT_NAMED;
373 object->overlay = overlay;
374 object->parent = parent;
375 object->name = name;
376
377 REF(object);
378 return 0;
379}
380
382 const aml_name_string_t* nameString, aml_object_t* object)
383{
384 if (nameString == NULL || nameString->namePath.segmentCount == 0)
385 {
386 errno = EINVAL;
387 return ERR;
388 }
389
390 aml_name_t targetName = nameString->namePath.segments[nameString->namePath.segmentCount - 1];
391
392 if (nameString->namePath.segmentCount == 1)
393 {
394 aml_object_t* parent = (start == NULL || nameString->rootChar.present) ? REF(namespaceRoot) : REF(start);
395
396 parent = aml_namespace_traverse_parents(parent, nameString->prefixPath.depth);
397 if (parent == NULL)
398 {
399 return ERR;
400 }
401
402 uint64_t result = aml_namespace_add_child(overlay, parent, targetName, object);
403 DEREF(parent);
404 return result;
405 }
406
407 aml_name_string_t parentNameString = *nameString;
408 parentNameString.namePath.segmentCount--;
409
410 aml_object_t* parent = aml_namespace_find_by_name_string(overlay, start, &parentNameString);
411 if (parent == NULL)
412 {
413 errno = ENOENT;
414 return ERR;
415 }
416
417 DEREF_DEFER(parent);
418 return aml_namespace_add_child(overlay, parent, targetName, object);
419}
420
422{
423 if (object == NULL || !(object->flags & AML_OBJECT_NAMED))
424 {
425 return;
426 }
427
428 aml_object_id_t parentId = object->parent != NULL ? object->parent->id : AML_OBJECT_ID_NONE;
429 map_key_t key = aml_object_map_key(parentId, object->name);
430
431 map_remove(&object->overlay->map, &key);
432 list_remove(&object->overlay->objects, &object->listEntry);
433 list_remove(&object->parent->children, &object->siblingsEntry);
434
435 object->overlay = NULL;
436 object->parent = NULL;
437 object->flags &= ~AML_OBJECT_NAMED;
438 object->name = AML_NAME_UNDEFINED;
439
440 DEREF(object);
441}
442
444{
445 if (overlay == NULL || overlay->parent == NULL)
446 {
447 errno = EINVAL;
448 return ERR;
449 }
450
451 aml_object_t* object;
452 aml_object_t* temp;
453 LIST_FOR_EACH_SAFE(object, temp, &overlay->objects, listEntry)
454 {
455 aml_object_id_t parentId = object->parent != NULL ? object->parent->id : AML_OBJECT_ID_NONE;
456 map_key_t key = aml_object_map_key(parentId, object->name);
457
458 map_remove(&overlay->map, &key);
459 if (map_insert(&overlay->parent->map, &key, &object->mapEntry) == ERR)
460 {
461 return ERR;
462 }
463
464 list_remove(&overlay->objects, &object->listEntry);
465 list_push(&overlay->parent->objects, &object->listEntry);
466
467 object->overlay = overlay->parent;
468 }
469
470 assert(list_is_empty(&overlay->objects));
471 assert(map_is_empty(&overlay->map));
472
473 return 0;
474}
475
477{
478 if (overlay == NULL)
479 {
480 errno = EINVAL;
481 return ERR;
482 }
483
484 if (map_init(&overlay->map) == ERR)
485 {
486 return ERR;
487 }
488 list_init(&overlay->objects);
489 overlay->parent = overlay != &globalOverlay ? &globalOverlay : NULL;
490 return 0;
491}
492
494{
495 if (overlay == NULL)
496 {
497 return;
498 }
499
500 aml_object_t* object;
501 aml_object_t* temp;
502 LIST_FOR_EACH_SAFE(object, temp, &overlay->objects, listEntry)
503 {
504 aml_namespace_remove(object);
505 }
506
507 map_deinit(&overlay->map);
508}
509
511{
512 if (overlay == NULL)
513 {
514 return;
515 }
516
517 overlay->parent = parent;
518}
519
521 aml_object_t* object)
522{
523 if (overlay == NULL || object == NULL)
524 {
525 return NULL;
526 }
527
528 aml_object_id_t parentId = object->parent != NULL ? object->parent->id : AML_OBJECT_ID_NONE;
529 map_key_t key = aml_object_map_key(parentId, object->name);
530
531 aml_namespace_overlay_t* currentOverlay = overlay;
532 while (currentOverlay != NULL)
533 {
534 if (map_get(&currentOverlay->map, &key) != NULL)
535 {
536 return currentOverlay;
537 }
538
539 currentOverlay = currentOverlay->parent;
540 }
541
542 return NULL;
543}
static aml_object_t * aml_namespace_search_single_name(aml_namespace_overlay_t *overlay, aml_object_t *current, aml_name_t name)
Definition namespace.c:43
static aml_object_t * aml_namespace_traverse_parents(aml_object_t *current, uint64_t depth)
Definition namespace.c:27
static map_key_t aml_object_map_key(aml_object_id_t parentId, aml_name_t name)
Definition namespace.c:14
static aml_object_t * namespaceRoot
Definition namespace.c:12
static aml_namespace_overlay_t globalOverlay
Definition namespace.c:10
#define assert(expression)
Definition assert.h:29
aml_object_t * aml_namespace_find(aml_namespace_overlay_t *overlay, aml_object_t *start, uint64_t nameCount,...)
Find an object in the namespace heirarchy by name segments.
Definition namespace.c:129
aml_object_t * aml_namespace_find_by_name_string(aml_namespace_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:174
uint64_t aml_namespace_commit(aml_namespace_overlay_t *overlay)
Commit all names in a namespace overlay to the global namespace heirarchy.
Definition namespace.c:443
uint64_t aml_namespace_init(aml_object_t *root)
Initialize the namespace heirarchy.
Definition namespace.c:68
uint64_t aml_namespace_add_child(aml_namespace_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:332
void aml_namespace_overlay_set_parent(aml_namespace_overlay_t *overlay, aml_namespace_overlay_t *parent)
Set the parent of a namespace overlay.
Definition namespace.c:510
#define AML_NAME_UNDEFINED
Macro for an undefined name.
Definition namespace.h:121
aml_object_t * aml_namespace_find_child(aml_namespace_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:91
uint64_t aml_namespace_expose(void)
Expose the entire namespace heirarchy to sysfs.
Definition namespace.c:80
aml_object_t * aml_namespace_find_by_path(aml_namespace_overlay_t *overlay, aml_object_t *start, const char *path)
Find an object in the namespace heirarchy by a path string.
Definition namespace.c:225
aml_namespace_overlay_t * aml_namespace_overlay_get_highest_that_contains(aml_namespace_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:520
uint64_t aml_namespace_overlay_init(aml_namespace_overlay_t *overlay)
Initialize a namespace overlay.
Definition namespace.c:476
#define AML_NAME(a, b, c, d)
Macro to create an aml_name_t from 4 characters.
Definition namespace.h:112
void aml_namespace_remove(aml_object_t *object)
Remove an object from the namespace heirarchy it was added to.
Definition namespace.c:421
void aml_namespace_overlay_deinit(aml_namespace_overlay_t *overlay)
Deinitialize a namespace overlay.
Definition namespace.c:493
uint64_t aml_namespace_add_by_name_string(aml_namespace_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:381
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:86
aml_object_t * aml_alias_obj_traverse(aml_alias_obj_t *alias)
Traverse an alias object to get the target object.
Definition object.c:1114
#define AML_OBJECT_ID_NONE
Value for an invalid object id.
Definition object.h:151
uint64_t aml_object_id_t
Object id type.
Definition object.h:146
@ AML_ALIAS
Not in the spec, used internally to represent Aliases.
Definition object.h:85
@ AML_OBJECT_ROOT
Is the root object.
Definition object.h:125
@ AML_OBJECT_NAMED
Appears in the namespace tree. Will be set in aml_object_add().
Definition object.h:126
#define PACKED
GCC packed attribute.
Definition defs.h:32
static map_key_t map_key_buffer(const void *buffer, uint64_t length)
Create a map key from a buffer.
Definition map.h:99
void map_deinit(map_t *map)
Deinitialize a map.
Definition map.c:182
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *value)
Insert a key-value pair into the map.
Definition map.c:191
uint64_t map_init(map_t *map)
Initialize a map.
Definition map.c:172
void map_remove(map_t *map, const map_key_t *key)
Remove a key-value pair from the map.
Definition map.c:258
bool map_is_empty(const map_t *map)
Check if the map is empty.
Definition map.c:289
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:236
#define DEREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EEXIST
File exists.
Definition errno.h:117
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:81
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static void start()
Definition main.c:542
static atomic_long next
Definition main.c:10
#define va_start(ap, parmN)
Definition stdarg.h:14
#define va_arg(ap, type)
Definition stdarg.h:11
#define va_end(ap)
Definition stdarg.h:13
__builtin_va_list va_list
Definition stdarg.h:9
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
aml_name_seg_t * segments
Array of segments in the name path.
Definition name.h:79
uint64_t segmentCount
Number of segments in the name path.
Definition name.h:78
A NameString structure.
Definition name.h:87
aml_name_path_t namePath
Definition name.h:90
aml_prefix_path_t prefixPath
Definition name.h:89
aml_root_char_t rootChar
Definition name.h:88
Namespace overlay.
Definition namespace.h:87
struct aml_namespace_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
list_t objects
List of all objects in this namespace. Used for fast iteration.
Definition namespace.h:89
ACPI object.
Definition object.h:425
aml_alias_obj_t alias
Definition object.h:446
uint16_t depth
Definition name.h:53
bool present
If the first character is a root character ('\'), if yes, the name string is absolute.
Definition name.h:63
Map key stucture.
Definition map.h:45