PatchworkOS
A modular, non-POSIX operating system for x86_64, built from scratch in C and assembly. Intended to be educational and experimental while rigorously following a Plan9-style "everything is a file" philosophy, featuring a from-scratch ACPI AML parser, EEVDF scheduler and a pseudo-capability namespace based security model.
Install / Use
/learn @KaiNorberg/PatchworkOSREADME
PatchworkOS
<br> <div align="center"> <a href="https://github.com/KaiNorberg/PatchworkOS/issues"> <img src="https://img.shields.io/github/issues/KaiNorberg/PatchworkOS"> </a> <a href="https://github.com/KaiNorberg/PatchworkOS/stargazers"> <img src="https://img.shields.io/github/stars/KaiNorberg/PatchworkOS"> </a> <a href="https://kainorberg.github.io/PatchworkOS/html/index.html"> <img src="https://img.shields.io/badge/docs-Doxygen-blue"> </a> <a href="https://github.com/KaiNorberg/PatchworkOS/blob/main/license"> <img src="https://img.shields.io/github/license/KaiNorberg/PatchworkOS"> </a> <a href="https://github.com/KaiNorberg/PatchworkOS/actions/workflows/test.yml"> <img src="https://github.com/KaiNorberg/PatchworkOS/actions/workflows/test.yml/badge.svg" alt="Build and Test"/> </a> <br> <i>PatchworkOS is currently undergoing a major rewrite, see the <a href="https://github.com/KaiNorberg/PatchworkOS/tree/develop">develop</a> branch for more information.</i> </div> <br> <img src="meta/screenshots/desktop.png" alt="Desktop Screenshot" />PatchworkOS is a modular non-POSIX operating system for the x86_64 architecture that rigorously follows an "everything is a file" philosophy. Built from scratch in C and assembly.
While primarily a project made for fun, the goal is still to make a "real" operating system, one that runs on real hardware and has the performance one would expect from a modern operating system without jumping ahead to user space features or drivers, a floppy disk driver with a round-robin scheduler is not enough.
PatchworkOS is not a UNIX clone, it's intended to be a (hopefully) interesting experiment in operating system design by attempting to use unique algorithms and designs over tried and tested ones. Sometimes this leads to bad results, and sometimes, with a bit of luck, good ones.
Despite its experimental nature and scale, the project aims to remain approachable and educational, something that can work as a middle ground between fully educational operating systems like xv6 and production operating system like Linux.
Will this project ever reach its goals? Probably not, but that's not the point.
<table> <tr> <td width="50%" valign="top" align="center"> <img src="meta/screenshots/stresstest.png" alt="Stresstest Screenshot" /> <br> <i>Stress test showing ~100% utilization across 12 CPUs.</i> </td> <td width="50%" valign="top" align="center"> <img src="meta/screenshots/doom.png" alt="Doom Screenshot" /> <br> <i>DOOM running on PatchworkOS using a <a href="https://github.com/ozkl/doomgeneric">doomgeneric</a> port.</i> </td> </tr> </table>Features
Kernel
- Preemptive and tickless EEVDF scheduler based upon the original paper and implemented using an Augmented Red-Black tree to achieve
O(log n)worst case complexity. EEVDF is the same algorithm used in the modern Linux kernel, but ours is obviously a lot less mature. - Multithreading and Symmetric Multi Processing with fine-grained locking.
- Optimized memory management, featuring object caching and
O(1)per page physical and virtual memory managers. See benchmarks for more info. - File based IPC including pipes, shared memory, sockets and Plan9 inspired "signals" called notes.
- File based device API abstractions, including framebuffers, input devices, etc.
- Synchronization primitives including Read-Copy-Update, mutexes, R/W locks, sequential locks, futexes and others.
- Highly Modular design, even SMP Bootstrapping is done in a module.
File System
- Inode and dentry based VFS with RCU traversal, hardlinks, symlinks, per-process namespaces, etc.
- Custom Framebuffer BitMaP (.fbmp) image format, allows for faster loading by removing the need for parsing.
- Custom Grayscale Raster Font (.grf) font format, allows for antialiasing and kerning without complex vector graphics.
User Space
- Custom superset of the ANSI C standard library including threading, buffered I/O, math.h, PatchworkOS extensions, etc.
- Highly modular shared memory based desktop environment.
- Theming via config files.
- Capability based containerization security model using per-process mountpoint namespaces. See Security for more info.
- Note that currently a heavy focus has been placed on the kernel and low-level stuff, so user space is quite small... for now.
And much more...
Limitations
- Currently limited to RAM disks only (Waiting for USB support).
- Only support for x86_64.
Notable Future Plans
- Fully Asynchronous I/O and syscalls (io_uring?). <-- Currently being worked on.
- Implement 9P file servers. <-- Currently being worked on.
- Implement user system in user-space using namespaces.
- Improve
share()andclaim()security by specifying a target PID when sharing. - Overhaul Desktop Window Manager to use the new security system and file servers?
- Port LUA and use it for dynamic system configuration.
- USB support.
Setup
# Install dependencies
sudo dnf install gcc make mtools qemu-system-x86 # For Fedora
sudo apt install build-essential mtools qemu-system-x86 # For Debian/Ubuntu
# Clone this repository, you can also use the green Code button at the top of the Github.
git clone https://github.com/KaiNorberg/PatchworkOS
cd PatchworkOS
# Build (creates PatchworkOS.img in bin/)
make all
# Run using QEMU
make run
Doxygen Documentation
As one of the main goals of PatchworkOS is to be educational, I have tried to document the codebase as much as possible along with providing citations to any sources used. Currently, this is still a work in progress, but as old code is refactored and new code is added, I try to add documentation.
If you are interested in knowing more, then you can check out the Doxygen generated documentation. For an overview check the topics section in the sidebar.
Modules
PatchworkOS uses a "modular" kernel design, meaning that instead of having one big kernel binary, the kernel is split into several smaller "modules" that can be loaded and unloaded at runtime.
This is highly convenient for development, but it also has practical advantages, for example, there is no need to load a driver for a device that is not attached to the system, saving memory.
Make your own Module
Making a module is intended to be as straightforward as possible. For the sake of demonstration, we will create a simple "Hello, World!" module.
First, we create a new directory in src/kernel/modules/ named hello, and inside that directory we create a hello.c file to which we write the following code:
#include <kernel/module/module.h>
#include <kernel/log/log.h>
#include <stdint.h>
uint64_t _module_procedure(const module_event_t* event)
{
switch (event->type)
{
case MODULE_EVENT_LOAD:
LOG_INFO("Hello, World!\n");
break;
default:
break;
}
return 0;
}
MODULE_INFO("Hello", "<author>", "A simple hello world module", "1.0", "MIT", "BOOT_ALWAYS");
An explanation of the code will be provided later.
Now we need to add the module to the build system. To do this, just copy an existing module's .mk file without making any modifications. For example, we can copy src/modules/drivers/ps2/ps2.mk to src/modules/hello/hello.mk. The build system will handle the rest, including copying the module to the final image.
Now, we can build and run PatchworkOS using make all run, or we could use make all and then flash the generated bin/PatchworkOS.img file to a USB drive.
Now to validate that the module is working, you can either watch the boot log and spot the Hello, World! message, or you could use grep on the /dev/klog file in the terminal program like so:
cat /dev/klog | grep "Hello, World!"
This should output something like:
[ 0.747-00-I] Hello, World!
That's all, if this did not work, make sure you followed all the steps correctly. If there is still issues, feel free to open an issue.
What can I do now?
Whatever you want. You can include any kernel header, or even headers from other modules, create your own modules and include their headers or anything else. There is no need to worry about linking, dependencies or exporting/importing symbols, the kernels module loader will handle all of it for you. Go nuts.
Code Explanation
This code in the hello.c file does a few things. First, it includes the relevant kernel headers.
Second, it defines a _module_procedure() function. This function serves as the entry point for the module and will be called by the kernel to notify the module of events, for example the module being loaded or a device attached. On the load event, it will print using the kernels logging system "Hello, World!", resulting in the message being readable from /dev/klog.
