Recently, work on mnemos has started up again, and we have made a pretty exciting amount of progress in a relatively short amount of time.
This is a recap (or introduction!) of where I left off with mnemos at the end of 2022.
What is mnemos?
mnemos is a hobby-grade OS, written in Rust. I started writing it to learn more about operating system development, and to see how far I could push Rust to make it easier to write an operating system.
From a "hopes and dreams" perspective
I'm hoping mnemos will help for projects that exist in the liminal space between "too big/complicated for bare metal or a simple RTOS", and "too small/underpowered/time critical for Linux".
I've found a lot of projects that need things that are often challenging to do well with an RTOS, like:
- Non-trivial networking capabilities, including over the air updates
- Complex User Interfaces, like high resolution displays, touch screens, or keyboards
- Running portable, isolated, or (over the air) upgrade-able applications and drivers
- Running on more powerful or complex hardware, like Cortex-A or 64-bit RISC-V CPUs
At the same time, I've also found that many of these projects are ALSO challenging to do well in Linux, as they also often need:
- Low level control of niche hardware accessories, like sensors or motor controllers
- Relatively demanding soft/firm real-time deadlines
- Power optimization for battery-powered devices
I'm not saying you can't do these things in either Linux or an RTOS! But it often requires fairly specialist knowledge of either system to approach, and if you find yourself needing to switch from one domain to the other, or support similar products with different foundations, it can be challenging to live in this "between space".
I'm hoping that mnemos can live in that area: customizable enough when you need it to be, and with enough "batteries included" that writing something that feels special doesn't require a specialist.
From a "technical novelties" perspective
Mnemos' kernel exists primarily as a cooperative async executor, with message passing as the primary means of interactions between "kernel services", like drivers, and provides a "service discovery" interface for working with abstract and dynamic driver implementations.
It also (aims) to present an io_uring-like userspace/kernel interface, allowing userspace applications to interact with the kernel through the same message passing model. It is intended that userspace applications are also async, meaning that applications can efficiently await responses from the kernel, often pipelining many system call requests into a single context switch.
The kernel itself is "just a plain,
no_std Rust library crate". This means dropping
it onto any hardware platform isn't meaningfully more complex than writing any
"bare metal" application today.
For "big microcontrollers", like a high powered chip from NXP, STMicro, or Espressif, I could see running JUST the kernel, similar to how BSD "rump kernels" work, or potentially with a single userspace program. In these cases, having more limited features, like no Memory Management Unit, or only 256KiB to 8MiB of RAM, would be acceptable.
For "small processors", including low cost/low power ARM Cortex-A or RISC-V CPUs, I hope to make it easier to support the "bring up" process. This will allow for getting to a multi-processing and more dynamic environment quickly.
For both processors and microcontrollers, I want the bring-up process to feel familiar for folks already comfortable in writing embedded Rust code.
For microcontroller environments, this might mean being able to directly use async HALs and component drivers like those from the popular Embassy framework.
For processor environments, I'm hoping that folks who already have experience with Embassy (or other async environments) will feel comfortable writing drivers for larger and more powerful chips.
From an "actual current status" perspective
Some things work already!
mnemos has a simulator,
melpomene, which can run the kernel and its
executor as a desktop application.
The service discovery and abstract driver interface exists, which I've used to implement drivers for the simulator, such as using the embedded-graphics simulator library to act as a virtual display, as well as mapping TCP ports on the host to virtual serial ports in the kernel.
I also started porting the OS to run on our first hardware target, the Allwinner D1, a 1GHz, 64-bit, single core RISC-V processor.
But in the scale of things, it is FAR from production ready, and honestly still a little hard to use even as a test bed. There are lots of things to be built, but no way to play with it! This is part of why my activity on the project fell off at the end of last year, it was getting to be more work than fun.
It has been sitting on the shelf for the last couple of months, waiting for new inspiration.
New Motivation, New Goals
Recently, there have been a lot of new "slab computers" that have been announced, which in my opinion is the perfect form factor for mnemos, with full(-ish) keyboards, screens, batteries, and wifi.
In particular, the uConsole from Clockwork Pi and the beepberry from beeper x SQFMI:
I’m excited to introduce a little side project I’ve been working on: Beepberry - a portable e-paper computer for hackers, designed for chatting on Beeper. It’s available today to pre-order for $79. It’s a partnership between me (@onbeeper) and @sqfmi: https://t.co/hIZRQMTrvr— Eric Migicovsky (@ericmigi) May 17, 2023
Both of these devices can be customized to use the same RISC-V Allwinner D1 processor shown above, and the beepberry even uses the same screen!
Having all of these capabilities in a package that can be easily carried around also makes it easier to hit two important emotional goals for me:
First — Moving from a mostly-simulated environment to a real physical environment means it is more fun to play with the device, which should hopefully be inspiring to add more functionality, like designing fun user interfaces, talking over the network with wifi, and even writing and running scripts directly on the device.
Second — Being able to load/write/run scripts directly on the device also "crosses the rubicon" between being an embedded system: something built for a specific and limited purpose; and being a computer: something general purpose that allows you to build things not originally imagined when designing the OS itself.
On the next episode...
Now that we've covered the history and some hopes and dreams of mnemos, the next post will detail how we're working on getting the first "shell environment" up and running on mnemos.
Interesting in hacking on mnemos, or think it could fit something you need to do in the future? Let me know, I'm always happy to chat.
Need help with building something (else) in Rust? Maybe I can help!.