Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Nyxos is a microkernel-based operating system, featuring a wide array of supported programs and components designed to create a comprehensive user and application environment. In this chapter, we will explore the goals, philosophy, and scope of Nyxos.
As with any microkernel-based operating system, a significant portion of kernel components in nyxOS are moved to user-space and adapted to function there. This design contrasts with monolithic kernels, which typically have hundreds of system calls due to the large number of integrated kernel components. These system calls serve as interfaces to the kernel components and often include numerous sub-calls through mechanisms like ioctl and procfs/sysfs. In contrast, microkernels like NyxOS have only a limited set of system calls—usually just a few dozen.
This reduction in system calls occurs because non-essential kernel components are shifted to user-space, relying instead on Inter-Process Communication (IPC), which will be detailed later.
The user-space bootstrap is the initial program launched by the kernel. It has a straightforward design: the kernel loads the initfs blob, which contains both the bootstrap executable and the initfs image that was provided by the boot loader. The kernel sets up an address space for this blob and jumps to a designated offset provided by the bootloader. The bootstrap process allocates a stack (using an Assembly stub), applies memory protection (mprotect), and completes the necessary steps to execute the init daemon. It also sets up the initfs scheme daemon.
For IPC, NyxOS primarily utilizes file-based system calls. The kernel needs to know which schemes to forward certain system calls to, which it determines through scheme prefixes or by tracking which scheme opened a file descriptor. File-based syscalls are tagged with either SYS_CLASS_PATH or SYS_CLASS_FILE. In the case of SYS_CLASS_PATH, the kernel matches the path prefix with the scheme name. For SYS_CLASS_FILE, the kernel remembers the scheme associated with the file descriptors. While most IPC operations use schemes, there are exceptions, such as standard pipes (similar to Linux's pipe2, read, write, close). Schemes can also establish custom pipe-like IPC mechanisms, like shm: and chan: from ipcd.
Schemes are implemented as Rust traits within the kernel, with built-in kernel schemes adhering to this trait. User-space schemes are provided via the UserScheme trait implementor, which involves messaging between the kernel and the scheme daemon. This communication channel is established when scheme daemons open a :SCHEME_NAME, which is parsed to the root scheme "" with path "SCHEME_NAME". Messages are sent by reading from and writing to the root scheme file descriptor.
Thus, file-based syscalls interacting with user-space files send messages to the respective scheme daemon. The results of these operations are sent back to the kernel, which then returns the outcome to the process that made the syscall.
Communication between user-space and the kernel is generally efficient, although the current syscall handler implementation may be somewhat unoptimized. Systems with Meltdown mitigations might experience exceptions, but such mitigations have not yet been implemented.
The NyxOS kernel employs the Round Robin scheduling algorithm to manage task execution. This algorithm ensures that each process gets a fair share of CPU time in a cyclical manner.
To facilitate this, the kernel registers a special function known as an interrupt handler, which the CPU invokes at regular intervals. This handler monitors the number of times it has been called, and after every 10 "ticks," it schedules the next process in line that is ready to run.
This method of scheduling ensures efficient time-sharing between processes, providing a balanced and predictable execution environment.
This chapter will discuss the design of Nyxos.
System calls are generally straightforward, sharing a similar Application Binary Interface (ABI) with standard function calls. On the x86_64 architecture, system calls are invoked using the syscall instruction, which triggers a mode switch from user-mode (ring 3) to kernel-mode (ring 0). Once the system call handler completes its operation, it switches back to user-mode, using the sysretq instruction to return control, functioning similarly to how a regular function call returns.
Security Mechanisms on NyxOS
NyxOS employs several security mechanisms to ensure the integrity and isolation of processes, including namespaces and a capability-based system. Some aspects of these mechanisms are managed by the kernel, though certain features can be handled in user-space.
Namespaces
In NyxOS, a namespace represents a list of schemes. For example, running ls : will display the schemes available in the current namespace. Each process operates within its own namespace, providing isolation and control over which schemes and resources are accessible.
Capabilities
Capabilities in NyxOS are specialized file descriptors that define specific actions or permissions. These capabilities can be used to control and limit what a process can do, enhancing security by preventing unauthorized actions.
Sandbox
NyxOS supports sandboxing through the following methods:
Namespace Restrictions: By limiting the number of schemes available in a process’s namespace, or by excluding schemes entirely, you can restrict a program’s access. For instance, a process without any schemes in its namespace cannot open new file descriptors, thus limiting its interactions and potential security risks.
File Descriptor-Based Functionality: While this feature is still under development, NyxOS aims to enforce all functionalities through file descriptors. This approach ensures that programs interact with the system in a controlled manner, further enhancing security and sandboxing capabilities.
Boot Loader
The source code for the bootloader can be found in cookbook/recipes/bootloader/source after a successful build or can be accessed here.
BIOS Boot
In x86 systems utilizing BIOS, the very first code executed is located in the boot sector, known as stage 1. This part is written in Assembly and can be found in asm/x86-unknown-none/stage1.asm. Stage 1 is responsible for loading the stage 2 bootloader from the disk, which is also written in Assembly. At this point, the system transitions into 32-bit mode and loads the final bootloader, stage 3, which is written in Rust. All three stages are combined into a single executable and stored within the first megabyte of the storage device. From here, the bootloader moves into the unified boot process that is shared across all booting methods, explained later.
UEFI Boot
(TODO)
The bootloader sets up the memory map and display mode, both of which depend on firmware operations that can no longer be accessed once control is passed to the kernel. After initializing these, the bootloader locates the NyxFS partition on the disk and loads the kernel, along with the bootstrap and initfs files, into memory. The kernel is mapped to its designated virtual memory address, and control is handed off to its entry point.
Kernel
The NyxOS kernel performs architecture-specific setup during the kstart function. Once complete, it transitions to the kmain function. The bootstrap process in user space—a pre-processed executable to minimize kernel parsing—then initializes the initfs scheme and launches the init program.
Init Process
NyxOS uses a multi-stage init system designed to allow the dynamic loading of drivers for disk access and other functions. This is referred to as the init RAMdisk.
RAMdisk Init
The RAMdisk init stage loads drivers required to access the root filesystem, then passes control to the filesystem init stage. This includes drivers for ACPI, the framebuffer, and support for IDE, SATA, and NVMe storage devices. Once the disk drivers are in place, the NyxFS driver is activated using the UUID of the partition where the kernel and boot files are stored. It scans the drivers for this partition, mounts it, and continues the initialization process.
Filesystem Init
In this stage, drivers for non-disk-related tasks, such as audio and networking, are loaded. Once these essential drivers are initialized, the system displays the login prompt. If the display server Orbital is enabled, it is launched at this point.
Login
After all drivers and services are initialized, the user is able to log in. The login program prompts for a username, with "user" being the default, and displays the /etc/motd file. It then launches the user’s default shell, typically ion, providing full access to the system shell.
Graphical Overview
A graphical illustration of the boot and initialization process, including major scheme interactions, can be found below. While this overview may be slightly outdated, it remains informative regarding the overall system initialization.
Boot Process Documentation
For further information, more detailed documentation on the boot process is available.
Why We Chose to Write an Operating System in Rust
Rust offers significant advantages, especially in the context of operating systems, where security and stability are paramount. Operating systems are foundational to computing, making them the most crucial piece of software. Throughout the history of computing, there have been numerous bugs and vulnerabilities in systems like Linux, BSD, glibc, Bash, and X11, often stemming from issues related to memory allocation and type safety. Rust addresses these issues by enforcing memory safety at the compile-time, which is crucial for preventing such vulnerabilities.
The Importance of Rust in OS Development
Design is important, but so is the implementation. Rust excels in preventing unexpected memory-unsafe conditions, which are a major source of security-critical bugs. Rust's design is transparent, allowing developers to clearly understand what is happening in the code and what the intended behavior is.
The basic design of the kernel and user-space separation in Nyxos is similar to Unix-like systems. The core idea is to separate the kernel and user-space, with the kernel strictly enforcing system resource management. However, Nyxos has a significant advantage: enforced memory and type safety. Rust's strength lies in eliminating a large number of "unexpected bugs," such as undefined behavior, at compile-time.
While the design of Linux and BSD is secure, their implementation is not. Many bugs in Linux stem from unsafe conditions—like buffer overflows—that Rust effectively eliminates. By using Rust, we aim to produce a more secure and stable operating system.
The Role of unsafe in Rust
unsafe is a mechanism in Rust that allows developers to perform operations that the compiler cannot guarantee to be safe, such as low-level memory manipulation. While you cannot write a kernel without using unsafe, Rust requires that these unsafe operations be explicitly marked as such. This keeps the unsafe parts isolated from the rest of the safe code. We aim to minimize the use of unsafe where possible, and when we do use it, we do so with extreme caution.
This approach contrasts with kernels written in C, where no guarantees about security can be made without costly formal analysis. In Rust, the use of unsafe is carefully controlled, enhancing overall system safety.
Benefits of Writing Nyxos in Rust
1. Reduced Likelihood of Bugs
The restrictive syntax and strict compiler requirements of Rust significantly reduce the probability of bugs in the code.
2. Less Vulnerability to Data Corruption
The Rust compiler helps programmers avoid memory errors and race conditions, reducing the chances of data corruption bugs.
3. No Need for C/C++ Exploit Mitigations
The microkernel design, when written in Rust, is naturally protected against the memory defects commonly seen in software written in C/C++. By isolating system components from the kernel, the attack surface is significantly reduced.
4. Improved Security and Reliability Without Performance Impact
The small size of the kernel means it uses less memory, helping to maintain a bug-free status (KISS principle). Rust’s combination of safe and fast language design, along with the minimal kernel code size, ensures a reliable, performant, and easy-to-maintain core.
5. Thread-Safety
C/C++ support for thread safety is fragile, making it easy to introduce subtle bugs or security holes when running programs across multiple threads. Rust's type system prevents the writing of unsafe concurrent access patterns, helping to avoid these issues. This ensures that Nyxos is less prone to bugs related to thread safety.
6. Rust-Written Drivers
Drivers written in Rust are likely to have fewer bugs, making them more stable and secure, contributing to the overall reliability of Nyxos.
By choosing Rust for Nyxos, we are working towards creating an operating system that is not only secure and stable but also efficient and reliable, setting a new standard for operating system development.
There are billions of devices across hundreds of models and architectures globally. We aim to develop drivers for the most commonly used devices to reach a wider audience. Support is dependent on the specific hardware, as some drivers are tailored to specific devices while others are architecture-specific.
You can check HARDWARE.md for a list of all tested computers.
CPU
Intel: 64-bit (x86_64) and 32-bit (i686) from Pentium II onwards with certain limitations.
AMD: 64-bit (AMD64) and 32-bit.
ARM: 64-bit (Aarch64) with some limitations.
Why aren't CPUs older than i686 supported?
i686 (essentially Pentium II) introduced a variety of features that are crucial for the Nyxos kernel. While it's technically possible to support older CPUs like the i486, doing so would mean losing valuable functions such as fxsave/fxrstor, and we would need to build the userspace without any SSE code. Additionally, i386 lacks atomic operations entirely, making it an unlikely target.
Hardware Interfaces
ACPI
PCI
(USB support coming soon)
Video
VGA - (BIOS)
GOP (UEFI)
LLVMpipe (OpenGL CPU emulation)
(Support for Intel/AMD and others in the future)
Sound
Intel chipsets
Realtek chipsets
PC speaker
(Sound Blaster support coming soon)
Storage
IDE (PATA)
SATA (AHCI)
NVMe
(USB support coming soon)
Input
PS/2 keyboards, mice, and touchpads
USB keyboards, mice, and touchpads
Internet
Intel Gigabit Ethernet
Intel 10 Gigabit Ethernet
Realtek Ethernet
(Support for Wi-Fi and Atheros Ethernet coming soon)
I have a low-end computer, would Nyxos work on it?
A CPU is one of the most complex machines in the world; even the oldest processors are capable of handling some tasks but may struggle with others. The primary challenge with older computers is the limited amount of RAM available (as they were sold during a time when RAM was expensive) and the lack of SSE/AVX extensions (which modern programs use to accelerate algorithms). As a result, some contemporary software may not function properly or may require substantial amounts of RAM to handle complex tasks.
nyxOS itself will generally operate if the processor architecture is supported by the system, but the performance and stability can vary depending on the program.
In Nyxos, device drivers operate as user-space daemons, each running as a separate Unix process with its own namespace and restricted schemes. This setup ensures that a driver cannot interfere with or damage other system interfaces. In contrast, on monolithic kernels, drivers run within the same memory address space as the filesystem and other kernel components, meaning they share the same privilege level. This design can potentially lead to severe issues, such as data loss, if a driver malfunctions or is compromised.
You can find detailed documentation and source code for the drivers in the repository's README and the drivers' code sections.
nyxOS is an effort to create a complete, fully functional, general-purpose operating system with a strong emphasis on safety, freedom, stability, correctness, and practicality. Our goal is to use it without barriers as a full-fledged alternative to Linux/BSD on our computers. It should be capable of running most Linux/BSD programs with minimal modifications.
We are striving to build a complete, stable, and secure Rust ecosystem. This is a deliberate design choice intended to enhance correctness and security (see Why Rust). Our aim is to improve security design compared to other Unix-like operating systems by adopting safe defaults and minimizing insecure configurations wherever possible.
The Non-Goals of nyxOS
We are not trying to be a Linux/BSD clone or POSIX-compliant, nor are we attempting to radically redesign everything. Generally, we adhere to well-tested and proven designs. If it isn’t broken, don’t fix it.
This approach ensures that a significant number of programs and libraries will be compatible with nyxOS. However, some elements that do not align with our design choices may need to be ported. The key here is balancing correctness with compatibility. Ideally, both should be achievable, but unfortunately, this is not always possible.
How Nyxos Was Influenced by Other Operating Systems
Plan 9
Plan 9, an operating system developed by Bell Labs, brings the concept of "Everything is a File" to its highest level by handling all system communication through the filesystem. This philosophy has strongly influenced Nyxos, which adopts a similar approach to create a more unified and efficient system API.
Minix
Minix is one of the most influential Unix-like systems with a microkernel architecture. It includes advanced features such as system modularity, kernel panic resistance, driver reincarnation, protection against faulty drivers, and secure interfaces for process communication. Nyxos is heavily influenced by Minix, sharing a similar architecture but with a feature set implemented in Rust, which enhances both security and reliability.
seL4
seL4 is known as the most performant and simplest microkernel in the world. Nyxos follows similar principles, striving to keep the kernel space as minimal as possible by moving components to user space and reducing the number of system calls. This approach not only simplifies the kernel but also maintains overall system performance by minimizing the cost of context switching.
BSD
The BSD family of Unix systems introduced several improvements to the original Unix systems, and the open-source variants of BSD brought many additional enhancements. Specific influences on Nyxos include:
FreeBSD: The Capsicum (a capability-based security system) and jails (a sandbox technology) from FreeBSD have influenced the implementation of namespaces in Nyxos.
OpenBSD: The system call, filesystem, display server, and audio server sandboxes from OpenBSD have inspired various security features in Nyxos.
Linux
Linux, the most advanced monolithic kernel and the largest open-source project in the world, has introduced numerous improvements and optimizations to Unix-like systems. Nyxos aims to implement these performance enhancements within a microkernel design, combining the efficiency of Linux with the security and modularity of a microkernel architecture.
Nyxos is primarily licensed under the MIT X11-style license, which covers all software, documentation, and fonts within the project. There are only a few exceptions to this, all of which are licensed under other compatible open-source licenses.
The MIT X11-style license offers the following benefits:
Unrestricted Access: It grants you, the user, full and unrestricted access to the software, allowing you to inspect, modify, and redistribute your changes.
Inspection: Anyone is permitted to inspect the software to identify any security vulnerabilities.
Redistribution: Anyone can redistribute the software to patch any discovered security vulnerabilities.
GPL Compatibility: It is compatible with GPL licenses, meaning that projects licensed under GPL can be distributed with Nyxos.
Incorporation of GPL-Incompatible Free Software: The license permits the inclusion of GPL-incompatible free software, such as OpenZFS, which is licensed under CDDL.
Moreover, the license does not impose restrictions on the software that can run on Nyxos. Thanks to the microkernel architecture, even components that are traditionally tightly coupled, like drivers, can be distributed separately, allowing maintainers to choose any license they prefer for their projects.
Nyxosis committed to being free forever, as we aspire to be a foundational element in the creation of secure and resilient systems.
We share quite a lot with other operating systems.
System Calls
The Nyxos API is Unix-like. For instance, we have system calls like open, pipe, pipe2, lseek, read, write, brk, execv, and so on. Currently, we support the most common POSIX and Linux system calls.
However, Nyxos does not necessarily implement them as direct system calls. Much of the functionality for these operations (typically the man(2) functions) is provided in user space through an interface library, relibc.
"Everything is a File"
In a model largely inspired by Plan 9, in Nyxos, resources can be socket-like or file-like, providing a more unified system API. Resources are named using paths, similar to what you would find in Linux or another Unix system. However, when referring to a resource managed by a particular resource manager, you can address it using a scheme-rooted path. We will explain this later in Schemes and Resources.
The Kernel
Nyxos's kernel is a microkernel, with an architecture largely inspired by MINIX and seL4.
In contrast to Linux or BSD, Nyxos has around 50,000 lines of kernel code, a number that is often decreasing. Most system services are provided in user space, either through an interface library or as daemons.
Having a vastly smaller amount of code in the kernel makes it easier to efficiently identify and fix bugs and security issues. Andrew Tanenbaum (author of MINIX) stated that for every 1,000 lines of properly written C code, there is a bug. This implies that in a monolithic kernel with nearly 25,000,000 lines of C code, there could be nearly 25,000 bugs. A microkernel with only 50,000 lines of C code would likely contain around 50 bugs.
It's important to note that the extra code is not discarded; it is simply based outside of kernel space, making it less hazardous.
The primary idea is to ensure that system components and drivers, which would typically reside within a monolithic kernel, exist in user space and adhere to the Principle of Least Authority (POLA). This means that each component is:
Completely isolated in memory as separate user processes (daemons).
The failure of one component does not crash other components.
Foreign and untrusted code does not compromise the entire system.
Bugs and malware cannot spread to other components.
All of these factors significantly enhance the system's reliability, which is crucial for users seeking minimal issues with their computers or for mission-critical applications.
Communication with other components is restricted.
Lacks Admin/Super-User privileges.
Bugs are confined to user space, reducing their potential impact.
Nyxos is a general-purpose operating system that can be utilized in a variety of scenarios. Some of the key use cases for Nyxos are as follows:
Server
Nyxos has the potential to be a secure server platform for cloud services and web hosting. The enhanced safety and reliability that Nyxos aims to provide as it matures make it an excellent fit for the server environment. There is ongoing work to support crucial server technologies such as databases and web servers, as well as compatibility with high-end server hardware.
Plans are also underway for virtualization support in Nyxos. Although running an instance of Linux in a container on Nyxos may forfeit some of the unique benefits of Nyxos, it can still help to limit the scope of vulnerabilities. Virtualization of Nyxos-on-Nyxos and Linux-on-Nyxos has the potential to be much more secure than Linux-on-Linux. These capabilities are still in development but are among the goals of the Nyxos team.
Desktop
The development of Nyxos for the desktop is well underway. Although support for accelerated graphics is currently limited, Nyxos does include a graphical user interface and support for Rust-written GUI libraries like winit, Iced, and Slint.
A demo version of Nyxos is available with several games and programs to explore. However, the primary objective for the desktop environment is to host the development of Nyxos itself. We are addressing issues with some of our build tools, and other developer tools such as editors have not yet been fully tested for daily use, but we continue to prioritize this.
Due to a relatively limited list of currently supported hardware, once self-hosted development becomes available, development can be performed within Nyxos for quicker testing. We are continuously expanding hardware compatibility, and we aim to support development on a wide range of desktops and notebooks in the near future.
Infrastructure
Nyxos's modular architecture makes it an ideal candidate for various telecom infrastructure applications, such as routers, telecom components, edge servers, and more, especially as additional functionality is integrated into these devices. While there are no specific plans for remote management yet, Nyxos's potential for security and reliability makes it well-suited for this type of application.
Embedded and IoT
For embedded systems with complex user interfaces and extensive feature sets, Nyxos has the potential to be an excellent fit. As everyday appliances become internet-connected devices with sensors, microphones, and cameras, they become vulnerable to attacks that could infringe upon consumer privacy within their homes. Nyxos can offer a full-featured, reliable operating system while minimizing the likelihood of such attacks. Currently, Nyxos does not yet support touchscreens, video capture, or sensors and buttons, but these are well-understood technologies that can be added as they become a priority.
Mission-Critical Applications
Although there are no immediate plans to develop a version of Nyxos for mission-critical applications such as satellites or air safety systems, this possibility is not entirely out of reach. As tools for correctness proofs of Rust software continue to improve, it may eventually be possible to create a version of Nyxos that is proven correct within practical limits.
The essential goal of the Nyxos project is to develop a robust, reliable, and secure general-purpose operating system. To achieve this, the following key design choices have been made:
Written in Rust
Whenever possible, Nyxos code is written in Rust. Rust enforces a strict set of rules and checks on the use, sharing, and deallocation of memory references. This almost entirely eliminates the potential for memory leaks, buffer overruns, use-after-free errors, and other memory-related issues that typically arise during development. The majority of security vulnerabilities in operating systems stem from memory errors, but the Rust compiler prevents these types of errors before they can be introduced into the codebase.
Microkernel Architecture
The Microkernel Architecture in Nyxos shifts as many components as possible out of the operating system kernel. Drivers, subsystems, and other operating system functionalities run as independent processes in user-space (daemons). The kernel's primary responsibility is to coordinate these processes and manage system resources.
Most kernels, except for some real-time operating systems, use an event-handler design. Hardware interrupts and application system calls each trigger an event that invokes the appropriate handler. The kernel operates in supervisor mode, with access to all system resources. In Monolithic Kernels, the entire operating system’s response to an event must be completed in supervisor mode. An error in the kernel, or even a malfunctioning piece of hardware, can cause the system to enter a state where it is unable to respond to any event. Due to the extensive amount of code in the kernel, the potential for vulnerabilities in supervisor mode is significantly higher compared to a microkernel design.
In Nyxos, drivers and many system services run in user mode, similar to user programs, and the system can restrict them so they only access the resources necessary for their designated purpose. If a driver fails or crashes, it can be ignored or restarted without impacting the rest of the system. A malfunctioning piece of hardware might affect system performance or cause the loss of a service, but the kernel will continue to function and provide whatever services remain available.
This makes Nyxos a unique opportunity to demonstrate the potential of microkernel architecture in mainstream operating systems.
Benefits
The following sections summarize the benefits of a microkernel design:
True Modularity: You can modify or change many system components without needing to restart the system, offering a safer alternative to kernel modules and live patching.
Bug Isolation: Most system components run in user-space on a microkernel system. As a result, bugs in most system components won't crash the entire system or kernel.
Restartless Design: A mature microkernel undergoes very few changes (except for bug fixes), so you won’t need to restart your system often to update it. Since most system components are in user-space, they can be replaced on-the-fly, significantly reducing server downtime.
You can read more about these benefits on this page.
Advanced Filesystem
Nyxos provides an advanced filesystem, nyxFS. It includes many features found in ZFS but offers a more modular design.
More details on nyxFS can be found here.
Unix-like Tools and API
Nyxos offers a Unix-like command interface, with many everyday tools written in Rust but with familiar names and options. Additionally, Nyxos system services include a programming interface that is a subset of the POSIX API, via relibc. This means that many Linux/POSIX programs can run on Nyxos with only recompilation. While the Nyxos team strongly prefers essential programs to be written in Rust, we are agnostic about the programming language for user-chosen programs. This provides an easy migration path for systems and programs previously developed for Unix-like platforms.
The NyxOS kernel is a microkernel. Microkernels are notable for their design, providing only minimal abstractions in kernel space. Unlike monolithic kernels, which emphasize kernel-space functionality, microkernels focus more on user-space. The core philosophy behind microkernels is that any component capable of running in user-space should indeed run there. Kernel-space should be reserved for only the most critical functions, such as system calls, process isolation, resource management, inter-process communication (IPC), and thread management.
The main role of the kernel is to facilitate communication and isolation between processes. It should offer minimal abstraction over the hardware—drivers, for instance, should run in user-space when possible. Microkernels offer superior security and are less prone to crashes compared to monolithic kernels. This is due to moving most components into user-space, utilizing separate memory address spaces, reducing the potential for harm to the system. Furthermore, microkernels are highly maintainable, as their smaller codebase results in fewer bugs overall.
As with everything, microkernels come with their own advantages and disadvantages.
Advantages of Microkernels
Improved Modularity and Configuration Monolithic kernels are, as the name implies, monolithic in structure. They lack the fine-grained control that microkernels offer. This is because many essential components are hard-coded directly into the kernel, necessitating modifications when changes are required, such as with device drivers. In contrast, microkernels are inherently modular. You can add, remove, replace, or modify modules during runtime without needing to alter the kernel itself. While modern monolithic kernels have adopted kernel modules to address this issue, they still often require a system reboot.
Enhanced Security Microkernels are considerably more secure than their monolithic counterparts. This stems from the principle of minimality, which aligns with the least privilege concept: each component should have only the permissions absolutely necessary to function. Many security vulnerabilities in monolithic kernels come from services and drivers that run with unrestricted access in kernel mode, exposing the system to various risks. In a monolithic design, drivers can operate without limitations in kernel mode, making the system more vulnerable.
Better System Stability Compared to microkernels, monolithic kernels are more prone to crashes. A faulty driver in a monolithic kernel can bring down the entire system, as both the driver and the kernel share the same memory space. A crash in the kernel cannot be recovered without risking memory corruption, resulting in a system failure (kernel panic). In a microkernel system, drivers are isolated in their own memory spaces, so any crash can be safely contained. In Linux, for instance, drivers frequently encounter issues with dereferencing invalid pointers, often leading to kernel panics. Extensive documentation, such as that found in MINIX, explains how microkernels handle such issues more effectively.
Easier Debugging In microkernels, since most kernel components (e.g., drivers, file systems) run in user-space, bugs in these components don’t result in kernel crashes. This is particularly useful when debugging on physical hardware; if a kernel panic occurs, it is often impossible to save logs that could help identify the bug. In contrast, a bug in a monolithic kernel’s component causes a system-wide crash, locking the system completely. This makes debugging hardware issues significantly more challenging, especially without serial output.
Disadvantages of Microkernels
Slight Performance Overhead Modern operating systems require fundamental security features like memory segmentation and virtualization. Additionally, every process, including the kernel, needs its own stack and register storage. When a context switch occurs, such as during a system call or any other form of inter-process communication (IPC), a series of tasks must be executed:
Saving the caller’s registers, especially the program counter.
Reprogramming the memory management unit (MMU) page tables.
Switching between CPU modes (user mode to kernel mode, and vice versa).
Restoring the callee’s registers.
While these operations aren’t inherently slower in microkernels, they need to be performed more frequently due to the nature of microkernel design. Since many functionalities are handled by user-space processes, more context switches are required. However, over time, the performance gap between monolithic and microkernels has shrunk considerably, partly due to the smaller codebase in microkernels, which is easier to optimize.
Microkernels vs. Monolithic Kernels
Monolithic kernels offer more built-in abstractions compared to microkernels. The illustration provided in public domain highlights the difference between the two approaches.
Documentation and Further Reading
Kernel/User-Space Separation Documentation
Dual Mode Operations in OS
User Mode and Kernel Mode Switching
OSDev Technical Wiki
Current State of NyxOS
NyxOS kernel currently contains fewer than 40,000 lines of Rust code. For comparison, MINIX's kernel has about 6,000 lines of C code. However, this comparison does not imply that MINIX is more stable or secure than NyxOS solely based on lines of code. NyxOS includes more advanced features, which naturally results in a larger codebase. In the future, we aim to move even more components to user-space, further minimizing the kernel's size and complexity.
MINIX Features and Reliability
GNU Hurd Documentation
Fuchsia Documentation
HelenOS FAQ
MINIX Papers
seL4 Whitepapers
Microkernel Performance Papers
Tanenbaum-Torvalds Debate