# Driver API API for developing hardware drivers in ModuOS. ## SQRM (SQRELFM) Third‑Party Driver SDK (Loadable Kernel Modules) ModuOS supports third‑party loadable kernel modules called **SQRM** modules. These are ELF64 `ET_DYN` shared-object style binaries (file extension `.sqrm`) that are loaded by the kernel module loader at boot. ### Where modules live Modules are searched under: - `/ModuOS/System64/md/` (on the selected boot filesystem) On the ISO this corresponds to: - `targets/AMD64/iso/ModuOS/System64/md/` ### Required symbols / entry points A valid module must export: 1) A module descriptor symbol named `sqrm_module_desc` ```c #include "sdk/sqrm_sdk.h" // or "moduos/kernel/sqrm.h" in-tree // ABI v1 descriptor (no dependencies) SQRM_DEFINE_MODULE(SQRM_TYPE_USB, "hello"); // ABI v2 descriptor (dependencies + class/subclass) static const char * const deps[] = { "uhci" }; SQRM_DEFINE_MODULE_V2(SQRM_TYPE_USB, "usb", 1, 0, 1, deps); ``` 2) An entry point: ```c int sqrm_module_init(const sqrm_kernel_api_t *api); ``` The kernel passes a pointer to a **kernel API table** (`sqrm_kernel_api_t`) containing function pointers you can call (logging, driver registration, etc.). Always check ABI compatibility: ```c if (!api || api->abi_version != SQRM_ABI_VERSION) return -1; ``` ### Module types Common module types: - `SQRM_TYPE_FS` – filesystem drivers (example: `modules/ext2_sqrm.c`) - `SQRM_TYPE_AUDIO` – audio drivers (example: `modules/ac97_audio_sqrm.c`) - `SQRM_TYPE_USB` – USB drivers (core, controllers, classes) - `SQRM_TYPE_GPU` – framebuffer GPU/display drivers (examples: QXL, VMSVGA, MD VGA Compatible Display Driver) - `SQRM_TYPE_NET` – network/NIC drivers (skeleton template: `sdk/template_net_skeleton/`) - `SQRM_TYPE_HID` – Human Interface Device drivers (keyboard/mouse/gamepads; often depends on USB) - `SQRM_TYPE_GENERIC` – generic modules (not bound to a specific subsystem) ## Exporting APIs (SQRM Services) Some modules (notably NET/USB/HID) are most useful when they **export a service API** that the kernel or other modules can use. The kernel provides a small named service registry: - `api->sqrm_service_register("name", api_ptr, sizeof(*api_ptr))` - `api->sqrm_service_get("name", &size)` Conventions (current): - `"net"` exports `sqrm_net_api_v1_t` - `"usb"` exports `sqrm_usb_api_v1_t` - `"hid"` exports `sqrm_hid_api_v1_t` A skeleton module should export a stub API that returns `-ENOSYS` for unimplemented operations, so third-party drivers have a stable surface to build against. ### Building a `.sqrm` You can build third‑party modules out-of-tree using the SDK in `sdk/`. Minimal build flags (from `sdk/template_hello/build.sh`): ```sh x86_64-elf-gcc -I sdk -ffreestanding -fPIC -mno-red-zone -nostdlib \ -Wl,-shared -Wl,-e,sqrm_module_init \ hello_sqrm.c -o hello.sqrm ``` Notes: - `-fPIC` is required. - `-mno-red-zone` is required for interrupt-safe kernel code. - The link must produce `ET_DYN` (`-shared`). - The entry point must be `sqrm_module_init`. ### Installing / testing 1) Copy your module into the ISO tree: - `targets/AMD64/iso/ModuOS/System64/md/.sqrm` 2) Rebuild the ISO. 3) Boot and check COM logs for module loader output: - `[SQRM] Loading module: ...` ### Examples - In-tree minimal module: `modules/hello_sqrm.c` - SDK template: `sdk/template_hello/hello_sqrm.c` - Filesystem module: `modules/ext2_sqrm.c` --- ## Driver Structure ```c typedef struct { const char *name; int (*init)(void); int (*probe)(void); void (*remove)(void); } driver_t; ``` ## PCI Driver ### PCI Device Structure ```c typedef struct { uint8_t bus; uint8_t device; uint8_t function; uint16_t vendor_id; uint16_t device_id; uint8_t class_code; uint8_t subclass; uint32_t bar[6]; } pci_device_t; ``` ### PCI Functions ```c // Find device by vendor/device ID pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id); // Find device by class pci_device_t* pci_find_class(uint8_t class_code, uint8_t subclass); // Enable bus mastering void pci_enable_bus_mastering(pci_device_t *dev); // Read BAR uint32_t pci_read_bar(pci_device_t *dev, int bar_num); ``` ### Example PCI Driver ```c int mydriver_init(void) { // Find device pci_device_t *dev = pci_find_device(VENDOR_ID, DEVICE_ID); if (!dev) { return -1; } // Enable device pci_enable_bus_mastering(dev); pci_enable_memory_space(dev); // Map BARs uint32_t bar0 = pci_read_bar(dev, 0); // Initialize hardware // ... return 0; } ``` ## IRQ Handling ### Register IRQ Handler ```c void irq_register_handler(int irq, irq_handler_t handler); void my_irq_handler(registers_t *regs) { // Handle interrupt // ... } // In driver init: irq_register_handler(IRQ_NUM, my_irq_handler); ``` ## I/O Operations ### Port I/O ```c // Read from I/O port uint8_t inb(uint16_t port); uint16_t inw(uint16_t port); uint32_t inl(uint16_t port); // Write to I/O port void outb(uint16_t port, uint8_t value); void outw(uint16_t port, uint16_t value); void outl(uint16_t port, uint32_t value); ``` ### Memory-Mapped I/O ```c // Map physical address to virtual void *ioremap(uint64_t phys_addr, size_t size); // Access memory-mapped registers volatile uint32_t *regs = (volatile uint32_t*)ioremap(bar0, 0x1000); uint32_t status = regs[0]; regs[1] = command; ``` ## Next Steps - [Device Drivers](Device-Drivers.md) - Driver overview - [PCI Subsystem](PCI-Subsystem.md) - PCI details