PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
module.c
Go to the documentation of this file.
1#include <kernel/fs/dentry.h>
2#include <kernel/fs/sysfs.h>
4
5#include <kernel/fs/vfs.h>
7#include <kernel/log/log.h>
8#include <kernel/log/panic.h>
9#include <kernel/mem/vmm.h>
11#include <kernel/proc/process.h>
12#include <kernel/sched/sched.h>
13#include <kernel/sync/lock.h>
14#include <kernel/utils/map.h>
15#include <kernel/version.h>
16
17#include <stddef.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/elf.h>
23#include <sys/io.h>
24#include <sys/list.h>
25
27 .name = "kernel",
28 .author = "The PatchworkOS Authors",
29 .description = "The PatchworkOS Kernel",
30 .version = OS_VERSION,
31 .license = "MIT",
32 .osVersion = OS_VERSION,
33 .deviceTypes = "",
34};
35
37static map_t modulesMap = MAP_CREATE(); ///< Key = module name, value = module_t*
39 MAP_CREATE(); ///< Key = symbol_group_id_t, value = module_t*. Used to find which module provides which symbols.
40
41static map_t deviceMap = MAP_CREATE(); ///< Key = device name, value = module_device_t*
42
43static map_t symbolCache = MAP_CREATE(); ///< Key = symbol name, value = module_cached_symbol_t*
44static map_t deviceCache = MAP_CREATE(); ///< Key = device type, value = module_cached_device_t*
45static bool cacheValid = false;
46
48
49static void* module_resolve_symbol_callback(const char* name, void* private);
50
51#define MODULE_SYMBOL_ALLOWED(type, binding, name) \
52 (((type) == STT_OBJECT || (type) == STT_FUNC) && ((binding) == STB_GLOBAL) && \
53 (strncmp(name, MODULE_RESERVED_PREFIX, MODULE_RESERVED_PREFIX_LENGTH) != 0))
54
56{
57 module_t* module = malloc(sizeof(module_t) + info->dataSize);
58 if (module == NULL)
59 {
60 return NULL;
61 }
62 list_entry_init(&module->listEntry);
63 map_entry_init(&module->mapEntry);
64 map_entry_init(&module->providerEntry);
65 list_entry_init(&module->gcEntry);
66 list_entry_init(&module->loadEntry);
67 module->flags = MODULE_FLAG_NONE;
68 module->baseAddr = NULL;
69 module->size = 0;
70 module->procedure = NULL;
71 module->symbolGroupId = symbol_generate_group_id();
72 list_init(&module->dependencies);
73 list_init(&module->deviceHandlers);
74 memcpy_s(&module->info, sizeof(module_info_t) + info->dataSize, info, sizeof(module_info_t) + info->dataSize);
75
76 // Since the info strings are stored as pointers into the info data, we need to adjust them to point into our own
77 // copy.
78 intptr_t offset = (intptr_t)module->info.data - (intptr_t)info->data;
79 module->info.name = (char*)((uintptr_t)module->info.name + offset);
80 module->info.author = (char*)((uintptr_t)module->info.author + offset);
81 module->info.description = (char*)((uintptr_t)module->info.description + offset);
82 module->info.version = (char*)((uintptr_t)module->info.version + offset);
83 module->info.license = (char*)((uintptr_t)module->info.license + offset);
84 module->info.osVersion = (char*)((uintptr_t)module->info.osVersion + offset);
85 module->info.deviceTypes = (char*)((uintptr_t)module->info.deviceTypes + offset);
86
87 list_push_back(&modulesList, &module->listEntry);
88
89 map_key_t moduleKey = map_key_string(info->name);
90 if (map_insert(&modulesMap, &moduleKey, &module->mapEntry) == ERR)
91 {
92 list_remove(&modulesList, &module->listEntry);
93 free(module);
94 return NULL;
95 }
96
97 map_key_t providerKey = map_key_uint64(module->symbolGroupId);
98 if (map_insert(&providerMap, &providerKey, &module->providerEntry) == ERR)
99 {
100 list_remove(&modulesList, &module->listEntry);
101 map_remove(&modulesMap, &module->mapEntry);
102 free(module);
103 return NULL;
104 }
105
106 return module;
107}
108
109static void module_free(module_t* module)
110{
111 LOG_DEBUG("freeing resources for module '%s'\n", module->info.name);
112
113 assert(!(module->flags & MODULE_FLAG_LOADED));
114
116 map_remove(&modulesMap, &module->mapEntry);
118
120
121 if (module->baseAddr != NULL)
122 {
123 vmm_unmap(NULL, module->baseAddr, module->size);
124 }
125
126 free(module);
127}
128
130{
131 LOG_DEBUG("calling load event for module '%s'\n", module->info.name);
132 module_event_t loadEvent = {
134 };
135 if (module->procedure(&loadEvent) == ERR)
136 {
137 LOG_ERR("call to load event for module '%s' failed\n", module->info.name);
138 return ERR;
139 }
140 module->flags |= MODULE_FLAG_LOADED;
141 return 0;
142}
143
145{
146 if (module->flags & MODULE_FLAG_LOADED)
147 {
148 LOG_DEBUG("calling unload event for module '%s'\n", module->info.name);
149 module_event_t unloadEvent = {
151 };
152 module->procedure(&unloadEvent);
153 module->flags &= ~MODULE_FLAG_LOADED;
154 }
155}
156
157static module_t* module_find_by_name(const char* name)
158{
159 map_key_t moduleKey = map_key_string(name);
160 return CONTAINER_OF_SAFE(map_get(&modulesMap, &moduleKey), module_t, mapEntry);
161}
162
164{
165 map_key_t providerKey = map_key_uint64(groupId);
166 return CONTAINER_OF_SAFE(map_get(&providerMap, &providerKey), module_t, providerEntry);
167}
168
169static module_device_t* module_device_new(const char* type, const char* name)
170{
171 module_device_t* device = malloc(sizeof(module_device_t));
172 if (device == NULL)
173 {
174 return NULL;
175 }
176 map_entry_init(&device->mapEntry);
179 list_init(&device->handlers);
180
181 map_key_t deviceKey = map_key_string(name);
182 if (map_insert(&deviceMap, &deviceKey, &device->mapEntry) == ERR)
183 {
184 free(device);
185 return NULL;
186 }
187
188 return device;
189}
190
192{
193 assert(list_is_empty(&device->handlers));
194
195 map_remove(&deviceMap, &device->mapEntry);
196 free(device);
197}
198
199static module_device_t* module_device_get(const char* name)
200{
201 map_key_t deviceKey = map_key_string(name);
202 return CONTAINER_OF_SAFE(map_get(&deviceMap, &deviceKey), module_device_t, mapEntry);
203}
204
206{
208 if (handler == NULL)
209 {
210 return NULL;
211 }
212 list_entry_init(&handler->deviceEntry);
213 list_entry_init(&handler->moduleEntry);
214 list_entry_init(&handler->loadEntry);
215 handler->module = module;
216 handler->device = device;
217
218 module_event_t attachEvent = {
220 .deviceAttach.type = device->type,
221 .deviceAttach.name = device->name,
222 };
223 if (module->procedure(&attachEvent) == ERR)
224 {
225 LOG_ERR("call to attach event for module '%s' failed\n", module->info.name);
226 free(handler);
227 return NULL;
228 }
229
230 list_push_back(&device->handlers, &handler->deviceEntry);
231 list_push_back(&module->deviceHandlers, &handler->moduleEntry);
232 return handler;
233}
234
236{
237 module_event_t detachEvent = {
239 .deviceDetach.type = handler->device->type,
240 .deviceDetach.name = handler->device->name,
241 };
242 handler->module->procedure(&detachEvent);
243
244 list_remove(&handler->device->handlers, &handler->deviceEntry);
245 list_remove(&handler->module->deviceHandlers, &handler->moduleEntry);
246 free(handler);
247}
248
249/**
250 * @brief Copy a string up to either a null-terminator or a semicolon into the output buffer.
251 */
252static inline uint64_t module_string_copy(const char* str, char* out, size_t outSize)
253{
254 if (outSize == 0)
255 {
256 return 0;
257 }
258
259 size_t len = 0;
260 while (str[len] != '\0' && str[len] != ';' && len < outSize - 1)
261 {
262 len++;
263 }
264 strncpy_s(out, outSize, str, len);
265 return len;
266}
267
268static inline module_info_t* module_info_parse(const char* moduleInfo)
269{
270 size_t totalSize = strnlen_s(moduleInfo, MODULE_MAX_INFO);
271 if (totalSize < MODULE_MIN_INFO || totalSize >= MODULE_MAX_INFO)
272 {
273 LOG_ERR("module info string is of invalid size %zu\n", totalSize);
274 errno = EILSEQ;
275 return NULL;
276 }
277
278 module_info_t* info = malloc(sizeof(module_info_t) + totalSize + 1);
279 if (info == NULL)
280 {
281 return NULL;
282 }
283
284 size_t offset = 0;
285 info->name = &info->data[offset];
286 size_t parsed = module_string_copy(&moduleInfo[offset], info->name, MODULE_MAX_NAME);
287 if (parsed == 0)
288 {
289 LOG_ERR("failed to parse module name\n");
290 goto error;
291 }
292 info->name[parsed] = '\0';
293 offset += parsed + 1;
294
295 info->author = &info->data[offset];
296 parsed = module_string_copy(&moduleInfo[offset], info->author, MODULE_MAX_AUTHOR);
297 if (parsed == 0)
298 {
299 LOG_ERR("failed to parse module author\n");
300 goto error;
301 }
302 info->author[parsed] = '\0';
303 offset += parsed + 1;
304
305 info->description = &info->data[offset];
306 parsed = module_string_copy(&moduleInfo[offset], info->description, MODULE_MAX_DESCRIPTION);
307 if (parsed == 0)
308 {
309 LOG_ERR("failed to parse module description\n");
310 goto error;
311 }
312 info->description[parsed] = '\0';
313 offset += parsed + 1;
314
315 info->version = &info->data[offset];
316 parsed = module_string_copy(&moduleInfo[offset], info->version, MODULE_MAX_VERSION);
317 if (parsed == 0)
318 {
319 LOG_ERR("failed to parse module version\n");
320 goto error;
321 }
322 info->version[parsed] = '\0';
323 offset += parsed + 1;
324
325 info->license = &info->data[offset];
326 parsed = module_string_copy(&moduleInfo[offset], info->license, MODULE_MAX_LICENSE);
327 if (parsed == 0)
328 {
329 LOG_ERR("failed to parse module license\n");
330 goto error;
331 }
332 info->license[parsed] = '\0';
333 offset += parsed + 1;
334
335 info->osVersion = &info->data[offset];
336 parsed = module_string_copy(&moduleInfo[offset], info->osVersion, MODULE_MAX_VERSION);
337 if (parsed == 0)
338 {
339 LOG_ERR("failed to parse module OS version\n");
340 goto error;
341 }
342 info->osVersion[parsed] = '\0';
343 offset += parsed + 1;
344
345 if (strcmp(info->osVersion, OS_VERSION) != 0)
346 {
347 LOG_ERR("module '%s' requires OS version '%s' but running version is '%s'\n", info->name, info->osVersion,
348 OS_VERSION);
349 goto error;
350 }
351
352 size_t deviceTypesLength = totalSize - offset;
353 info->deviceTypes = &info->data[offset];
354 strncpy_s(info->deviceTypes, deviceTypesLength + 1, &moduleInfo[offset], deviceTypesLength + 1);
355
356 info->dataSize = totalSize + 1;
357 return info;
358
359error:
360 free(info);
361 errno = EILSEQ;
362 return NULL;
363}
364
370
371static uint64_t module_file_read(module_file_t* outFile, const path_t* dirPath, process_t* process,
372 const char* filename)
373{
374 file_t* file = vfs_openat(dirPath, PATHNAME(filename), process);
375 if (file == NULL)
376 {
377 return ERR;
378 }
380
381 uint64_t fileSize = vfs_seek(file, 0, SEEK_END);
383 if (fileSize == ERR)
384 {
385 return ERR;
386 }
387
388 uint8_t* fileData = malloc(fileSize);
389 if (fileData == NULL)
390 {
391 return ERR;
392 }
393
394 if (vfs_read(file, fileData, fileSize) != fileSize)
395 {
396 free(fileData);
397 return ERR;
398 }
399
400 if (elf64_validate(&outFile->elf, fileData, fileSize) == ERR)
401 {
402 LOG_ERR("failed to validate ELF file '%s' while reading module metadata\n", filename);
403 free(fileData);
404 errno = EILSEQ;
405 return ERR;
406 }
407
408 Elf64_Shdr* moduleInfoShdr = elf64_get_section_by_name(&outFile->elf, MODULE_INFO_SECTION);
409 if (moduleInfoShdr == NULL || moduleInfoShdr->sh_size < MODULE_MIN_INFO ||
410 moduleInfoShdr->sh_size > MODULE_MAX_INFO)
411 {
412 LOG_ERR("failed to find valid module info section in ELF file '%s'\n", filename);
413 free(fileData);
414 errno = EILSEQ;
415 return ERR;
416 }
417
418 outFile->info = module_info_parse((const char*)((uintptr_t)outFile->elf.header + moduleInfoShdr->sh_offset));
419 if (outFile->info == NULL)
420 {
421 free(fileData);
422 errno = EILSEQ;
423 return ERR;
424 }
425
426 return 0;
427}
428
430{
431 free(file->elf.header);
432 free(file->info);
433}
434
436{
437 uint64_t index = 0;
438 while (true)
439 {
440 Elf64_Sym* sym = elf64_get_symbol_by_index(&file->elf, index++);
441 if (sym == NULL)
442 {
443 break;
444 }
445
446 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_ABS)
447 {
448 continue;
449 }
450
453 const char* symName = elf64_get_symbol_name(&file->elf, sym);
454 if (!MODULE_SYMBOL_ALLOWED(type, binding, symName))
455 {
456 continue;
457 }
458
460 if (symbolEntry == NULL)
461 {
462 return ERR;
463 }
464 map_entry_init(&symbolEntry->mapEntry);
465 symbolEntry->modulePath = strdup(path);
466 if (symbolEntry->modulePath == NULL)
467 {
468 free(symbolEntry);
469 return ERR;
470 }
471
472 map_key_t symbolKey = map_key_string(symName);
473 if (map_insert(&symbolCache, &symbolKey, &symbolEntry->mapEntry) == ERR)
474 {
475 if (errno == EEXIST)
476 {
477 LOG_ERR("symbol name collision for '%s' in module '%s'\n", symName, path);
478 }
479 free(symbolEntry);
480 return ERR;
481 }
482 }
483
484 return 0;
485}
486
488{
489 const char* ptr = file->info->deviceTypes;
490 while (*ptr != '\0')
491 {
492 char deviceType[MODULE_MAX_DEVICE_STRING] = {0};
493 uint64_t parsed = module_string_copy(ptr, deviceType, MODULE_MAX_DEVICE_STRING);
494 if (parsed == 0)
495 {
496 break;
497 }
498 ptr += parsed + 1;
499
500 map_key_t key = map_key_string(deviceType);
501 module_cached_device_t* cachedDevice =
503 if (cachedDevice == NULL)
504 {
505 cachedDevice = malloc(sizeof(module_cached_device_t));
506 if (cachedDevice == NULL)
507 {
508 return ERR;
509 }
510 map_entry_init(&cachedDevice->mapEntry);
511 list_init(&cachedDevice->entries);
512
513 if (map_insert(&deviceCache, &key, &cachedDevice->mapEntry) == ERR)
514 {
515 free(cachedDevice);
516 return ERR;
517 }
518 }
519
521 if (deviceEntry == NULL)
522 {
523 return ERR;
524 }
525 list_entry_init(&deviceEntry->listEntry);
526 strncpy_s(deviceEntry->path, MAX_PATH, path, MAX_PATH);
527
528 list_push_back(&cachedDevice->entries, &deviceEntry->listEntry);
529 }
530
531 return 0;
532}
533
535{
536 map_key_t symbolKey = map_key_string(name);
537 return CONTAINER_OF_SAFE(map_get(&symbolCache, &symbolKey), module_cached_symbol_t, mapEntry);
538}
539
541{
542 map_key_t deviceKey = map_key_string(type);
543 return CONTAINER_OF_SAFE(map_get(&deviceCache, &deviceKey), module_cached_device_t, mapEntry);
544}
545
546static void module_cache_clear(void)
547{
548 for (uint64_t i = 0; i < symbolCache.capacity; i++)
549 {
550 map_entry_t* entry = symbolCache.entries[i];
551 if (!MAP_ENTRY_PTR_IS_VALID(entry))
552 {
553 continue;
554 }
555 module_cached_symbol_t* cachedSymbol = CONTAINER_OF(entry, module_cached_symbol_t, mapEntry);
556 free(cachedSymbol->modulePath);
557 free(cachedSymbol);
558 }
560
561 for (uint64_t i = 0; i < deviceCache.capacity; i++)
562 {
563 map_entry_t* entry = deviceCache.entries[i];
564 if (!MAP_ENTRY_PTR_IS_VALID(entry))
565 {
566 continue;
567 }
568 module_cached_device_t* cachedDevice = CONTAINER_OF(entry, module_cached_device_t, mapEntry);
569 module_cached_device_entry_t* deviceEntry;
570 while (!list_is_empty(&cachedDevice->entries))
571 {
572 deviceEntry = CONTAINER_OF(list_pop_first(&cachedDevice->entries), module_cached_device_entry_t, listEntry);
573 free(deviceEntry);
574 }
575 free(cachedDevice);
576 }
578
579 cacheValid = false;
580}
581
583{
584 if (cacheValid)
585 {
586 return 0;
587 }
588
589 process_t* process = sched_process();
590 assert(process != NULL);
591
592 file_t* dir = vfs_open(PATHNAME(MODULE_DIR), process);
593 if (dir == NULL)
594 {
595 return ERR;
596 }
597 UNREF_DEFER(dir);
598
600 while (true)
601 {
602 uint64_t readCount = vfs_getdents(dir, buffer, sizeof(buffer));
603 if (readCount == ERR)
604 {
606 return ERR;
607 }
608 if (readCount == 0)
609 {
610 break;
611 }
612
613 for (uint64_t i = 0; i < readCount / sizeof(dirent_t); i++)
614 {
615 if (buffer[i].path[0] == '.' || buffer[i].type != INODE_FILE)
616 {
617 continue;
618 }
619
621 if (module_file_read(&file, &dir->path, process, buffer[i].path) == ERR)
622 {
623 if (errno == EILSEQ)
624 {
625 LOG_ERR("skipping invalid module file '%s'\n", buffer[i].path);
626 continue;
627 }
629 return ERR;
630 }
631
632 if (module_cache_symbols_add(&file, buffer[i].path) == ERR)
633 {
636 return ERR;
637 }
638
640 {
643 return ERR;
644 }
645
646 LOG_DEBUG("built cache entry for module '%s'\n", file.info->name);
648 }
649 }
650
651 cacheValid = true;
652 return 0;
653}
654
656{
657 if (module == NULL || module->flags & MODULE_FLAG_GC_REACHABLE)
658 {
659 return;
660 }
661
662 module->flags |= MODULE_FLAG_GC_REACHABLE;
663 module_dependency_t* dependency;
664 LIST_FOR_EACH(dependency, &module->dependencies, listEntry)
665 {
666 module_gc_mark_reachable(dependency->module);
667 }
668}
669
670// This makes sure we collect unreachable modulesList in dependency order
671static void module_gc_sweep_unreachable(module_t* module, list_t* unreachables)
672{
673 if (module == NULL || module->flags & MODULE_FLAG_GC_REACHABLE || module->flags & MODULE_FLAG_GC_PINNED)
674 {
675 return;
676 }
677 module->flags |= MODULE_FLAG_GC_REACHABLE; // Prevent re-entrance
678
679 list_push_back(unreachables, &module->gcEntry);
680
681 module_dependency_t* dependency;
682 LIST_FOR_EACH(dependency, &module->dependencies, listEntry)
683 {
684 module_gc_sweep_unreachable(dependency->module, unreachables);
685 }
686}
687
688static void module_gc_collect(void)
689{
690 module_t* module;
691 LIST_FOR_EACH(module, &modulesList, listEntry)
692 {
693 if (!list_is_empty(&module->deviceHandlers))
694 {
696 }
697 }
698
699 list_t unreachables = LIST_CREATE(unreachables);
700 LIST_FOR_EACH(module, &modulesList, listEntry)
701 {
702 module_gc_sweep_unreachable(module, &unreachables);
703 }
704
705 LIST_FOR_EACH(module, &modulesList, listEntry)
706 {
707 module->flags &= ~MODULE_FLAG_GC_REACHABLE;
708 }
709
710 LIST_FOR_EACH(module, &unreachables, gcEntry)
711 {
712 // Be extra safe and call unload event before freeing any resources
714 }
715
716 while (!list_is_empty(&unreachables))
717 {
718 module = CONTAINER_OF(list_pop_first(&unreachables), module_t, gcEntry);
719 module_free(module);
720 }
721}
722
724{
726 const boot_kernel_t* kernel = &bootInfo->kernel;
727 const Elf64_File* elf = &kernel->elf;
728
729 module_t* kernelModule = module_new(&fakeKernelModuleInfo);
730 if (kernelModule == NULL)
731 {
732 panic(NULL, "Failed to create fake kernel module (%s)", strerror(errno));
733 }
735
736 uint64_t index = 0;
737 while (true)
738 {
739 Elf64_Sym* sym = elf64_get_symbol_by_index(elf, index++);
740 if (sym == NULL)
741 {
742 break;
743 }
744
745 const char* symName = elf64_get_symbol_name(elf, sym);
746 void* symAddr = (void*)sym->st_value;
749 if (symbol_add(symName, symAddr, kernelModule->symbolGroupId, binding, type) == ERR)
750 {
751 panic(NULL, "Failed to load kernel symbol '%s' (%s)", symName, strerror(errno));
752 }
753 }
754
755 LOG_INFO("loaded %llu kernel symbols\n", index);
756}
757
758static bool module_info_supports_device(const module_info_t* info, const char* type)
759{
760 if (info == NULL || type == NULL)
761 {
762 return false;
763 }
764
765 const char* deviceTypePtr = info->deviceTypes;
766 while (*deviceTypePtr != '\0')
767 {
768 char currentDeviceType[MODULE_MAX_DEVICE_STRING] = {0};
769 uint64_t parsed = module_string_copy(deviceTypePtr, currentDeviceType, MODULE_MAX_DEVICE_STRING);
770 if (parsed == 0)
771 {
772 break;
773 }
774 deviceTypePtr += parsed + 1;
775
776 if (strncmp(currentDeviceType, type, MODULE_MAX_DEVICE_STRING) == 0)
777 {
778 return true;
779 }
780 }
781
782 return false;
783}
784
785typedef struct
786{
788 const char* filename;
790 module_t* current; ///< The module whose dependencies are currently being loaded.
793
795{
796 Elf64_Addr minVaddr;
797 Elf64_Addr maxVaddr;
798 elf64_get_loadable_bounds(elf, &minVaddr, &maxVaddr);
799 uint64_t moduleMemSize = maxVaddr - minVaddr;
800
801 // Will be unmapped in module_free
802 module->baseAddr = vmm_alloc(NULL, NULL, moduleMemSize, PML_PRESENT | PML_WRITE | PML_GLOBAL, VMM_ALLOC_OVERWRITE);
803 if (module->baseAddr == NULL)
804 {
805 return ERR;
806 }
807 module->size = moduleMemSize;
808 module->procedure = (module_procedure_t)((uintptr_t)module->baseAddr + (elf->header->e_entry - minVaddr));
809
810 elf64_load_segments(elf, (Elf64_Addr)module->baseAddr, minVaddr);
811
812 uint64_t index = 0;
813 while (true)
814 {
815 Elf64_Sym* sym = elf64_get_symbol_by_index(elf, index++);
816 if (sym == NULL)
817 {
818 break;
819 }
820
821 if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_ABS)
822 {
823 continue;
824 }
825
826 const char* symName = elf64_get_symbol_name(elf, sym);
829 if (!MODULE_SYMBOL_ALLOWED(type, binding, symName))
830 {
831 continue;
832 }
833
834 void* symAddr = (void*)((uintptr_t)module->baseAddr + (sym->st_value - minVaddr));
835 if (symbol_add(symName, symAddr, module->symbolGroupId, binding, type) == ERR)
836 {
837 LOG_ERR("failed to add symbol '%s' to module '%s'\n", symName, module->info.name);
838 return ERR;
839 }
840 }
841
842 module_t* previous = ctx->current;
843 ctx->current = module;
844 if (elf64_relocate(elf, (Elf64_Addr)module->baseAddr, minVaddr, module_resolve_symbol_callback, ctx) == ERR)
845 {
846 return ERR;
847 }
848 ctx->current = previous;
849
850 return 0;
851}
852
853static uint64_t module_load_dependency(module_load_ctx_t* ctx, const char* symbolName)
854{
855 map_key_t cacheKey = map_key_string(symbolName);
856 module_cached_symbol_t* cacheEntry =
858 if (cacheEntry == NULL)
859 {
860 LOG_ERR("no cached module found for symbol '%s'\n", symbolName);
861 return ERR;
862 }
863
865 if (module_file_read(&file, &ctx->dir->path, ctx->process, cacheEntry->modulePath) == ERR)
866 {
867 return ERR;
868 }
869
870 if (module_find_by_name(file.info->name) != NULL)
871 {
873 return 0;
874 }
875
876 module_t* dependency = module_new(file.info);
877 if (dependency == NULL)
878 {
880 return ERR;
881 }
882
883 LOG_INFO("loading dependency '%s' version %s by %s\n", dependency->info.name, dependency->info.version,
884 dependency->info.author);
885 LOG_DEBUG(" description: %s\n licence: %s\n", dependency->info.description, dependency->info.license);
886
887 if (module_load_and_relocate_elf(dependency, &file.elf, ctx) == ERR)
888 {
890 module_free(dependency);
891 return ERR;
892 }
893
894 list_push_back(&ctx->dependencies, &dependency->loadEntry);
896 return 0;
897}
898
899static void* module_resolve_symbol_callback(const char* symbolName, void* private)
900{
901 module_load_ctx_t* ctx = private;
902
903 symbol_info_t symbolInfo;
904 if (symbol_resolve_name(&symbolInfo, symbolName) == ERR)
905 {
906 if (module_load_dependency(ctx, symbolName) == ERR)
907 {
908 return NULL;
909 }
910
911 if (symbol_resolve_name(&symbolInfo, symbolName) == ERR)
912 {
913 LOG_ERR("failed to resolve symbol '%s' after loading dependency\n", symbolName);
914 return NULL;
915 }
916 }
917
918 map_key_t providerKey = map_key_uint64(symbolInfo.groupId);
919 module_t* existingModule = CONTAINER_OF_SAFE(map_get(&providerMap, &providerKey), module_t, providerEntry);
920 if (existingModule != NULL)
921 {
922 return symbolInfo.addr;
923 }
924
925 module_dependency_t* dependency = malloc(sizeof(module_dependency_t));
926 if (dependency == NULL)
927 {
928 return NULL;
929 }
930 list_entry_init(&dependency->listEntry);
931 dependency->module = CONTAINER_OF_SAFE(map_get(&providerMap, &providerKey), module_t, providerEntry);
932 if (dependency->module == NULL)
933 {
934 free(dependency);
935 return NULL;
936 }
937
938 module_dependency_t* existingDependency;
939 LIST_FOR_EACH(existingDependency, &ctx->current->dependencies, listEntry)
940 {
941 if (existingDependency->module == dependency->module)
942 {
943 free(dependency);
944 return symbolInfo.addr;
945 }
946 }
947
948 list_push_back(&ctx->current->dependencies, &dependency->listEntry);
949 return symbolInfo.addr;
950}
951
952static module_t* module_get_or_load(const char* filename, file_t* dir, const char* type)
953{
954 if (filename == NULL || dir == NULL || type == NULL)
955 {
956 errno = EINVAL;
957 return NULL;
958 }
959
960 module_load_ctx_t ctx = {
961 .dir = dir,
962 .filename = filename,
963 .process = sched_process(),
964 .current = NULL,
965 .dependencies = LIST_CREATE(ctx.dependencies),
966 };
967
969 if (module_file_read(&file, &ctx.dir->path, ctx.process, filename) == ERR)
970 {
971 return NULL;
972 }
973
974 if (!module_info_supports_device(file.info, type))
975 {
977 errno = ENODEV;
978 return NULL;
979 }
980
981 module_t* existingModule = module_find_by_name(file.info->name);
982 if (existingModule != NULL)
983 {
985 return existingModule;
986 }
987
988 module_t* module = module_new(file.info);
989 if (module == NULL)
990 {
992 return NULL;
993 }
994
995 list_t loadedDependencies = LIST_CREATE(loadedDependencies);
996
997 LOG_INFO("loading '%s' version %s by %s\n", module->info.name, module->info.version, module->info.author);
998 LOG_DEBUG(" description: %s\n licence: %s\n", module->info.description, module->info.license);
999
1000 uint64_t loadResult = module_load_and_relocate_elf(module, &file.elf, &ctx);
1002 if (loadResult == ERR)
1003 {
1004 goto error;
1005 }
1006
1007 while (!list_is_empty(&ctx.dependencies))
1008 {
1009 // Go in reverse to start at the deepest dependency
1010 module_t* dependency = CONTAINER_OF_SAFE(list_pop_last(&ctx.dependencies), module_t, loadEntry);
1011 if (dependency == NULL)
1012 {
1013 break;
1014 }
1015
1016 if (module_call_load_event(dependency) == ERR)
1017 {
1018 module_free(dependency);
1019 goto error;
1020 }
1021
1022 list_push_back(&loadedDependencies, &dependency->loadEntry);
1023 }
1024
1025 while (!list_is_empty(&loadedDependencies))
1026 {
1027 module_t* dependency = CONTAINER_OF(list_pop_first(&loadedDependencies), module_t, loadEntry);
1028 LOG_DEBUG("finished loading dependency module '%s'\n", dependency->info.name);
1029 }
1030
1031 if (module_call_load_event(module) == ERR)
1032 {
1033 goto error;
1034 }
1035
1036 LOG_DEBUG("finished loading module '%s'\n", module->info.name);
1037
1038 return module;
1039
1040error:
1041 while (!list_is_empty(&loadedDependencies))
1042 {
1043 module_t* dependency = CONTAINER_OF(list_pop_last(&loadedDependencies), module_t, loadEntry);
1044 module_call_unload_event(dependency);
1045 module_free(dependency);
1046 }
1047 while (!list_is_empty(&ctx.dependencies))
1048 {
1049 module_t* dependency = CONTAINER_OF(list_pop_first(&ctx.dependencies), module_t, loadEntry);
1050 module_free(dependency);
1051 }
1052 module_free(module);
1053 return NULL;
1054}
1055
1056uint64_t module_device_attach(const char* type, const char* name, module_load_flags_t flags)
1057{
1058 if (type == NULL || name == NULL)
1059 {
1060 errno = EINVAL;
1061 return ERR;
1062 }
1063
1064 MUTEX_SCOPE(&lock);
1065
1066 if (module_cache_build() == ERR)
1067 {
1068 return ERR;
1069 }
1070
1072 if (cachedDevice == NULL) // No modules support this device type
1073 {
1074 return 0;
1075 }
1076
1078 if (dir == NULL)
1079 {
1080 return ERR;
1081 }
1082 UNREF_DEFER(dir);
1083
1084 module_device_t* device = module_device_get(name);
1085 if (device != NULL)
1086 {
1087 if (strncmp(device->type, type, MODULE_MAX_DEVICE_STRING) != 0)
1088 {
1089 LOG_ERR("device '%s' type mismatch (expected '%s', got '%s')\n", name, device->type, type);
1090 errno = EINVAL;
1091 return ERR;
1092 }
1093
1094 if (!(flags & MODULE_LOAD_ALL) && !list_is_empty(&device->handlers))
1095 {
1096 return 0;
1097 }
1098 }
1099 else
1100 {
1101 device = module_device_new(type, name);
1102 if (device == NULL)
1103 {
1104 return ERR;
1105 }
1106 }
1107
1108 list_t handlers = LIST_CREATE(handlers);
1109
1110 module_cached_device_entry_t* deviceEntry;
1111 LIST_FOR_EACH(deviceEntry, &cachedDevice->entries, listEntry)
1112 {
1113 module_t* module = module_get_or_load(deviceEntry->path, dir, type);
1114 if (module == NULL)
1115 {
1116 LOG_ERR("failed to load module '%s' for device '%s'\n", deviceEntry->path, name);
1117 continue;
1118 }
1119
1120 module_device_handler_t* handler = module_handler_add(module, device);
1121 if (handler == NULL)
1122 {
1123 goto error;
1124 }
1125 list_push_back(&handlers, &handler->loadEntry);
1126
1127 if (!(flags & MODULE_LOAD_ALL))
1128 {
1129 break;
1130 }
1131 }
1132
1133 uint64_t loadedCount = list_length(&handlers);
1134 while (!list_is_empty(&handlers))
1135 {
1137 LOG_DEBUG("added handler with module '%s' and device '%s'\n", handler->module->info.name, name);
1138 }
1139
1140 return loadedCount;
1141error:
1142 while (!list_is_empty(&handlers))
1143 {
1145 module_handler_remove(handler);
1146 }
1147 if (list_is_empty(&device->handlers))
1148 {
1149 module_device_free(device);
1150 }
1152 return ERR;
1153}
1154
1155void module_device_detach(const char* name)
1156{
1157 if (name == NULL)
1158 {
1159 return;
1160 }
1161
1162 MUTEX_SCOPE(&lock);
1163
1164 module_device_t* device = module_device_get(name);
1165 if (device == NULL)
1166 {
1167 return;
1168 }
1169
1170 while (!list_is_empty(&device->handlers))
1171 {
1172 module_device_handler_t* handler =
1174 module_handler_remove(handler);
1175 }
1177
1178 if (list_is_empty(&device->handlers))
1179 {
1180 module_device_free(device);
1181 }
1182}
1183
1184bool module_device_types_contains(const char* deviceTypes, const char* type)
1185{
1186 if (deviceTypes == NULL || type == NULL)
1187 {
1188 return false;
1189 }
1190
1191 size_t idLen = strlen(type);
1192 const char* pos = deviceTypes;
1193
1194 while ((pos = strstr(pos, type)) != NULL)
1195 {
1196 bool isStart = (pos == deviceTypes) || (*(pos - 1) == ';');
1197 bool isEnd = (pos[idLen] == ';') || (pos[idLen] == '\0');
1198
1199 if (isStart && isEnd)
1200 {
1201 return true;
1202 }
1203
1204 pos++;
1205 }
1206
1207 return false;
1208}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define SEEK_SET
Definition SEEK.h:4
#define SEEK_END
Definition SEEK.h:6
#define assert(expression)
Definition assert.h:29
boot_info_t * bootInfo
Definition boot_info.c:14
#define PATHNAME(string)
Helper to create a pathname.
Definition path.h:166
boot_info_t * boot_info_get(void)
Gets the boot info structure.
Definition boot_info.c:16
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:266
#define LOG_ERR(format,...)
Definition log.h:108
#define LOG_INFO(format,...)
Definition log.h:106
#define LOG_DEBUG(format,...)
Definition log.h:100
void * vmm_unmap(space_t *space, void *virtAddr, uint64_t length)
Unmaps virtual memory from a given address space.
Definition vmm.c:334
uint64_t symbol_resolve_name(symbol_info_t *outSymbol, const char *name)
Resolve a symbol by name.
Definition symbol.c:344
uint64_t symbol_group_id_t
Symbol group identifier type.
Definition symbol.h:67
uint64_t symbol_add(const char *name, void *addr, symbol_group_id_t groupId, Elf64_Symbol_Binding binding, Elf64_Symbol_Type type)
Add a symbol to the kernel symbol table.
Definition symbol.c:165
void symbol_remove_group(symbol_group_id_t groupId)
Remove all symbols from the kernel symbol table in the given group.
Definition symbol.c:278
bool module_device_types_contains(const char *deviceTypes, const char *type)
Check if a list of device types contains a specific device type.
Definition module.c:1184
void module_device_detach(const char *name)
Notify the module system of a device being detached.
Definition module.c:1155
module_load_flags_t
Module load flags.
Definition module.h:397
#define MODULE_INFO_SECTION
Definition module.h:160
#define MODULE_DIR
The directory where the kernel will look for modules.
Definition module.h:225
void module_init_fake_kernel_module(void)
Initialize a fake module representing the kernel itself.
Definition module.c:723
uint64_t module_device_attach(const char *type, const char *name, module_load_flags_t flags)
Notify the module system of a device being attached.
Definition module.c:1056
@ MODULE_EVENT_DEVICE_ATTACH
Definition module.h:251
@ MODULE_EVENT_DEVICE_DETACH
Definition module.h:257
@ MODULE_EVENT_LOAD
Definition module.h:239
@ MODULE_EVENT_UNLOAD
Definition module.h:245
@ MODULE_FLAG_LOADED
If set, the module has received the MODULE_EVENT_LOAD event.
Definition module.h:323
@ MODULE_FLAG_GC_REACHABLE
Used by the GC to mark reachable modules.
Definition module.h:324
@ MODULE_FLAG_GC_PINNED
If set, the module will never be collected by the GC, used for the fake kernel module.
Definition module.h:325
@ MODULE_LOAD_ALL
If set, will load all modules matching the device type.
Definition module.h:399
@ MODULE_MAX_LICENSE
Definition module.h:132
@ MODULE_MAX_NAME
Definition module.h:128
@ MODULE_MAX_VERSION
Definition module.h:131
@ MODULE_MAX_DEVICE_STRING
Definition module.h:135
@ MODULE_MAX_AUTHOR
Definition module.h:129
@ MODULE_MAX_INFO
Definition module.h:134
@ MODULE_MAX_DESCRIPTION
Definition module.h:130
@ MODULE_MIN_INFO
Definition module.h:133
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:620
#define MUTEX_CREATE(name)
Create a mutex initializer.
Definition mutex.h:33
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
void map_clear(map_t *map)
Clear all entries from the map.
Definition map.c:401
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:71
static map_key_t map_key_uint64(uint64_t uint64)
Create a map key from a uint64_t.
Definition map.h:128
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
#define MAP_ENTRY_PTR_IS_VALID(entryPtr)
Check if a map entry pointer is valid (not NULL or tombstone).
Definition map.h:80
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
static map_key_t map_key_string(const char *str)
Create a map key from a string.
Definition map.h:143
#define MAP_CREATE()
Create a map initializer.
Definition map.h:160
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
uint64_t vfs_seek(file_t *file, int64_t offset, seek_origin_t origin)
Seek in a file.
Definition vfs.c:286
uint64_t vfs_getdents(file_t *file, dirent_t *buffer, uint64_t count)
Get directory entries from a directory file.
Definition vfs.c:515
file_t * vfs_open(const pathname_t *pathname, process_t *process)
Open a file.
Definition vfs.c:94
uint64_t vfs_read(file_t *file, void *buffer, uint64_t count)
Read from a file.
Definition vfs.c:200
file_t * vfs_openat(const path_t *from, const pathname_t *pathname, process_t *process)
Open a file relative to another path.
Definition vfs.c:158
#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 ENODEV
No such device.
Definition errno.h:127
#define EILSEQ
Illegal byte sequence.
Definition errno.h:447
#define ELF64_ST_TYPE(i)
Extract the type from st_info.
Definition elf.h:581
Elf64_Symbol_Binding
Symbol binding values stored in st_info.
Definition elf.h:565
#define ELF64_ST_BIND(i)
Extract the binding from st_info.
Definition elf.h:558
uint64_t elf64_relocate(const Elf64_File *elf, Elf64_Addr base, Elf64_Off offset, void *(*resolve_symbol)(const char *name, void *private), void *private)
Perform relocations on an ELF file loaded into memory.
void elf64_load_segments(const Elf64_File *elf, Elf64_Addr base, Elf64_Off offset)
Load all loadable segments of an ELF file into memory.
uint64_t elf64_validate(Elf64_File *elf, void *data, uint64_t size)
Validate a files content and initalize a ELF64_File structure using it.
Elf64_Sym * elf64_get_symbol_by_index(const Elf64_File *elf, Elf64_Xword symbolIndex)
Get a symbol by its index from the symbol table.
const char * elf64_get_symbol_name(const Elf64_File *elf, const Elf64_Sym *symbol)
Get the name of a symbol.
void elf64_get_loadable_bounds(const Elf64_File *elf, Elf64_Addr *minAddr, Elf64_Addr *maxAddr)
Get the loadable virtual memory bounds of an ELF file.
uint64_t Elf64_Addr
ELF64 Unsigned program address.
Definition elf.h:30
Elf64_Shdr * elf64_get_section_by_name(const Elf64_File *elf, const char *name)
Get a section by its name.
Elf64_Symbol_Type
Symbol type values stored in st_info.
Definition elf.h:588
@ SHN_UNDEF
Undefined section.
Definition elf.h:446
@ SHN_ABS
Specifies absolute values for the corresponding reference.
Definition elf.h:452
@ INODE_FILE
Is a file.
Definition io.h:314
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:63
static list_entry_t * list_first(list_t *list)
Gets the first entry in the list without removing it.
Definition list.h:417
static list_entry_t * list_pop_first(list_t *list)
Pops the first entry from the list.
Definition list.h:375
static uint64_t list_length(list_t *list)
Gets the length of the list.
Definition list.h:246
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:343
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:174
static list_entry_t * list_pop_last(list_t *list)
Pops the last entry from the list.
Definition list.h:396
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:315
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:227
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:182
static void list_init(list_t *list)
Initializes a list.
Definition list.h:196
#define PAGE_SIZE
The size of a memory page in bytes.
Definition proc.h:106
#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.
static fb_info_t info
Definition gop.c:51
static dentry_t * file
Definition log_file.c:22
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
errno_t memcpy_s(void *_RESTRICT s1, rsize_t s1max, const void *_RESTRICT s2, rsize_t n)
Definition memcpy_s.c:9
static module_cached_device_t * module_cache_lookup_device_type(const char *type)
Definition module.c:540
static module_t * module_new(module_info_t *info)
Definition module.c:55
static void module_gc_collect(void)
Definition module.c:688
static uint64_t module_call_load_event(module_t *module)
Definition module.c:129
static map_t symbolCache
Key = symbol name, value = module_cached_symbol_t*.
Definition module.c:43
static module_device_handler_t * module_handler_add(module_t *module, module_device_t *device)
Definition module.c:205
static uint64_t module_file_read(module_file_t *outFile, const path_t *dirPath, process_t *process, const char *filename)
Definition module.c:371
#define MODULE_SYMBOL_ALLOWED(type, binding, name)
Definition module.c:51
static void module_gc_sweep_unreachable(module_t *module, list_t *unreachables)
Definition module.c:671
static uint64_t module_load_and_relocate_elf(module_t *module, Elf64_File *elf, module_load_ctx_t *ctx)
Definition module.c:794
static uint64_t module_cache_device_types_add(module_file_t *file, const char *path)
Definition module.c:487
static module_t * module_find_by_name(const char *name)
Definition module.c:157
static uint64_t module_string_copy(const char *str, char *out, size_t outSize)
Copy a string up to either a null-terminator or a semicolon into the output buffer.
Definition module.c:252
static map_t modulesMap
Key = module name, value = module_t*.
Definition module.c:37
static void module_call_unload_event(module_t *module)
Definition module.c:144
static map_t deviceCache
Key = device type, value = module_cached_device_t*.
Definition module.c:44
static list_t modulesList
Definition module.c:36
static bool module_info_supports_device(const module_info_t *info, const char *type)
Definition module.c:758
static void module_cache_clear(void)
Definition module.c:546
static uint64_t module_load_dependency(module_load_ctx_t *ctx, const char *symbolName)
Definition module.c:853
static map_t deviceMap
Key = device name, value = module_device_t*.
Definition module.c:41
static bool cacheValid
Definition module.c:45
static module_info_t * module_info_parse(const char *moduleInfo)
Definition module.c:268
static module_cached_symbol_t * module_cache_lookup_symbol(const char *name)
Definition module.c:534
static void module_handler_remove(module_device_handler_t *handler)
Definition module.c:235
static void * module_resolve_symbol_callback(const char *name, void *private)
Definition module.c:899
static uint64_t module_cache_build(void)
Definition module.c:582
static module_info_t fakeKernelModuleInfo
Definition module.c:26
static uint64_t module_cache_symbols_add(module_file_t *file, const char *path)
Definition module.c:435
static void module_free(module_t *module)
Definition module.c:109
static module_device_t * module_device_new(const char *type, const char *name)
Definition module.c:169
static map_t providerMap
Key = symbol_group_id_t, value = module_t*. Used to find which module provides which symbols.
Definition module.c:38
static void module_gc_mark_reachable(module_t *module)
Definition module.c:655
static module_t * module_find_provider(symbol_group_id_t groupId)
Definition module.c:163
static module_device_t * module_device_get(const char *name)
Definition module.c:199
static void module_device_free(module_device_t *device)
Definition module.c:191
static module_t * module_get_or_load(const char *filename, file_t *dir, const char *type)
Definition module.c:952
static mutex_t lock
Definition module.c:47
static void module_file_deinit(module_file_t *file)
Definition module.c:429
static const path_flag_t flags[]
Definition path.c:42
__INTPTR_TYPE__ intptr_t
Definition stdint.h:42
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strerror(int errnum)
Definition strerror.c:6
char * strdup(const char *src)
Definition strdup.c:5
_PUBLIC char * strstr(const char *s1, const char *s2)
Definition strstr.c:3
_PUBLIC int strncmp(const char *s1, const char *s2, size_t n)
Definition strncmp.c:3
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
_PUBLIC int strcmp(const char *s1, const char *s2)
Definition strcmp.c:3
errno_t strncpy_s(char *_RESTRICT s1, rsize_t s1max, const char *_RESTRICT s2, rsize_t n)
Definition strncpy_s.c:9
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
ELF File Helper structure.
Definition elf.h:781
Elf64_Ehdr * header
The data in the file, pointed to the start of the ELF header.
Definition elf.h:782
ELF64 Section Header.
Definition elf.h:468
Elf64_Xword sh_size
Section size in bytes.
Definition elf.h:474
Elf64_Off sh_offset
Section's file offset in bytes.
Definition elf.h:473
ELF64 Symbol Table Entry.
Definition elf.h:543
Elf64_Half st_shndx
Definition elf.h:547
Elf64_Addr st_value
Definition elf.h:548
unsigned char st_info
Definition elf.h:545
boot_kernel_t kernel
Definition boot_info.h:105
Elf64_File elf
Definition boot_info.h:89
char name[MAX_NAME]
Constant after creation.
Definition dentry.h:87
Directory entry struct.
Definition io.h:393
char name[MAX_NAME]
Definition fb.h:44
File structure.
Definition file.h:39
path_t path
Definition file.h:44
A doubly linked list.
Definition list.h:49
Map entry structure.
Definition map.h:68
Map key stucture.
Definition map.h:56
Hash map structure.
Definition map.h:89
uint64_t capacity
Definition map.h:91
map_entry_t ** entries
Definition map.h:90
Module device cache entry structure.
Definition module.h:377
list_entry_t listEntry
Definition module.h:378
char path[MAX_PATH]
Path to the module supporting the device.
Definition module.h:379
Module device cache entry structure.
Definition module.h:387
list_t entries
List of module_cached_device_entry_t.
Definition module.h:389
map_entry_t mapEntry
Definition module.h:388
Module symbol cache entry structure.
Definition module.h:367
map_entry_t mapEntry
Definition module.h:368
char * modulePath
Path to the module defining the symbol.
Definition module.h:369
list_entry_t listEntry
Definition module.h:337
list_entry_t moduleEntry
Definition module.h:310
list_entry_t deviceEntry
Definition module.h:309
list_entry_t loadEntry
Definition module.h:311
module_t *module_device_t * device
Definition module.h:313
map_entry_t mapEntry
Definition module.h:297
char name[MODULE_MAX_DEVICE_STRING]
Definition module.h:298
char type[MODULE_MAX_DEVICE_STRING]
Definition module.h:299
list_t handlers
List of module_device_handler_t representing modules handling this device.
Definition module.h:300
module_event_type_t type
Definition module.h:268
Elf64_File elf
Definition module.c:367
module_info_t * info
Definition module.c:368
char * author
Definition module.h:147
char * version
Definition module.h:149
char * description
Definition module.h:148
char * license
Definition module.h:150
char * name
Definition module.h:146
module_t * current
The module whose dependencies are currently being loaded.
Definition module.c:790
file_t * dir
Definition module.c:787
const char * filename
Definition module.c:788
list_t dependencies
Definition module.c:791
process_t * process
Definition module.c:789
list_t deviceHandlers
List of module_device_handler_t representing devices this module handles.
Definition module.h:358
map_entry_t mapEntry
Entry for the global module map.
Definition module.h:348
uint64_t size
The size of the modules loaded image in memory.
Definition module.h:354
list_t dependencies
List of module_dependency_t representing modules this module depends on.
Definition module.h:357
list_entry_t gcEntry
Entry used for garbage collection.
Definition module.h:350
list_entry_t listEntry
Entry for the global module list.
Definition module.h:347
module_info_t info
Definition module.h:359
void * baseAddr
The address where the modules image is loaded in memory.
Definition module.h:353
symbol_group_id_t symbolGroupId
The symbol group ID for the module's symbols.
Definition module.h:356
module_procedure_t procedure
The module's procedure function and entry point.
Definition module.h:355
module_flags_t flags
Definition module.h:352
map_entry_t providerEntry
Entry for the module provider map.
Definition module.h:349
list_entry_t loadEntry
Entry used while loading modules.
Definition module.h:351
Mutex structure.
Definition mutex.h:41
Path structure.
Definition path.h:125
Process structure.
Definition process.h:205
Symbol information structure.
Definition symbol.h:119
void * addr
Definition symbol.h:121
symbol_group_id_t groupId
Definition symbol.h:122