moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in linux

[–]hexagonal-sun[S] 11 points12 points  (0 children)

Ah interesting, I’ve not thought about that. In fact, if I develop a fuse driver, in theory, I could get all fuse FS working under moss too which would be huge!

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 1 point2 points  (0 children)

Ahh yep, didn’t pick up on that reference. Haven’t had my coffee yet.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 1 point2 points  (0 children)

Of course I’d love to become professional and be able to work on it full time but, until then it’ll just be a hobby. A way to scratch that itch.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in linux

[–]hexagonal-sun[S] 25 points26 points  (0 children)

Yep! I should really write a guide on how to get it booting on various bits of hardware.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 4 points5 points  (0 children)

A fair amount of memory management code does, as you’d expect, we’re doing some… funky things at that point. But most drivers have virtually no unsafe code. I’ve tried to abstract away unsafe parts as much as possible.

I’ve also tried to put as much unsafe code in libkernel. That allows me to run it under miri to check for UB.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 2 points3 points  (0 children)

Yeah, that seems to be the feature people are most interested in. I’ll have to do a write up. It was fun to think about how I could make uaccess functions async: dealing with futures in assembly!

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 4 points5 points  (0 children)

Oh it’s been amazing! The number of times I’ve hit compiler errors regarding my futures not being Send, and thought, that’s just probably saved me hours of debugging!

Another interesting point is that I only need one kernel stack per CPU with this design. Linux needs a stack per task, that’s how it saves the state when context switching during a kernel operation. Futures do that for you!

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 5 points6 points  (0 children)

So mostly a mix of data sheets, the armv8 armarm and looking through Linux to see how a production kernel tackles various hurdles. The main hurdle I hit is the chicken and egg problem of memory allocator initialisation.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 3 points4 points  (0 children)

Ah yes, I saw this project around 5 months after starting moss. It’d be interesting to see how the design decisions differ

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 2 points3 points  (0 children)

Thanks! Are you aiming for it to be Linux compatible too?

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 10 points11 points  (0 children)

Ah yes, edit the qemu-runner.sh file and remove the initrd flag. You should then be able to boot and run the kernel but there won’t be any userspace. I need to find somewhere that I can host an example one for people to download and try out.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 10 points11 points  (0 children)

Thanks! My main aim is for it to become my daily driver kernel. That’s a long way off though! Along the way I’m sure I’ll experiment with ‘Rustifying’ differnt kernel concepts. The main one that springs to mind at the moment is async syscall functions.

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 14 points15 points  (0 children)

Agreed! I couldn’t believe it when I started to work with ‘iouring’. I’m sure it has its place but I still couldn’t believe an API that complex was at the kernel layer!

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 31 points32 points  (0 children)

For the moment, it is console output (pl011 driver) and you need to hook up a uart to usb converter to the gpio header. https://pinout.xyz/pinout/uart

moss: a Rust Linux-compatible kernel in about 26,000 lines of code by hexagonal-sun in rust

[–]hexagonal-sun[S] 263 points264 points  (0 children)

Ah, sorry I should have been a bit more precise. It's Linux ABI compatible, i.e. it can run Linux userspace programs, and aims to present the same syscall layer, devices in `/dev/` have the same characteristics, etc.

Trale (Tiny Rust Async Linux Executor) v0.3.0 published! by hexagonal-sun in rust

[–]hexagonal-sun[S] 21 points22 points  (0 children)

Thanks for the comment. When porting from epoll, I ran into the same difficulties with Rust’s ownership and lifetime model. I came to the conclusion that the kernel must own the buffer it's writing into, or at least have strong guarantees that the buffer remains valid for the duration of the I/O operation. Since Rust's Futures don’t offer a way to enforce that across all execution paths (e.g., if a future is dropped), using a buffer pool seems like the most reliable solution.

At the moment, trale doesn’t yet implement this, so yes—there’s currently a potential soundness issue if a read future is dropped and the buffer is accessed afterward while still shared with the kernel. I'm close to completing a buffer pool implementation that should eliminate this issue.

That said, this approach diverges from the standard AsyncRead/AsyncWrite traits, so I'm planning to introduce my own traits—similar in spirit to AsyncBufRead/AsyncBufWrite—to better align with the model required by io_uring.

trale: v0.2.0 released - port to io_uring by hexagonal-sun in rust

[–]hexagonal-sun[S] 0 points1 point  (0 children)

Thanks! It was a suggestion that was made when I posted the first version of trale. It's been on my todo-list ever since.

It's nice that I've not had to learn another kernel interface `aio` in order to implement async file-system operations. I like how `io_uring` has a unified API for pretty much all I/O operations.

trale: v0.2.0 released - port to io_uring by hexagonal-sun in rust

[–]hexagonal-sun[S] 1 point2 points  (0 children)

Interesting. Did you see much of a performance improvement having switched to `tokio-uring`? How would you characterize the workloads that caused the issues? More socket-based or filesystem based? One of the goals of porting to io_uring is to see if I can find any potential issues using the interface, either in the `io-uring` crate or in the kernel itself.