PatchworkOS  2ca1c69
A non-POSIX operating system.
Loading...
Searching...
No Matches
namespace.c
Go to the documentation of this file.
2
3#include <kernel/fs/sysfs.h>
4#include <kernel/log/log.h>
5#include <kernel/log/panic.h>
6#include <kernel/utils/map.h>
7#include <modules/acpi/acpi.h>
11
12#include <errno.h>
13
15
17
19
21{
22 // Pack the parentId and name into a single buffer for the map key
23 struct PACKED
24 {
25 aml_object_id_t parentId;
26 aml_name_t name;
27 } buffer;
28 buffer.parentId = parentId;
29 buffer.name = name;
30 return map_key_buffer(&buffer, sizeof(buffer));
31}
32
34{
35 for (uint64_t i = 0; i < depth; i++)
36 {
37 if (current == NULL || current->parent == NULL)
38 {
39 DEREF(current);
40 return NULL;
41 }
42 aml_object_t* parent = REF(current->parent);
43 DEREF(current);
44 current = parent;
45 }
46 return current;
47}
48
50 aml_name_t name)
51{
52 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
53
54 if (next == NULL)
55 {
56 while (current->parent != NULL)
57 {
58 aml_object_t* parent = REF(current->parent);
59 DEREF(current);
60 current = parent;
61
62 next = aml_namespace_find_child(overlay, current, name);
63 if (next != NULL)
64 {
65 break;
66 }
67 }
68 }
69
70 DEREF(current);
71 return next;
72}
73
75{
77 root->flags |= AML_OBJECT_NAMED | AML_OBJECT_ROOT;
78 root->name = AML_NAME('\\', '_', '_', '_');
79 namespaceRoot = REF(root);
80}
81
83{
84 if (object == NULL || parentDir == NULL)
85 {
86 return ERR;
87 }
88
89 if (!(object->flags & AML_OBJECT_NAMED))
90 {
91 // Something is very wrong if we have an unnamed object in the namespace heirarchy
92 LOG_ERR("unnamed object %s of type %s found in the namespace heirarchy\n", AML_NAME_TO_STRING(object->name),
93 aml_type_to_string(object->type));
94 return ERR;
95 }
96
97 object->dir = sysfs_dir_new(parentDir, AML_NAME_TO_STRING(object->name), NULL, NULL);
98 if (object->dir == NULL)
99 {
100 LOG_ERR("Failed to create sysfs directory %s\n", AML_NAME_TO_STRING(object->name));
101 return ERR;
102 }
103
104 if (object->type & AML_NAMESPACES)
105 {
106 aml_object_t* child = NULL;
107 LIST_FOR_EACH(child, &object->children, siblingsEntry)
108 {
109 if (aml_namespace_expose_object(child, object->dir) == ERR)
110 {
111 LOG_ERR("Failed to expose child %s of %s in sysfs\n", AML_NAME_TO_STRING(child->name),
112 AML_NAME_TO_STRING(object->name));
113 return ERR;
114 }
115 }
116 }
117
118 return 0;
119}
120
122{
123 dentry_t* acpiDir = acpi_get_sysfs_root();
124 assert(acpiDir != NULL);
125
126 namespaceDir = sysfs_dir_new(acpiDir, "namespace", NULL, NULL);
127 DEREF(acpiDir);
128 if (namespaceDir == NULL)
129 {
130 LOG_ERR("Failed to create ACPI namespace sysfs directory");
131 return ERR;
132 }
133
134 aml_object_t* child = NULL;
135 LIST_FOR_EACH(child, &namespaceRoot->children, siblingsEntry)
136 {
138 {
141 LOG_ERR("Failed to expose ACPI namespace in sysfs");
142 return ERR;
143 }
144 }
145
146 return 0;
147}
148
153
155{
156 if (parent == NULL || !(parent->flags & AML_OBJECT_NAMED))
157 {
158 return NULL;
159 }
160
161 if (overlay == NULL)
162 {
163 overlay = &globalOverlay;
164 }
165
166 map_key_t key = aml_object_map_key(parent->id, name);
167 aml_object_t* child = NULL;
168 while (overlay != NULL)
169 {
170 child = CONTAINER_OF_SAFE(map_get(&overlay->map, &key), aml_object_t, mapEntry);
171 if (child != NULL)
172 {
173 break;
174 }
175
176 overlay = overlay->parent;
177 }
178
179 if (child == NULL)
180 {
181 return NULL;
182 }
183
184 if (child->type == AML_ALIAS)
185 {
186 return aml_alias_traverse(&child->alias);
187 }
188
189 return REF(child);
190}
191
193{
194 if (nameCount == 0)
195 {
196 return NULL;
197 }
198
199 aml_object_t* current = start != NULL ? REF(start) : REF(namespaceRoot);
200 if (current == NULL || !(current->flags & AML_OBJECT_NAMED))
201 {
202 DEREF(current);
203 return NULL;
204 }
205
206 if (nameCount == 1)
207 {
208 va_list args;
209 va_start(args, nameCount);
210 aml_name_t name = va_arg(args, aml_name_t);
211 va_end(args);
212
213 return aml_namespace_search_single_name(overlay, current, name);
214 }
215
216 va_list args;
217 va_start(args, nameCount);
218 for (uint64_t i = 0; i < nameCount; i++)
219 {
220 aml_name_t name = va_arg(args, aml_name_t);
221 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
222
223 if (next == NULL)
224 {
225 DEREF(current);
226 va_end(args);
227 return NULL;
228 }
229
230 DEREF(current);
231 current = next;
232 }
233 va_end(args);
234 return current; // Transfer ownership
235}
236
238 const aml_name_string_t* nameString)
239{
240 if (nameString == NULL)
241 {
242 return NULL;
243 }
244
245 aml_object_t* current = (start == NULL || nameString->rootChar.present) ? REF(namespaceRoot) : REF(start);
246 if (!(current->flags & AML_OBJECT_NAMED))
247 {
248 DEREF(current);
249 return NULL;
250 }
251
252 current = aml_namespace_traverse_parents(current, nameString->prefixPath.depth);
253 if (current == NULL)
254 {
255 return NULL;
256 }
257
258 if (!nameString->rootChar.present && nameString->prefixPath.depth == 0 && nameString->namePath.segmentCount == 1)
259 {
260 aml_name_t name = nameString->namePath.segments[0];
261 return aml_namespace_search_single_name(overlay, current, name);
262 }
263
264 for (uint64_t i = 0; i < nameString->namePath.segmentCount; i++)
265 {
266 if (!(current->flags & AML_OBJECT_NAMED))
267 {
268 DEREF(current);
269 return NULL;
270 }
271
272 aml_name_t name = nameString->namePath.segments[i];
273 aml_object_t* next = aml_namespace_find_child(overlay, current, name);
274
275 if (next == NULL)
276 {
277 DEREF(current);
278 return NULL;
279 }
280
281 DEREF(current);
282 current = next;
283 }
284
285 return current; // Transfer ownership
286}
287
289{
290 if (path == NULL || path[0] == '\0')
291 {
292 errno = EINVAL;
293 return NULL;
294 }
295
296 aml_object_t* current = NULL;
297 const char* p = path;
298 if (p[0] == '\\')
299 {
300 current = REF(namespaceRoot);
301 p++;
302 }
303 else if (p[0] == '^')
304 {
305 if (start == NULL)
306 {
307 errno = EINVAL;
308 return NULL;
309 }
310
311 uint64_t depth = 0;
312 while (p[0] == '^')
313 {
314 depth++;
315 p++;
316 }
317
318 current = aml_namespace_traverse_parents(REF(start), depth);
319 }
320 else
321 {
322 current = start != NULL ? REF(start) : REF(namespaceRoot);
323 }
324
325 if (current == NULL || !(current->flags & AML_OBJECT_NAMED))
326 {
327 DEREF(current);
328 return NULL;
329 }
330
331 if (*p == '\0')
332 {
333 return current; // Transfer ownership
334 }
335
336 uint64_t segmentCount = 0;
337 while (*p != '\0')
338 {
339 const char* segmentStart = p;
340 while (*p != '.' && *p != '\0')
341 {
342 p++;
343 }
344
345 uint64_t segmentLength = p - segmentStart;
346 if (segmentLength > sizeof(aml_name_t))
347 {
348 DEREF(current);
349 return NULL;
350 }
351
352 aml_name_t segment = 0;
353 for (uint64_t i = 0; i < segmentLength; i++)
354 {
355 segment |= ((aml_name_t)(uint8_t)segmentStart[i]) << (i * 8);
356 }
357
358 segmentCount++;
359
360 if (*p == '.')
361 {
362 p++;
363 }
364
365 aml_object_t* next = aml_namespace_find_child(overlay, current, segment);
366 if (next == NULL && segmentCount == 1 && *p == '\0')
367 {
368 while (current->parent != NULL)
369 {
370 aml_object_t* parent = REF(current->parent);
371 DEREF(current);
372 current = parent;
373
374 next = aml_namespace_find_child(overlay, current, segment);
375 if (next != NULL)
376 {
377 break;
378 }
379 }
380 }
381
382 if (next == NULL)
383 {
384 DEREF(current);
385 return NULL;
386 }
387
388 DEREF(current);
389 current = next;
390 }
391
392 return current; // Transfer ownership
393}
394
396{
397 if (object == NULL)
398 {
399 errno = EINVAL;
400 return ERR;
401 }
402
403 if (object->type == AML_UNINITIALIZED)
404 {
405 errno = EINVAL;
406 return ERR;
407 }
408
409 parent = parent != NULL ? parent : namespaceRoot;
410 if (!(parent->flags & AML_OBJECT_NAMED) || (object->flags & AML_OBJECT_NAMED))
411 {
412 errno = EINVAL;
413 return ERR;
414 }
415
416 if (overlay == NULL)
417 {
418 overlay = &globalOverlay;
419 }
420
421 map_key_t key = aml_object_map_key(parent->id, name);
422 aml_overlay_t* currentOverlay = overlay;
423 while (currentOverlay != NULL)
424 {
425 if (map_get(&currentOverlay->map, &key) != NULL)
426 {
427 errno = EEXIST;
428 return ERR;
429 }
430 currentOverlay = currentOverlay->parent;
431 }
432
433 if (map_insert(&overlay->map, &key, &object->mapEntry) == ERR)
434 {
435 return ERR;
436 }
437 list_push_back(&overlay->objects, &object->listEntry);
438 list_push_back(&parent->children, &object->siblingsEntry);
439
440 object->flags |= AML_OBJECT_NAMED;
441 object->overlay = overlay;
442 object->parent = parent;
443 object->name = name;
444
445 REF(object);
446 return 0;
447}
448
450 const aml_name_string_t* nameString, aml_object_t* object)
451{
452 if (nameString == NULL || nameString->namePath.segmentCount == 0)
453 {
454 errno = EINVAL;
455 return ERR;
456 }
457
458 aml_name_t targetName = nameString->namePath.segments[nameString->namePath.segmentCount - 1];
459 if (nameString->namePath.segmentCount == 1)
460 {
461 aml_object_t* parent = (start == NULL || nameString->rootChar.present) ? REF(namespaceRoot) : REF(start);
462
463 parent = aml_namespace_traverse_parents(parent, nameString->prefixPath.depth);
464 if (parent == NULL)
465 {
466 return ERR;
467 }
468 DEREF_DEFER(parent);
469
470 return aml_namespace_add_child(overlay, parent, targetName, object);
471 }
472
473 aml_name_string_t parentNameString = *nameString;
474 parentNameString.namePath.segmentCount--;
475
476 aml_object_t* parent = aml_namespace_find_by_name_string(overlay, start, &parentNameString);
477 if (parent == NULL)
478 {
479 errno = ENOENT;
480 return ERR;
481 }
482 DEREF_DEFER(parent);
483
484 return aml_namespace_add_child(overlay, parent, targetName, object);
485}
486
488{
489 if (object == NULL || !(object->flags & AML_OBJECT_NAMED))
490 {
491 return;
492 }
493
494 map_remove(&object->overlay->map, &object->mapEntry);
495 list_remove(&object->overlay->objects, &object->listEntry);
496 list_remove(&object->parent->children, &object->siblingsEntry);
497
498 object->overlay = NULL;
499 object->parent = NULL;
500 object->flags &= ~AML_OBJECT_NAMED;
501 object->name = AML_NAME_UNDEFINED;
502
503 DEREF(object);
504}
505
507{
508 if (overlay == NULL || overlay->parent == NULL)
509 {
510 errno = EINVAL;
511 return ERR;
512 }
513
514 aml_object_t* object;
515 aml_object_t* temp;
516 LIST_FOR_EACH_SAFE(object, temp, &overlay->objects, listEntry)
517 {
518 map_remove(&overlay->map, &object->mapEntry);
519
520 map_key_t key =
521 aml_object_map_key(object->parent != NULL ? object->parent->id : AML_OBJECT_ID_NONE, object->name);
522 if (map_insert(&overlay->parent->map, &key, &object->mapEntry) == ERR)
523 {
524 return ERR;
525 }
526
527 list_remove(&overlay->objects, &object->listEntry);
528 list_push_back(&overlay->parent->objects, &object->listEntry);
529
530 object->overlay = overlay->parent;
531 }
532
533 assert(list_is_empty(&overlay->objects));
534 assert(map_is_empty(&overlay->map));
535
536 return 0;
537}
538
540{
541 if (overlay == NULL)
542 {
543 return;
544 }
545
546 map_init(&overlay->map);
547 list_init(&overlay->objects);
548 overlay->parent = overlay != &globalOverlay ? &globalOverlay : NULL;
549}
550
552{
553 if (overlay == NULL)
554 {
555 return;
556 }
557
558 while (!list_is_empty(&overlay->objects))
559 {
560 aml_object_t* obj = CONTAINER_OF(list_pop_first(&overlay->objects), aml_object_t, listEntry);
562 }
563
564 map_deinit(&overlay->map);
565}
566
568{
569 if (overlay == NULL)
570 {
571 return;
572 }
573
574 overlay->parent = parent;
575}
576
578{
579 if (overlay == NULL || object == NULL)
580 {
581 return NULL;
582 }
583
584 aml_object_id_t parentId = object->parent != NULL ? object->parent->id : AML_OBJECT_ID_NONE;
585 map_key_t key = aml_object_map_key(parentId, object->name);
586
587 aml_overlay_t* currentOverlay = overlay;
588 while (currentOverlay != NULL)
589 {
590 if (map_get(&currentOverlay->map, &key) != NULL)
591 {
592 return currentOverlay;
593 }
594
595 currentOverlay = currentOverlay->parent;
596 }
597
598 return NULL;
599}
#define assert(expression)
Definition assert.h:29
#define PACKED
GCC packed attribute.
Definition defs.h:32
#define LOG_ERR(format,...)
Definition log.h:108
static map_key_t map_key_buffer(const void *buffer, uint64_t length)
Create a map key from a buffer.
Definition map.h:112
void map_init(map_t *map)
Initialize a map.
Definition map.c:176
void map_deinit(map_t *map)
Deinitialize a map.
Definition map.c:184
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:204
void map_remove(map_t *map, map_entry_t *entry)
Remove a entry from the map.
Definition map.c:353
bool map_is_empty(const map_t *map)
Check if the map is empty.
Definition map.c:391
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:287
#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(elem, list, member)
Iterates over a list.
Definition list.h:61
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:373
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:341
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:77
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:313
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:225
static void list_init(list_t *list)
Initializes a list.
Definition list.h:194
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF(ptr, type, member)
Container of macro.
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
#define AML_NAME_TO_STRING(name)
Macro to convert an aml_name_t to a stack allocated string.
Definition namespace.h:129
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
#define AML_NAME_UNDEFINED
Macro for an undefined name.
Definition namespace.h:121
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
#define AML_NAME(a, b, c, d)
Macro to create an aml_name_t from 4 characters.
Definition namespace.h:112
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
aml_object_t * aml_alias_traverse(aml_alias_t *alias)
Traverse an alias object to get the target object.
Definition object.c:1171
#define AML_OBJECT_ID_NONE
Value for an invalid object id.
Definition object.h:153
uint64_t aml_object_id_t
Object id type.
Definition object.h:148
@ AML_ALIAS
Not in the spec, used internally to represent Aliases.
Definition object.h:87
@ AML_NAMESPACES
Definition object.h:109
@ AML_UNINITIALIZED
Definition object.h:60
@ AML_OBJECT_ROOT
Is the root object.
Definition object.h:127
@ AML_OBJECT_NAMED
Appears in the namespace tree. Will be set in aml_object_add().
Definition object.h:128
const char * aml_type_to_string(aml_type_t type)
Convert an aml data type to a string.
Definition to_string.c:5
dentry_t * acpi_get_sysfs_root(void)
Retrieve the sysfs root directory for ACPI.
Definition acpi.c:34
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static dentry_t * namespaceDir
Definition namespace.c:18
static uint64_t aml_namespace_expose_object(aml_object_t *object, dentry_t *parentDir)
Definition namespace.c:82
static aml_object_t * aml_namespace_traverse_parents(aml_object_t *current, uint64_t depth)
Definition namespace.c:33
static aml_object_t * aml_namespace_search_single_name(aml_overlay_t *overlay, aml_object_t *current, aml_name_t name)
Definition namespace.c:49
static map_key_t aml_object_map_key(aml_object_id_t parentId, aml_name_t name)
Definition namespace.c:20
static aml_overlay_t globalOverlay
Definition namespace.c:14
static aml_object_t * namespaceRoot
Definition namespace.c:16
static void start()
Definition main.c:542
static atomic_long next
Definition main.c:11
#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
ACPI object.
Definition object.h:447
aml_alias_t alias
Definition object.h:469
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
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
Directory entry structure.
Definition dentry.h:80
Map key stucture.
Definition map.h:56
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted SysFS instance.
Definition sysfs.c:179