Blueprint for a Slow Machine

Note: this article is translated from the original Chinese version. The blog generator template is still designed only for Chinese posts, so there are some Chinese characters, and the Fediverse interaction won’t work.

The opening splash of DOOM(1993),with a ‘double vision’ effect because of buffer tearing

目录

The thrice-born Dionysus

Dionysus was originally the son of Zeus/Hades and Persephone, named Zagreus. Hera instructed Titans to kill Zagreus, and the youthful Dionysus was shredded and eaten. Then, Dionysus was born again. He reincarnated as the son of Zeus and Semele, this time, with the name of Dionysus. Hera plotted to have Zeus unleash his divine power upon the pregnant Semele, which burnt the innocent mother to death. The twice-born Dionysus was about to die young, however Zeus rescued the baby Dionysus from its dying mother, and sewed him into Zeus’ own thigh. Several months later, Zeus gave birth to Dionysus again, which is the thrice-born Dionysus. This time, Hermes sent the young Dionysus to be fostered by far-away Nymphs, preventing a fourth birth of Dionysus.

2020

My first attempt to write my own Operating System (OS) was during the summer vacation in 2020. My OS class lecturer back then recommended that I join a bootcamp to implement an OS in Rust, called rCore. I was interested in Rust at the time, as people on Hacker News touted it as ‘C++, but everything done right’. A classmate I admired also started using it two years prior. What’s more, that bootcamp ditched the x86 architecture for RISC-V. The former dates back to 1978 and is a Complex Instruction Set Computer (CISC) full of technical debt; while the latter was introduced in 2010, without backward-compatibility burdens, and was designed with the benefit of hindsight from all its predecessors’ missteps. I signed up for the bootcamp to learn Rust and RISC-V/OS simultaneously, as I couldn’t think of a better use of my time.

It later proved that trying to learn two new things at once meant mastering neither. The paradigm of Rust was too obscure for someone treating C++ as C+STL like me, the low-level designs of an OS were also too much for me to reason about back at that time. I found myself copying the code from the online textbook, rather than ‘designing and coding my own OS’. The final straw was that I was interning at a Cambricon Technologies, only having the after-work time for the bootcamp.

In the end, I didn’t implement my own OS like I had imagined.

2021

I have a fixation with unfinished things. When choosing my final year project in the fourth year of my undergraduate degree, I got the chance to keep working on 2020’s unfinished Rust OS (rCore): I chose a project called The User-level Interrupts Extension of RISC-V, which involved modifying rCore.

I was obsessed with designing a soft-core CPU using RTL: I had just finished implementing the classic five-stage pipelined MIPS CPU in the Computer Architecture class. I was tempted to implement a RISC-V CPU, which I had learned about in 2020, with a ‘super-Verilog’ called Chisel. The RISC-V instruction set was designed with extensions in mind. Take the N extension for user-level interrupts as an example: by duplicating the supervisor-level interrupt registers, it made it possible for the OS kernel (supervisor) to delegate interrupt handling to user-level programmes. This would save context switching for Network Interface Cards (NICs), as they wouldn’t need to trap into the kernel every time they interrupt. However, there was no CPU with the N extension back then, and that’s what made the project alluring to me: I could use Chisel to quickly prototype such a CPU, and modify rCore to use that capability.

In contrast to my high hopes when choosing the project, I didn’t manage to implement the N extension. That also meant I didn’t make it to the stage of continuing to learn about rCore and modifying it. Looking back, it seems every problem can be traced back to my preference to do things alone. Of course I was communicating with my supervisor and other classmates. However, lots of issues would have been easier to solve if I had just asked. I was too afraid to let people think I hadn’t thought things through before asking.

The project continued to the next year’s students. At first, my teacher asked me to help them. However, they didn’t need help and there was nothing I could help with. Looking back in 2026, the N extension was deprecated a long time ago, replaced by the Advanced Interrupt Architecture ratified in 2023.

2025

I read an article called RISC-V single-board computer for less than 40 euros (via) in August 2025. I learnt that StarFive would launch a crowdfunding campaign on Kickstarter for a cheap quad-core SiFive U74 (RV64GC instruction set, also known as RV64IMAFDC_Zicsr_Zifencei) development board. The unfinished things from 2021 suddenly rushed back to my head, the idea of continuing to develop a RISC-V OS came back to my mind, the vision of successfully running my own OS on the board played out vividly before my eyes…I backed the campaign, and received a small parcel on 11/11/2025.

Soul, Breath, and the Trinity Processor

According to Orphism, Zeus hurled his lightning at the Titans after learning that they had killed the young Dionysus (bearing the name of Zagreus). Then, humans were born with the sinful flesh of the Titans, and the innocent soul of Zagreus. That’s why humans need redemption from their Titanic bodies, to experience the purification of their Dionysian souls.

The soul here is ψυχή/Psyche. There’s another similar word, πνεῦμα/Pneuma, which originally meant breath. It’s easy to understand: breath is what only living creatures have. It was not unusual for ancient cultures to hold more than a simple mind-body dualism. The Chinese had three ‘Hun’ and seven ‘Po’ for souls, while the west also had more than one soul:

And the very God of peace sanctify you wholly; and I pray God your whole spirit (pneuma) and soul (psyche) and body (soma) be preserved blameless unto the coming of our Lord Jesus Christ.

A wallpaper showing Trinity Processor

Nonetheless, I want to introduce the name of my thrice-born OS, using the story of thrice-born Dionysus. During its first eight months, it was called ‘RV’, only to show its underlying instruction set. I have to come up with a name for the sake of this article, as a placeholder won’t do. Looking back at the name of my (also unfinished) 2021 CPU: Ousia, I decided to follow the naming convention at the time, which is choosing names from the Trinity Processors in Xenoblade Chronicles. The Trinity Processors have three parts, called ουσία/Ousia, λόγος/Logos, and πνεῦμα/Pneuma. Given that I’ve used Ousia, and Logos sounds like a drawing programming language featuring a turtle, Pneuma would be the name of the OS.

The code of Pneuma is published at my Forgejo. The latest commit while writing the Chinese version of this article was 5afb7debd1.

The Soul of a New Machine

The ad on the first page of the first issue of Byte magazine: Step right up and join the society for computer professionals

Four years had passed from 2021 to 2025. I had transformed from a student curious about new languages like Rust to a professional C++ engineer. Although I can call myself a professional because I have a full-time job writing C++, I didn’t look professional enough, like the man in the suit with his briefcase in the ad. What’s worse, I can’t say I fully mastered C++: I don’t have grey beard, and I’m not in the committee.

In my defence: It’s not that I don’t want to write idiomatic modern C++, it’s the aging codebase and the conservative compiler flag policy in my company forbidding me to use the most advanced, trending, beloved C++ style. The strain of writing C++ by day and hating myself for not mastering C++ at night made Rust no longer appealing for writing my OS. Coincidentally, I had bookmarked a new online textbook called Operating System in 1,000 Lines (via, abbreviated as OS in 1k Lines below), which teaches you to write a RISC-V OS in 1k lines of C. I was skeptical before opening the book, given that the last time I encountered a similar title was with Writing an editor in less than 1000 lines of code, just for fun. An OS is surely more complex than an editor, right?

I was proven to be wrong. The OS implemented in OS in 1k Lines was incredibly simple. For example, the memory allocation policy was first come, first served, without the ability to free memory; it fills the page table entirely and immediately upon creating a new process; the way to load user programs is simply objcopy-ing the prebuilt binaries to the linker symbols of the kernel; there’s no timer interrupt, and the user programs must cooperatively yield the CPU by calling yield()…The most surprising fact about that minimal OS was it supports a file system (FS). Not ext2, nor FAT, but TAR, for tapes!

That’s exactly the reason why I love that book: it taught me an OS can lack many seemingly essential functionalities, giving me a platform to implement them my own way. By comparison, the textbook I referenced in 2020 and 2021 (rCore-Tutorial-Book) was detailed to a degree that was confusing to its readers: it not only taught you how to delay memory allocation via page faults, but also how to hide the freeing process in a Rust trait. It even taught you the history of OS. The funniest thing I found when re-reading it in 2025 was that the author had added new content: they mapped the iconic creatures of the Cambrian, Devonian, Permian, …, all the way to the so-called 21st century ‘Homo Deus era’, onto the history of OS:

…The monitor program is the earliest prototype of an operating system, similar to the famous creature of the Cambrian explosion—the ‘trilobite’…The simple batch processing operating system can only manage one job in memory at a time, unable to fully utilise all the resources of large computer systems, resulting in poor overall system performance. This is like the prehistoric Devonian fish—Dunkleosteus, with its hard cranial armour, very powerful, but slow-moving, with low agility, unable to leave water… Due to its early widespread adoption, it has become the paradigm of time-sharing operating systems. This resembles a small dinosaur from the Late Jurassic—Archaeopteryx, which may be the ancestor of birds, eventually evolving into birds that could soar with their wings spread…

I’m not advocating that tutorials shouldn’t have personal touches, I’m just saying there are too many of them in the rCore Tutorial, and they’re too heavy-handed. The goal of a tutorial should be answering readers’ questions, not the opposite. A better OS book with an abundance of personal touches is Operating Systems: Three Easy Pieces. Look how the author introduces CPU virtualisation:

Student: So you are sharing the peach, but you don’t even know it?
Professor: Right! Exactly.
Student: But there’s only one peach.
Professor: Yes. And...?
Student: Well, if I was sharing a peach with somebody else, I think I would notice.
Professor: Ah yes! Good point. But that is the thing with many eaters; most of the time they are napping or doing something else, and thus, you can snatch that peach away and give it to someone else for a while. And thus we create the illusion of many virtual peaches, one peach for each person!
Student: Sounds like a bad campaign slogan. You are talking about computers, right Professor?

The metaphor of peaches reoccurred several times in later chapters’ dialogues. It makes readers laugh rather than scratch their heads, because the analogies are apt.

Master of DOOM

After completing the minimal and rudimentary OS described in OS in 1k Lines, I converted it to C++, and added support for 64-bit CPUs. Although the end goal is porting Pneuma to the StarFive board, the road is long and winding. I plan to finish a side quest first: port the 1993 DOOM to Pneuma.

DOOM wasn’t the first first-person shooter (FPS) game. However, given how successful it was, the FPS genre was called DOOM clones for a long time. The developer id Software open sourced its engine in 1997. Then, fans ported this game to a plethora of devices: Calculator, Cash Machine, Pregnancy Test, HDMI Adaptor, PDF, E. Coli……We can even say that porting DOOM is the ‘Hello World’ of graphics.

That said, my interest in DOOM originates from the biography of id Software, a book called Masters of DOOM. Reading that book was like injecting a bag of stimulants directly into your veins (my book review was ‘it was the purest stimulant you can buy legally’). Once upon a time when Intel produced CISC and RISC CPUs at the same time, when LAN was connected by coaxial cables, when the Internet was accessed by telephone lines, everything was in bloom, and the developers at id Software radiated a brazen, audacious energy. I was in awe of that spirit, so alien to this century, and began to revere DOOM.

Of course, there are obstacles to porting DOOM to Pneuma. The first one is that DOOM needs the C standard library (libc), while my OS doesn’t even meet the requirements for a libc: Pneuma can’t allocate and free memory in user space; TAR isn’t a usable FS, making it hard to support file operations in libc. For the former, a workaround is leaving a fixed 4MB space for every user program, reserved for malloc and free, so that I wouldn’t need to implement syscalls like mmap or sbrk for dynamic memory allocation. For the latter, please forgive me: I have no interest in FSes, so I instructed Claude to embed FatFs (an easy-to-port FS) into my implementation of libc.

In March 2026, I implemented virtio-gpu and virtio-input drivers for Pneuma. Then it could display graphics and read keyboard input in QEMU. I still remember the satisfaction of initialising the screen to pure blue, after I finished the virtio-gpu driver on 08/03/2026. The blue screen represents system faults on Windows, while here it meant Pneuma finally had the ability to show graphics.

The next day (09/03), I connected the SYS_GPU_FLUSH syscall to the DOOM callback, and saw the ‘double vision’ shown at the beginning of the article. Although it was a bug, it was also cool. The reason was that the graphic buffer address was not aligned to the page frame, while my driver assumed they were aligned. Soon the bug was resolved, and I became the Doom Guy via the keyboard.

The Thrice-Greatest Hermes

One of the responsibilities of Hermes is leading the soul/psycheψυχή of the dead into the underworld. He was soon associated with travelling and communication because of his ability to cross the boundary of life and death, making him a messenger among the Greek gods. Interestingly, Greeks in the Ptolemaic era associated him with the Egyptian god of wisdom and magic, Thoth, borrowing the latter’s epithet ‘Greatest, Greatest, Greatest’, creating the name ‘Hermes Trismegistus’ (Hermes the Thrice-Greatest). In the 21st century, Hermes was also given the responsibility of crossing the boundary of OS processes.

Hermes Trismegistus appears in Historia Deorum Fatidicorum, Vatum, Sibyllarum, Phoebadum, Apud Priscos Illustrium: Cum Eorum Iconibus; Præposita Est Dissertatio de Divinatione Et Oraculis

Back to my Pneuma OS: I was obviously happy after being able to play DOOM on Pneuma, but my other programs using disk stopped working. This was because I had embedded FatFs into every program via my libc. Multiple instances of FatFs don’t co-operate, and the end result would be file corruption.

How to make Pneuma great again? There are three ways:

  1. Modify FatFs, sharing state between its multiple instances.
  2. Move FatFs into the kernel, letting user programs access disk via syscalls.
  3. Keep FatFs in user-level, but have it act as a server. Let the FatFs server proxy all other processes’ requests.

The problem with the first two solutions is that I have no interest in FSes. I don’t want to modify FatFs, nor put it in my kernel. The problem with the third way is that I need to implement Inter-Process Communication (IPC), like Hermes crossing the boundary of processes.

To be honest, I didn’t know how to design IPC. At first I wanted to take inspiration from seL4, but the Capability concept made it hard to start. What about Xinu? It was my most referenced teaching OS after finishing OS in 1k Lines, but I didn’t understand why it needs two sets of IPC primitives. Actually, IPC can also be called Message Passing, and I remember learning about it in a class called Message Passing Programming. What was the framework used in that class? It was Message Passing Interface.

In the end, I created a synchronised sending syscall called ssend and a synchronised receiving syscall called recv, mimicking MPI_Ssend and MPI_Recv. Then I instructed Claude to turn all the file operations in libc into IPC calls to the new FatFs server. At any given moment, there would be only one process accessing disk, solving the concurrency problem of multiple instances of FatFs.

There’s a huge performance cost though: The clients could do something else if they had an asynchronous communication method, like MPI_Bsend; the file server could also buffer more requests before asking the kernel to deal with them, saving the cost of constant context switching…However, I don’t mind.

Blueprint for a Slow Machine

In 2016, a small developer shop called Hello Games released a game called No Man’s Sky. Upon release, it received lots of negative reviews from gamers and media, because the advertised 1.8×1019 unique planets were all the same and dull. In short, there wasn’t much to play in the game. Ironically, I love that game, so much so that I prefer No Man’s Sky to the critically acclaimed rebooted DOOM, which was released in the same year. I love the emptiness of the universe. If it were as bustling as a farmer’s market, would it still be the infinite universe?

In 2026, I dusted off the soundtrack album of No Man’s Sky, called No Man’s Sky: Music for an Infinite Universe. The ethereal and slowly building Heliosphere took me back to the moment of waking up on an alien planet. The emotionally undulating Blueprint for a Slow Machine, gently narrating, melancholic yet grand, spoke of the long, lonely hours of drifting through galaxies alone…

Attempting to implement an OS made me feel six years younger, taking me back to the summer vacation of 2020. The weakness of my syscall design throttled performance, but that’s not what I care about. If I wanted performance, I wouldn’t write an OS from scratch; contributing to Linux or seL4 would be more beneficial. My blueprint is indeed for a slow machine, a machine of my own, and that’s what I truly care about.

In fact, this article is called Blueprint for a Slow Machine because the song reminded me of the days I spent drifting through the boundless void. I love doing what I want to do, regardless of how useful it is. I am obsessed with implementing a slow OS, just like the ancient Greeks were obsessed with wine. Maybe it’s inappropriate to liken Pneuma to Dionysus. The computer is my true Dionysus.