For the past 8 months, or so, I've been working on a project to create a Linux-compatible kernel in nothing but Rust and assembly. I finally feel as though I have enough written that I'd like to share it with the community!
I'm currently targeting the ARM64 arch, as that's what I know best. It runs on qemu as well as various dev boards that I've got lying around (pi4, jetson nano, AMD Kria, imx8, etc). It has enough implemented to run most BusyBox commands on the console.
Major things that are missing at the moment: decent FS driver (only fat32 RO at the moment), and no networking support.
Cool project, congrats. I like the idea with libkernel which makes debugging easier before going to "hardware". It's like the advantages of a microkernel achievable in a monolithic kernel, without the huge size of LKL, UML or rump kernels. Isn't Rust async/awat depending on runtime and OS features? Using it in the kernel sounds like an complex bootstrap challenge.
Rust's async-await is executor-agnostic and runs entirely in userspace. It is just syntax-sugar for Futures as state machines, where "await points" are your states.
An executor (I think this is what you meant by runtime) is nothing special and doesn't need to be tied to OS features at all. You can poll and run futures in a single thread. It's just something that holds and runs futures to completion.
Not very different from an OS scheduler, except it is cooperative instead of preemptive. It's a drop in the ocean of kernel complexities.
Ok, I see. I spent a lot of time with .Net VMs, where you cannot simply separate await from the heavy machinery that runs it. I now understand that in a kernel context, you don't need a complex runtime like Tokio. But you still need a way to wake the executor up when hardware does something (like a disk interrupt); but this indeed is not a runtime dependency.
Yeah, for example embassy-rs is an RTOS that uses rust async on tiny microcontrollers. You can hook task execution up to a main loop and interrupts pretty easily. (And RTIC is another, more radically simple version which also uses async but just runs everything in interrupt handlers and uses the interrupt priority and nesting capability of most micros to do the scheduling)
There’s got to be some complexity within the executor implementation though I imagine as I believe you have to suspend and resume execution of the calling thread which can be non-trivial.
Really neat. Do you have any specific long term goals for it? Eg, provide an OS distro (using Linux drivers?) to provides memory safety for security-critical contexts?
Also, are there any opportunities to make this kernel significantly faster than Linux’s?
While it's very legitimate question, the answer is between the lines in the README, and it mostly means that there is a user space binary compatibility for everything that is implemented.
It might seem obscure, but syscalls to get access to kernel requires a tight integration on compilation and linking. So this is their approach and this is where the compatibility really means something : since you can cross compile on another machine, they don't need the full toolchain right away. Just compile your code on a linux machine, and run it there. You're at the mercy of all missing kernel API implementations, but it looks like a very good strategy if you aim is to code a kernel, as you only have to focus on actual syscalls implementation without getting distracted by toolchain.
Hello!
For the past 8 months, or so, I've been working on a project to create a Linux-compatible kernel in nothing but Rust and assembly. I finally feel as though I have enough written that I'd like to share it with the community!
I'm currently targeting the ARM64 arch, as that's what I know best. It runs on qemu as well as various dev boards that I've got lying around (pi4, jetson nano, AMD Kria, imx8, etc). It has enough implemented to run most BusyBox commands on the console.
Major things that are missing at the moment: decent FS driver (only fat32 RO at the moment), and no networking support.
More info is on the github readme.
https://github.com/hexagonal-sun/moss
Comments & contributions welcome!
Cool project, congrats. I like the idea with libkernel which makes debugging easier before going to "hardware". It's like the advantages of a microkernel achievable in a monolithic kernel, without the huge size of LKL, UML or rump kernels. Isn't Rust async/awat depending on runtime and OS features? Using it in the kernel sounds like an complex bootstrap challenge.
Rust's async-await is executor-agnostic and runs entirely in userspace. It is just syntax-sugar for Futures as state machines, where "await points" are your states.
An executor (I think this is what you meant by runtime) is nothing special and doesn't need to be tied to OS features at all. You can poll and run futures in a single thread. It's just something that holds and runs futures to completion.
Not very different from an OS scheduler, except it is cooperative instead of preemptive. It's a drop in the ocean of kernel complexities.
Ok, I see. I spent a lot of time with .Net VMs, where you cannot simply separate await from the heavy machinery that runs it. I now understand that in a kernel context, you don't need a complex runtime like Tokio. But you still need a way to wake the executor up when hardware does something (like a disk interrupt); but this indeed is not a runtime dependency.
EDIT: just found this source which explains in detail how it works: https://os.phil-opp.com/async-await/
Yeah, for example embassy-rs is an RTOS that uses rust async on tiny microcontrollers. You can hook task execution up to a main loop and interrupts pretty easily. (And RTIC is another, more radically simple version which also uses async but just runs everything in interrupt handlers and uses the interrupt priority and nesting capability of most micros to do the scheduling)
Interesting references, thanks. Moss seems to be doing the same thing as Embassy.
There’s got to be some complexity within the executor implementation though I imagine as I believe you have to suspend and resume execution of the calling thread which can be non-trivial.
Impressive work! Do you have any goals, other than learning and having fun?
Also how does it's design compare with Redox and Asterinas?
shouldn't this be a ShowHN?
Very cool project! I do have to admit - looking far, far into the future - I am a bit scared of a Linux ABI-compatible kernel with an MIT license.
Really neat. Do you have any specific long term goals for it? Eg, provide an OS distro (using Linux drivers?) to provides memory safety for security-critical contexts?
Also, are there any opportunities to make this kernel significantly faster than Linux’s?
In what extent is this compatible with Linux?
Could I swap Ubuntu's or Android's kernel with this, while keeping those OSes bootable?
While it's very legitimate question, the answer is between the lines in the README, and it mostly means that there is a user space binary compatibility for everything that is implemented.
It might seem obscure, but syscalls to get access to kernel requires a tight integration on compilation and linking. So this is their approach and this is where the compatibility really means something : since you can cross compile on another machine, they don't need the full toolchain right away. Just compile your code on a linux machine, and run it there. You're at the mercy of all missing kernel API implementations, but it looks like a very good strategy if you aim is to code a kernel, as you only have to focus on actual syscalls implementation without getting distracted by toolchain.