Rust OSDev Operating System Development in Rust

This Month in Rust OSDev (September 2020)

Welcome to a new issue of "This Month in Rust OSDev". In these posts, we will give a regular overview of notable changes in the Rust operating system development ecosystem.

This series is openly developed on GitHub. Feel free to open pull requests there with content you would like to see in the next issue. If you find some issues on this page, please report them by creating an issue.

Project Updates

In this section, we give an overview of notable changes to the projects hosted under the rust-osdev organization.

acpi

The acpi repository contains crates for parsing the ACPI tables – data structures that the firmware of modern computers use to relay information about the hardware to the OS. Lots of work happened this month:

  • Support for the Fixed Memory, Word Address Space, DWord Address Space, QWord Address Space, IRQ Format, DMA Format, and I/O Port Descriptor resource descriptors were added. These appear in _CRS objects - objects that describe the resources allocated to a particular hardware device. This should be enough support to parse the _CRS objects of all devices supported by QEMU. Thanks to @michaelmelanson for his contribution!
  • Version 2.0.0 of the acpi crate was published, after consultation with contributors to the Redox project. This splits the library into two parts - discovering ACPI tables using various methods, and separately, parsing them to discover information about the system. This provides much more flexibility in how tables are parsed, allows support for OS-specific tables, and is important to the Redox project as it allows parsing of the ACPI tables in userspace. We also used this opportunity for breaking changes to clean up a few parts of the library, especially in making our method of mapping physical memory ranges safer.
  • A new crate, rsdp, was split out from acpi. This new crate provides methods for searching for the first ACPI table (the Root System Description Pointer (RSDP)) on BIOS systems without alloc support. This makes it suitable for use from bootloaders and similar applications where heap allocation is not supported. All types are reexported by the acpi crate, so users can access the same functionality from the main library.

x86_64

The x86_64 crate provides various abstractions for x86_64 systems, including wrappers for CPU instructions, access to processor-specific registers, and abstraction types for architecture-specific structures such as page tables and descriptor tables.

The crate received the following updates in September:

Thanks to @ecstatic-morse, @toku-sa-n, @h33p, and @josephlr for their contributions!

We would also like to welcome @josephlr to our x86_64 review and maintenance team!

volatile

The volatile crate provides safe wrapper types for implementing volatile read and write operations. This month, we published version 0.4.0, which completely rewrites the crate based on reference values. Instead of wrapping the target value directly as e.g. Volatile<u32>, the new implementation works by wrapping reference types such as Volatile<&mut u32>. See our completely revamped documentation for more details.

The main advantage of the new reference-based implementation is that it is now possible to work with volatile arrays and slices, at least on nightly Rust. Through the index and index_mut methods it is possible to create sub-slices, which can then be read and written efficiently through the copy_into_slice and copy_from_slice methods. All these operations perform volatile memory accesses, so that the compiler won't optimize them away.

pci_types

pci_types is a new library in the Rust OSDev organisation that provides types for accessing and configuring PCI devices from Rust operating systems. Lots of this code (e.g. identifying devices by class codes) can be shared between projects, and would benefit from community contributions. This month, work started on some types for representing PCIe addresses, the layout of the configuration space for endpoints, device types, and a trait that allows the library to access the PCIe configuration space in whichever way the platform exposes it.

Thanks to @toku-sa-n for their contribution!

uefi-rs

The uefi-rs crate provides safe and performant wrappers for UEFI, the successor to the BIOS. In September, the crate was updated to Rust's new inline assembly implementation. We also published version 0.6.0 of the crate, including all the improvements added in the past two months.

Thanks to @toku-sa-n for their contribution!

bootloader

The bootloader crate implements a custom Rust-based bootloader for easy loading of 64-bit ELF executables. This month, we published versions 0.9.9 to 0.9.11 to fix build errors on the latest nightlies, caused by the new feature gate names for some const fn features.

We also made some more progress on the rewrite with UEFI support. It now passes additional framebuffer information and the address of the RSDP structure of ACPI in the boot info. (We later updated the RSDP code to use the new rsdp crate). The bootloader also gained support for setting up a recursive page table mapping, which makes it almost feature-equivalent with the current implementation. There are still a few things missing, but it should be ready to be published soon.

cargo-xbuild

The cargo-xbuild project provides cargo command wrappers to cross-compile the sysroot crates core and alloc. This month, we merged some maintenance updates to increase platform compatibility:

Thanks to @pfmooney for these contributions!

Even though we still maintain the cargo-xbuild crate, we recommend switching to cargo's own build-std feature that is always up-to-date with the latest Rust/Cargo changes. We wrote a short guide on how to switch to it, which is available in our Readme.

uart_16550

The uart_16550 crate provides basic support for serial port I/O for 16550-compatible UARTs. Like the x86_64 and bootloader crates, this crate received some dependency updates this month to fix nightly breakage. In the process, we released versions 0.2.8 to 0.2.10. Since none of these versions are semver-breaking, a normal cargo update should suffice to update to the latest version.

Personal Projects

In this section, we describe updates to personal projects that are not directly related to the rust-osdev organization. Feel free to create a pull request with the updates of your OS project for the next post.

IsaacWoods/pebble

(Section written by @IsaacWoods)

A fairly large amount of progress has been made on Pebble over the last two months, and a prototype of Pebble's defining feature (easy message passing between tasks) is now working!

  • The first, basic, version of Pebble's wire format, ptah has been completed. This first version is implemented as a Serde format, but libraries could be written for any language that can manipulate a byte stream.
  • Two system calls, send_message and get_message, were added that allows a message (a series of bytes, and optionally a number of handles (effectively, permission to access a certain kernel object)) to be sent down a channel, between two tasks.
  • Infrastructure for another of Pebble's key features, services, was added. This allows userspace tasks to advertise their ability to provide some kind of 'service' to other tasks. A task called echo was built to test this - it provides a service that simply echos any messages sent down it back to the sending task.
  • Work started on the Platform Bus, a concept inspired by another hobby OS managarm's mbus. All hardware devices on the platform will be added to the Platform Bus by Bus Drivers, and described using properties (as an example, a PCI device will have properties such as pci.vendor_id, and pci.class). Device drivers will be able to apply to manage devices by sending a Filter to the Platform Bus, which specifies which devices they are able to handle, based on a device's properties. In the future, Platform Bus will be responsible for handling all PCI, USB, and hardwired devices on all platforms.
  • The first Bus Driver was added to manage PCI devices. It uses a new system call, pci_get_info, to get the raw information about PCI from the kernel, and then creates a Platform Bus device for each function, with the correct properties. It uses the new pci_types library in the Rust OSDev organisation to identify each device (in the future, this will be extended to know about specific vendor+device ID combinations, to identify specific devices such as a particular graphics card).

phil-opp/blog_os

(Section written by @phil-opp)

This month, the "Writing an OS in Rust" blog received a few minor updates:

Apart from that, I did a lot of preparation for the upcoming switch to the UEFI bootloader. My prototype implementation of the blog_os system on top of the new UEFI bootloader has now reached feature parity with the existing implementation:

QEMU output of new bootloader implementation, including local APIC and I/O APIC debug output, the timer interrupt dots, and the keyboard input "Hello!!!"

The output looks different now because we are using a pixel based framebuffer instead of the VGA text mode. This is required because the VGA text mode is no longer supported with UEFI. For the framebuffer implementation I'm using the new version of the volatile crate and the font8x8 crate for font rendering.

You can also see some log output related to the APIC interrupt controller (not to be confused with the ACPI standard). I'm using the APIC instead of the legacy PIC because the latter is not supported anymore on most UEFI systems. For that, I started working on a new apic crate, which will include abstractions for the registers of the local APIC and the IOAPIC.

For the coming month(s), I'm planning to revamp the "Writing an OS in Rust" blog based on this prototype implementation. This will require complete rewrites of the VGA Text Mode and Hardware Interrupts posts, an update of the bootloader build process in A Minimal Rust Kernel, and replacing the QEMU screenshots across all posts. So I expect that it will take some time until the new version is ready.

andre-richter/qemu-exit

(Section written by @andre-richter)

Version 1.0.x of the crate has been released!

qemu-exit is a crate that allows you quit a running QEMU session with a user-defined exit code. This is useful for unit or integration tests of bare-metal software (e.g. OS kernels) that are tested in QEMU.

The crate supports the following architectures:

  • AArch64
  • RISC-V 64
  • x86_64

If you want to see the crate in action, you can have a look at how it is used in the rust-raspberrypi-OS-tutorials project.

Shoutout to @phil-opp for inspiring this crate with his original blog post and to @Skallwar for his many contributions.

Join Us?

Are you interested in Rust-based operating system development? Our rust-osdev organization is always open to new members and new projects. Just let us know if you want to join! A good way for getting in touch is our Zulip chat.

Comments