PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
module.h
Go to the documentation of this file.
1#pragma once
2
4#include <kernel/fs/file.h>
5#include <kernel/fs/path.h>
7#include <kernel/utils/map.h>
8#include <kernel/utils/ref.h>
9#include <kernel/version.h>
11
12#include <stdint.h>
13#include <sys/io.h>
14#include <sys/list.h>
15
16typedef struct module module_t;
17
18/**
19 * @brief Kernel module management.
20 * @defgroup kernel_module Module Management
21 * @ingroup kernel
22 *
23 * A module is a dynamically loadable piece of code. This means that for example, instead of having to store every
24 * possible driver into the kernel all the time we can detect what hardware is present and only load the necessary
25 * modules for that hardware.
26 *
27 * Its also very useful just for organization purposes as it lets us separate out our concerns, instead of just packing
28 * everything into the kernel.
29 *
30 * For the record, this is a rather complex system, and in most cases you wont need to understand every facet of it to
31 * use it effectively.
32 *
33 * ## Writing Modules
34 *
35 * Modules are in effect just ELF binaries which export a `._module_info` which contains metadata about the module.
36Check the `MODULE_INFO` macro or more details
37 *
38 * As expected, each module has an entry point defined by the module linker script as `_module_procedure()`, which can
39be thought of as the "main" function of the module but it also does way more than just that, whenever any event occurs
40that the module should be aware of this procedure will be called to notify the module of the event.
41 *
42 * Note that since all global symbols will be exposed to other modules, its a good idea to prefix all global symbols
43 * with some unique prefix to avoid naming collisions with other modules, for example `mymodule_*`. The exception to
44 * this is symbols starting with '_mod*' which will not be exported or visible to other modules.
45 *
46 * ## Loading Modules
47 *
48 * Modules can not be explicitly loaded, instead each module declares what device types it supports in its
49`.module_info` section, when the module loader is then told that a device with a specified type is present it will
50search for a module supporting that device type and load it. Check the `MODULE_INFO` macro for more details.
51 *
52 * ## Device Types and Names
53 *
54 * From the perspective of the module system, devices are identified via a type string and a name string. The type
55string, as the name suggests, specifies the type of the device, and there can be multiple devices of the same type.
56While the name string must be entirely unique to each instance of a device.
57 *
58 * As an example, for ACPI, the type string would be the ACPI Hardware ID (HID) of the device, for example "PNP0303" for
59a IBM Enhanced PS/2 Keyboard, while the name string would be the full ACPI path to the device in the AML namespace, for
60example "\_SB_.PCI0.SF8_.KBD_". But its important to note that the module system does not care or know anything about
61the semantics of these strings, it just treats them as opaque strings to identify devices.
62 *
63 * Since both the type and the name strings are provided to the module during a `MODULE_EVENT_DEVICE_ATTACH` event, the
64module is intended to use the name to retrieve more information about the device from the relevant subsystem (for
65example ACPI) if needed.
66 *
67 * ## Dependencies
68 *
69 * Modules can depend on other modules. For example, module1 could define the function `module_1_func()` and then
70 * module2 could call this function. The only way for that to work is for the kernel to load module1 before or during
71 * the loading of module2 so that the symbol `module_1_func()` can be resolved when module2 is being relocated.
72 *
73 * There are many, many ways of handling dependencies. In PatchworkOS it works like this.
74 *
75 * First, we load some module file, lets say "/kernel/modules/<OS_VERSION>/module2". This module wants to call
76`module_1_func()`
77 * which is defined in "/kernel/modules/<OS_VERSION>/module1". When resolving the symbols for module2 we will fail to
78resolve
79 * `module_1_func()`.
80 *
81 * The failure to resolve a symbol will cause the kernel to search for a module that provides the symbol, it checks all
82the symbols in each module eventually finding that module1
83 * defines `module_1_func()`. The kernel will then load module1 and retry the symbol resolution for module2, this time
84 * succeeding. This repeats until all symbols are resolved or no more modules are found to load.
85 *
86 * This means that both module1 and module2 need to do exactly nothing, they dont even need to declare that they depend
87 * on each other, the kernel will figure it all out automatically.
88 *
89 * Note that if a module was loaded as a dependency and all modules depending on it are unloaded, the
90 * dependency module will also be unloaded, unless it was later explicitly loaded, and if a module was loaded explicitly
91 * but later a module depending on it is loaded then it will also wait to be unloaded until all modules depending on it
92 * are unloaded.
93 *
94 * @todo Currently module symbols and device types are cached in memory after the first load, for now this is fine. But
95in the future this cache could become very large so we might need a Linux-style cache file on disk or atleast a way to
96invalidate the cache.
97 *
98 * ## Circular Dependencies
99 *
100 * When loading a module with dependencies, circular dependencies may occur. For example, module A depends on module B
101 * which in turn depends on module A.
102 *
103 * This is allowed, which means that, for the sake of safety, all modules should be written in such a way that all their
104 * global functions can be safely called even if the module is not fully initialized yet. This should rarely make any
105difference whatsoever.
106 *
107 * See "Unloading Modules" below for more details on how circular dependencies are handled during unloading.
108 *
109 * ## Unloading Modules
110 *
111 * Modules will be unloaded by the kernel when all the devices they handle are detached and no other loaded module
112depends on them.
113 *
114 * To solve both the issue of dependency tracking and circular dependency resolution, we implement a garbage collector
115 * which, using the dependency map, traverses all reachable modules starting from the modules that are currently
116handling devices. Any
117 * module that is not reachable is considered unused and will be unloaded.
118 *
119 * @{
120 */
121
122/**
123 * @brief Sizes for module strings.
124 * @typedef module_string_size_t
125 */
137
138/**
139 * @brief Module information structure.
140 * @typedef module_info_t
141 *
142 * Used to store module information from the `.module_info` section.
143 */
144typedef struct module_info
145{
146 char* name;
147 char* author;
149 char* version;
150 char* license;
152 char* deviceTypes; ///< Null-terminated semicolon-separated list of device type strings.
153 uint64_t dataSize; ///< Size of the `data` field.
154 char data[]; ///< All strings are stored here contiguously.
156
157/**
158 * Section for module information.
159 */
160#define MODULE_INFO_SECTION "._module_info"
161
162/**
163 * @brief Macro to define module information.
164 *
165 * To define a modules information we use a separate section in the module's binary called `.module_info` this section
166 * stores a concatenated string of the module's name, author, description, version, licence, the OS version and the
167 * modules device types, each separated by a `;` and ending with a null-terminator.
168 *
169 * ## Device Types
170 *
171 * The device types is a semicolon-separated list of generic device type strings that the module supports.
172 *
173 * These strings can be anything, all the kernel does is check for matches when loading modules to handle a specific
174device type and check for the special types listed below. For example, these types may be ACPI HIDs, PCI IDs, USB IDs or
175completely custom strings defined by the module itself.
176 *
177 * Special Device Types:
178 * - `BOOT_ALWAYS`: The module will be loaded after the kernel has initialized itself.
179 * - `BOOT_RSDP`: The module will be loaded if the RSDP is provided by the bootloader.
180 * - `BOOT_GOP`: The module will be loaded if GOP is provided by the bootloader.
181 *
182 * ## Data Format
183 *
184 * As an example of the data format in the `.module_info` section,
185 * ```c
186 * MODULE_INFO("My Module", "John Doe", "A sample module", "1.0.0", "MIT", "BOOT_ALWAYS;ACPI0001");
187 * ```
188 * becomes
189 * ```c
190 * "My Module;John Doe;A sample module;1.0.0;MIT;ac516767;BOOT_ALWAYS;ACPI0001\0"
191 * ```
192 *
193 * @param _name The name of the module.
194 * @param _author The author of the module.
195 * @param _description A short description of the module.
196 * @param _version The version of the module.
197 * @param _licence The licence of the module.
198 * @param _deviceTypes A semicolon-separated list of device type strings that the module supports.
199 */
200#define MODULE_INFO(_name, _author, _description, _version, _licence, _deviceTypes) \
201 const char _moduleInfo[] __attribute__((section(MODULE_INFO_SECTION), used)) = \
202 _name ";" _author ";" _description ";" _version ";" _licence ";" OS_VERSION ";" _deviceTypes "\0"
203
204/**
205 * @brief Reserved prefix for module global symbols.
206 *
207 * Any symbol with this prefix will not be loaded or exported.
208 */
209#define MODULE_RESERVED_PREFIX "_mod"
210
211/**
212 * @brief Length of `MODULE_RESERVED_PREFIX`.
213 * @typedef module_reserved_prefix_length_t
214 */
219
220/**
221 * @brief The directory where the kernel will look for modules.
222 *
223 * Note how the OS version is part of the path.
224 */
225#define MODULE_DIR "/kernel/modules/" OS_VERSION "/:directory"
226
227/**
228 * @brief Module event types.
229 * @typedef module_event_type_t
230 */
231typedef enum module_event_type
232{
234 /**
235 * Received when the module is loaded.
236 *
237 * If the module returns `ERR`, the module load will fail.
238 */
240 /**
241 * Received when the module is unloaded.
242 *
243 * Return value is ignored.
244 */
246 /**
247 * This event is sent when a device is attached that the module specified it supports.
248 *
249 * A return value of `ERR` can be used to specify that the module is unable to handle the device.
250 */
252 /**
253 * This event is sent when a device is detached that the module specified it supports.
254 *
255 * Return value is ignored.
256 */
259
260/**
261 * @brief Module event structure.
262 * @typedef module_event_t
263 *
264 * Will be sent to modules procedure as events occur.
265 */
266typedef struct module_event
267{
269 union {
270 struct
271 {
272 char* type;
273 char* name;
274 } deviceAttach;
275 struct
276 {
277 char* type;
278 char* name;
279 } deviceDetach;
280 };
282
283/**
284 * @brief Module procedure and entry point.
285 * @typedef module_procedure_t
286 */
288
289/**
290 * @brief Module device structure.
291 * @typedef module_device_t
292 *
293 * Represents a device known to the module system to be currently attached.
294 */
295typedef struct module_device
296{
300 list_t handlers; ///< List of `module_device_handler_t` representing modules handling this device.
302
303/**
304 * @brief Module device handler structure.
305 * @typedef module_device_handler_t
306 */
315
316/**
317 * @brief Module flags.
318 * @typedef module_flags_t
319 */
320typedef enum module_flags
321{
323 MODULE_FLAG_LOADED = 1 << 0, ///< If set, the module has received the `MODULE_EVENT_LOAD` event.
324 MODULE_FLAG_GC_REACHABLE = 1 << 1, ///< Used by the GC to mark reachable modules.
326 1 << 2, ///< If set, the module will never be collected by the GC, used for the fake kernel module.
328
329/**
330 * @brief Module dependency structure.
331 * @typedef module_dependency_t
332 *
333 * We avoid using a map for there as the number of direct dependencies on average should be quite low.
334 */
335typedef struct
336{
338 module_t* module;
340
341/**
342 * @brief Module structure.
343 * @typedef module_t
344 */
345typedef struct module
346{
347 list_entry_t listEntry; ///< Entry for the global module list.
348 map_entry_t mapEntry; ///< Entry for the global module map.
349 map_entry_t providerEntry; ///< Entry for the module provider map.
350 list_entry_t gcEntry; ///< Entry used for garbage collection.
351 list_entry_t loadEntry; ///< Entry used while loading modules.
353 void* baseAddr; ///< The address where the modules image is loaded in memory.
354 uint64_t size; ///< The size of the modules loaded image in memory.
355 module_procedure_t procedure; ///< The module's procedure function and entry point.
356 symbol_group_id_t symbolGroupId; ///< The symbol group ID for the module's symbols.
357 list_t dependencies; ///< List of `module_dependency_t` representing modules this module depends on.
358 list_t deviceHandlers; ///< List of `module_device_handler_t` representing devices this module handles.
360} module_t;
361
362/**
363 * @brief Module symbol cache entry structure.
364 * @struct module_cached_symbol_t
365 */
366typedef struct
367{
369 char* modulePath; ///< Path to the module defining the symbol.
371
372/**
373 * @brief Module device cache entry structure.
374 * @struct module_cached_device_entry_t
375 */
376typedef struct
377{
379 char path[MAX_PATH]; ///< Path to the module supporting the device.
381
382/**
383 * @brief Module device cache entry structure.
384 * @struct module_cached_device_t
385 */
386typedef struct
387{
389 list_t entries; ///< List of `module_cached_device_entry_t`.
391
392/**
393 * @brief Module load flags.
394 * @typedef module_load_flags_t
395 */
396typedef enum
397{
398 MODULE_LOAD_ONE = 0 << 0, ///< If set, will load only the first module matching the device type.
399 MODULE_LOAD_ALL = 1 << 0, ///< If set, will load all modules matching the device type.
401
402/**
403 * @brief Initialize a fake module representing the kernel itself.
404 *
405 * Will panic on failure.
406 *
407 * Used for symbol grouping.
408 */
410
411/**
412 * @brief Notify the module system of a device being attached.
413 *
414 * Will automatically load any dependencies required by the module.
415 *
416 * If a module fails to load, we do not consider it a fatal error, instead we log the error and continue loading other
417 * modules.
418 *
419 * @param type The device type string.
420 * @param name The unique device name string.
421 * @param flags Load flags, see `module_load_flags_t`.
422 * @return On success, the amount of modules loaded. On failure, `ERR` and `errno` is set.
423 */
424uint64_t module_device_attach(const char* type, const char* name, module_load_flags_t flags);
425
426/**
427 * @brief Notify the module system of a device being detached.
428 *
429 * If a module to unload is not currently considered a dependency but other modules depend on it, it will be demoted to
430 * a dependency and not actually unloaded until no modules depend on it anymore.
431 *
432 * @param name The unique device name string, or `NULL` for no-op.
433 */
434void module_device_detach(const char* name);
435
436/**
437 * @brief Check if a list of device types contains a specific device type.
438 *
439 * Useful as a helper when handling `MODULE_EVENT_DEVICE_ATTACH` events.
440 *
441 * @param deviceTypes The semicolon-separated list of device types.
442 * @param type The device type string.
443 * @return `true` if the device type is contained in the list, `false` otherwise.
444 */
445bool module_device_types_contains(const char* deviceTypes, const char* type);
446
447/** @} */
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
static fd_t data
Definition dwm.c:21
uint64_t symbol_group_id_t
Symbol group identifier type.
Definition symbol.h:67
module_event_type_t
Module event types.
Definition module.h:232
module_flags_t
Module flags.
Definition module.h:321
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
uint64_t(* module_procedure_t)(const module_event_t *event)
Module procedure and entry point.
Definition module.h:287
module_string_size_t
Sizes for module strings.
Definition module.h:127
void module_init_fake_kernel_module()
Initialize a fake module representing the kernel itself.
Definition module.c:723
module_reserved_prefix_length_t
Length of MODULE_RESERVED_PREFIX.
Definition module.h:216
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_NONE
Definition module.h:233
@ 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_NONE
Definition module.h:322
@ 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_ONE
If set, will load only the first module matching the device type.
Definition module.h:398
@ 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
@ MODULE_RESERVED_PREFIX_LENGTH
Definition module.h:217
static const path_flag_t flags[]
Definition path.c:42
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
A entry in a doubly linked list.
Definition list.h:36
A doubly linked list.
Definition list.h:49
Map entry structure.
Definition map.h:68
Module device cache entry structure.
Definition module.h:377
list_entry_t listEntry
Definition module.h:378
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
list_t handlers
List of module_device_handler_t representing modules handling this device.
Definition module.h:300
char * type
Definition module.h:272
module_event_type_t type
Definition module.h:268
char * name
Definition module.h:273
uint64_t dataSize
Size of the data field.
Definition module.h:153
char * author
Definition module.h:147
char * version
Definition module.h:149
char * deviceTypes
Null-terminated semicolon-separated list of device type strings.
Definition module.h:152
char * osVersion
Definition module.h:151
char * description
Definition module.h:148
char * license
Definition module.h:150
char * name
Definition module.h:146
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