Tech talk #1: Hybrid and modular Whitix (1/2)
May 3rd, 2008It’s been suggested to me that I should explain some of the technical decisions I’ve made on the project’s weblog. Here’s the first of (hopefully) a long series of articles about the technical elements of a modern desktop operating system. In this article, I’m going to explain and detail my recent redesign (or rather a redesign in progress in a Subversion branch) of the Whitix kernel.
The plan, at the moment, is to make Whitix a hybrid kernel, mainly to ensure stability. But hybrid in what way? Basically, most of the kernel at the moment will become modularised (even the slab allocator and virtual filesystem; a general rule is anything that has a *Init function in the current kernel will be modularised) and moved to userspace, where they’ll be linked in to the kernel at runtime using the kernel’s new module code. This will all happen at different points in the kernel’s startup procedure; some core modules will be loaded into memory at boot-time, where as drivers can wait a good deal longer before being loaded.
The advantages of moving a lot of driver and stack code is that it ensures system stability. A lot of the system crashes I see, in Whitix, Linux (see kerneloops.org) and other operating systems, involve null pointer errors or page faults in device drivers and subsystems, rather than in the core kernel code. Moving stacks and drivers to userspace means, that when they do crash, the kernel can look at the instruction pointer (eip) and determine which module crashed, and if so, reload it. (which may just involve resetting the module)
Surely the kernel needs some system functions that will now be modularised in userspace? Some functions, like malloc and other memory allocation functions, can still be called by the kernel (using a trampoline function down to userspace, much like how the kernel can transfer down to userspace for tasks) using a function pointer whose value is set by a GetModuleSymbol(<symbol>)-type function. The kernel can return a link to a stub function that transfers the CPU into userspace and then the real function.
How do the userspace drivers call kernel code? (or how does system code return to the kernel?) My proposal is for a seperate interrupt that transfers to any point in the kernel (the interrupt would check the EIP of the calling process, and ensure it came from a driver, rather than a user process). This interrupt would be called by a stub function in the kernel, which would be generated by a SYMBOL_EXPORT define. The kernel would return to userspace via the usual iret method.
One advantage is that there could be a DRIVERS_IN_KERNEL define, which would move all the modules into the kernel; losing the increased stability, but also decreasing the number of privilege switches while still retaining the modular aspect of the new design.
At the moment, development of this new kernel is taking place in the branches/hybrid/ section of the Whitix development tree. Want to help out? See the becoming a developer section of the wiki.
In the next tech talk article, I’ll go over (with code examples) the hybrid kernel design in greater detail. Thanks for reading.