diff --git a/README.md b/README.md index 2bad5ad..977a249 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Once a task is completed, it should be checked off. - [x] Create a physical memory allocator and mapper. The kernel should live in the upper last gigabyte of virtual memory. It should support different zones (e.g.: `SUB_16M`, `DEFAULT`, ...) These zones describe the region of memory that memory should be allocated in. If it is not possible to allocate in that region (because it is full, or has 0 capacity to begin with), it should fallback to another zone. - [x] Create a paging subsystem. It should allow drivers to allocate and deallocate pages at will. - [x] Create a memory allocator. This should provide the kernel with `malloc` and `free`. Internally, it should use the paging subsystem to ensure that the address it returns have actual RAM paged to them. -- [ ] Create an initial driver architecture, allowing different drivers included in the kernel to test whether they should load or not. +- [x] Create an initial driver architecture, allowing different drivers included in the kernel to test whether they should load or not. - [ ] Create a VGA driver. On startup, some memory statistics should be displayed, as well as boot progress. - [ ] Create subsystem for loading new processes in Ring 3. - [ ] Update the build script to generate a ramdisk containing any applications to run. This initial ramdisk is in CPIO format. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afb2f3c..c9e436f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(kernel paging.c kmalloc.c string.c + driver.c interrupts.S kernel.c ) diff --git a/src/driver.c b/src/driver.c new file mode 100644 index 0000000..4249322 --- /dev/null +++ b/src/driver.c @@ -0,0 +1,72 @@ +/** + * @file driver.c + * @brief Driver framework implementation. + * + * Iterates over all driver descriptors placed in the .drivers linker section + * by the REGISTER_DRIVER macro. Each driver is probed and, if the probe + * succeeds, initialized. + */ + +#include "driver.h" +#include "port_io.h" +#include + +/* Debug print helpers defined in kernel.c */ +extern void offset_print(const char *str); +extern void print_hex(uint32_t val); + +/** + * Linker-provided symbols marking the start and end of the .drivers section. + * Each entry is a pointer to a driver_t. + */ +extern const driver_t *__drivers_start[]; +extern const driver_t *__drivers_end[]; + +void init_drivers(void) { + const driver_t **drv; + int loaded = 0; + int skipped = 0; + int failed = 0; + + offset_print(" DRIVERS: scanning registered drivers...\n"); + + for (drv = __drivers_start; drv < __drivers_end; drv++) { + const driver_t *d = *drv; + if (!d || !d->name) { + continue; + } + + offset_print(" DRIVERS: probing "); + offset_print(d->name); + offset_print("... "); + + /* Run probe function if provided */ + if (d->probe) { + driver_probe_result_t result = d->probe(); + if (result == DRIVER_PROBE_NOT_FOUND) { + offset_print("not found\n"); + skipped++; + continue; + } else if (result == DRIVER_PROBE_ERROR) { + offset_print("probe error\n"); + failed++; + continue; + } + } + + /* Run init function */ + if (d->init) { + int ret = d->init(); + if (ret != 0) { + offset_print("init failed\n"); + failed++; + continue; + } + } + + offset_print("loaded\n"); + loaded++; + } + + offset_print(" DRIVERS: done\n"); +} diff --git a/src/driver.h b/src/driver.h new file mode 100644 index 0000000..6671abc --- /dev/null +++ b/src/driver.h @@ -0,0 +1,56 @@ +/** + * @file driver.h + * @brief Kernel driver architecture. + * + * Provides a simple framework for registering and initializing kernel drivers. + * Each driver provides a probe function that returns whether it should load, + * and an init function that performs the actual initialization. + * + * Drivers are registered at compile time using the REGISTER_DRIVER macro, + * which places driver descriptors in a special linker section. The kernel + * iterates over all registered drivers during boot. + */ + +#ifndef DRIVER_H +#define DRIVER_H + +#include + +/** Driver probe result codes. */ +typedef enum { + DRIVER_PROBE_OK = 0, /**< Driver should be loaded. */ + DRIVER_PROBE_NOT_FOUND = 1, /**< Hardware not found, skip this driver. */ + DRIVER_PROBE_ERROR = 2 /**< Error during probing. */ +} driver_probe_result_t; + +/** + * Driver descriptor structure. + * + * Each driver provides a name, a probe function (to test if hardware is + * present), and an init function (to set up the driver). + */ +typedef struct driver { + const char *name; /**< Human-readable driver name. */ + driver_probe_result_t (*probe)(void); /**< Probe function. Returns DRIVER_PROBE_OK if driver should load. */ + int (*init)(void); /**< Init function. Returns 0 on success, non-zero on failure. */ +} driver_t; + +/** + * Register a driver. + * + * Places the driver descriptor in the .drivers linker section so it + * is automatically discovered during boot. + */ +#define REGISTER_DRIVER(drv) \ + static const driver_t * __attribute__((used, section(".drivers"))) \ + _driver_##drv = &(drv) + +/** + * Initialize all registered drivers. + * + * Iterates over the .drivers section, probes each driver, and initializes + * those that respond positively to probing. + */ +void init_drivers(void); + +#endif /* DRIVER_H */ diff --git a/src/kernel.c b/src/kernel.c index 4f5f07e..477397e 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -8,6 +8,7 @@ #include "pmm.h" #include "paging.h" #include "kmalloc.h" +#include "driver.h" void offset_print(const char *str) { @@ -67,6 +68,9 @@ void kernel_main(uint32_t magic, uint32_t addr) { init_kmalloc(); offset_print("Memory allocator initialized\n"); + init_drivers(); + offset_print("Drivers initialized\n"); + /* Test kmalloc/kfree */ uint32_t *test_alloc = (uint32_t *)kmalloc(64); if (test_alloc) { diff --git a/src/linker.ld b/src/linker.ld index 8180131..b30291e 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -15,6 +15,14 @@ SECTIONS .rodata BLOCK(4K) : ALIGN(4K) { *(.rodata) + *(.rodata.*) + } + + .drivers BLOCK(4K) : ALIGN(4K) + { + __drivers_start = .; + KEEP(*(.drivers)) + __drivers_end = .; } .data BLOCK(4K) : ALIGN(4K)