Skip to content
This repository has been archived by the owner on Oct 11, 2020. It is now read-only.

Strategy

Connor Kuehl edited this page Oct 11, 2018 · 2 revisions

Strategy

So how do we port an operating system from C to Rust? Carefully, of course.

The following strategy depends on a breadth-first, iterative approach. I say "breadth-first" because we want as much of the code ported to Rust before we shape the code base into a more "idiomatic" rendition. This way, the more code that the Rust compiler is responsible for, the more likely we are to benefit from Rust's compile-time guarantees. A broad exposure to the code base will also help cultivate a better understanding of how the operating system works so that we can better identify pressure-points ripe for refactoring later.

Phase 1

  1. Select a module to begin porting to Rust. Ideally, this is a module with few other dependencies (or better yet, the dependencies have already been ported to Rust). Create a corresponding Rust source file underneath the src/ root. Expose the module you just made in src/lib.rs (pub mod uart).

  2. Choose a function within the module that you have selected.

  3. Port this function as verbatim as possible (this will be unsafe, of course); using #[no_mangle]. Rust's Foreign Function Interface (FFI) will allow the C code to call this newly ported function. If this function has dependencies which have not been ported, extern them in the appropriate corresponding Rust module (or do it in the same module you're using, so long as that dependency is not used by anyone else).

  4. Remove this function from the C code base. Update any part of the C code base where this function is included to be extern as it is defined in our Rust code base now (check header files, etc). If that was the last function within the module, remove its C source file and delete the referenced compilation unit from the build system (Makefile).

  5. Test the operating system as rigorously as possible. With a clean rebuild, the operating system should boot and successfully run through the usertests program in xv6.

  6. Repeat the previous steps until all of the C code has been ported to unsafe Rust.

Phase 2

Once Phase 1 is complete, the hard part begins. We need to refactor parts of the code base to create safe abstractions (shrinking the needed unsafe blocks as much as possible).

This phase is just as breadth-first and iterative as the first phase.

  1. Select a module. This will be easier if it's self-sufficient (i.e., no dependencies).

  2. Refactor a function such that it is no longer labelled unsafe and its interior unsafe blocks are as small as possible.

  3. Test the operating system as rigorously as possible. With a clean rebuild, the operating system should boot and successfully run through the usertests program in xv6.

  4. Repeat the previous steps until as much of the code base's unsafe blocks have been shrunk as far as they can.

Phase 3

Armed with as many safe abstractions as we were able to suss out, begin ruthlessly criticizing the code base and shaping it to use Rust idioms. This might help reduce the unsafe code further, too.

As always, one function at a time while also rigorously testing the operating system and ensuring usertests pass.

We are not making drastic changes to how xv6 behaves, as it is supposed to be a faithful port (i.e., not writing a new scheduler).

Clone this wiki locally