-
Notifications
You must be signed in to change notification settings - Fork 0
Driver API
API for developing hardware drivers in ModuOS.
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.
Modules are searched under:
-
/ModuOS/System64/md/(on the selected boot filesystem)
On the ISO this corresponds to:
targets/AMD64/iso/ModuOS/System64/md/
A valid module must export:
- A module descriptor symbol named
sqrm_module_desc
#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);- An entry point:
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:
if (!api || api->abi_version != SQRM_ABI_VERSION) return -1;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)
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"exportssqrm_net_api_v1_t -
"usb"exportssqrm_usb_api_v1_t -
"hid"exportssqrm_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.
You can build third‑party modules out-of-tree using the SDK in sdk/.
Minimal build flags (from sdk/template_hello/build.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.sqrmNotes:
-
-fPICis required. -
-mno-red-zoneis required for interrupt-safe kernel code. - The link must produce
ET_DYN(-shared). - The entry point must be
sqrm_module_init.
- Copy your module into the ISO tree:
targets/AMD64/iso/ModuOS/System64/md/<name>.sqrm
-
Rebuild the ISO.
-
Boot and check COM logs for module loader output:
[SQRM] Loading module: ...
- In-tree minimal module:
modules/hello_sqrm.c - SDK template:
sdk/template_hello/hello_sqrm.c - Filesystem module:
modules/ext2_sqrm.c
typedef struct {
const char *name;
int (*init)(void);
int (*probe)(void);
void (*remove)(void);
} driver_t;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;// 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);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;
}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);// 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);// 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;- Device Drivers - Driver overview
- PCI Subsystem - PCI details