This Month in Rust OSDev: August 2022
Welcome to a new issue of "This Month in Rust OSDev". In these posts, we 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 or using our comment form at the bottom of this page.
rust-osdev
Projects
In this section, we give an overview of notable changes to the projects hosted under the rust-osdev
organization.
uefi-rs
Maintained by @GabrielMajeri, @nicholasbishop, and @phip1611
The uefi
crate provides safe and performant wrappers for UEFI, the successor to the BIOS.
We merged the following changes in August:
- Add
DiskIo
andDiskIo2
protocols - Added macros
print!
andprintln!
- Use
doc_auto_cfg
to show feature requirements on docs.rs - add
Ord
andPartialOrd
forGuid
struct - QEMU/OVMF improvements
- Update
nix
requirement from 0.24.1 to 0.25.0 - Update deprecation version in
ScopedProtocol::interface
- Relax version requirements for various deps
We also published a subset of the above changes as a new v0.16.1
release:
Thanks to @kendase3, @JonahPlusPlus, and @e820 for their contributions!
bootloader
Maintained by @phil-opp, @rybot666, and @64
The bootloader
crate implements a custom Rust-based bootloader for easy loading of 64-bit ELF executables.
This month, we finally finished the new BIOS boot implementation for the upcoming v0.11
release. It's now almost completely written in Rust (instead of assembly), which should make further improvements much easier.
Some selected commits that might be interesting:
- Load a third stage
- Load the kernel into buffer memory
- Copy kernel to protected mode
- Jump to third stage
- Set up paging and enter long mode (compatibility mode)
- Create prototype for long mode stage 4 and load it
- Load long mode
GDT
and jump to 4th stage - Query vesa modes and filter by resolution
- Enable VESA framebuffer and update screen writer in stages 3 and 4
- Load
E820
memory map and put everything together
All the tests are passing now, so we only need to do some cleanup and write proper documentation, then we should be ready to publish an alpha release for testing.
linked-list-allocator
Maintained by @phil-opp and @jamesmunns
The linked-list-allocator
crate provides a basic no_std
allocator that builds a linked list from freed memory blocks and thus needs no additional data structures.
In August, Evan Richter discovered a vulnerability in Heap::extend
that could lead to out-of-bound writes. The issue occurred when extend
was called with a size smaller than size_of::<usize> * 2
, i.e., a size too small to store the metadata for the new memory region.
Upon investigating this issue, we found several similar issues:
- Initializing a heap with a size smaller than
size_of::<usize> * 3
could result in an out-of-bounds write too. - Calling
extend
on an uninitialized heap could also result in an out-of-bounds write. - Calling
extend
on a heap whose size is not a multiple of the size of twousize
s resulted in unaligned writes.
We created a security advisory with more details and released a fix in v0.10.2
, with the following changes:
- The initialization functions now panic if the given size is not large enough to store the necessary metadata. Depending on the alignment of the heap bottom pointer, the minimum size is between
2 * size_of::<usize>
and3 * size_of::<usize>
. - The
extend
method now panics when trying to extend an uninitialized heap. - Extend calls with a size smaller than
size_of::<usize>() * 2
are now buffered internally and not added to the list directly. The buffered region will be merged with futureextend
calls. - The
size()
method now returns the usable size of the heap, which might be slightly smaller than thetop() - bottom()
difference because of alignment constraints.
Thanks to @evanrichter for reporting this vulnerability and working with us on a fix.
xhci
Maintained by @toku-sa-n
The xhci
crate provides types of xHCI structures, such as Registers and TRBs.
We merged the following changes this month:
- Rename
InterruptRegisterSet
toInterrupterRegisterSet
(published as0.8.7
) - Allow updating single fields of InterrupterRegisterSet (published as
0.9.0
)
Thanks to @Demindiro for their contribution!
pci_types
Maintained by @IsaacWoods
The pci_types
library provides types for accessing and configuring PCI devices from Rust operating systems.
We merged the following change in August:
Thanks to @0Killian for this contribution!
acpi
Maintained by @IsaacWoods, @Restioson, and @Gegy
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.
We merged the following changes this month:
Thanks to @semiviral, and @Freax13 for their contributions!
Call for Participation
Want to contribute to a Rust OSDev project, but don't know where to start? Help with one of these outstanding issues!
If you maintain a Rust project related to operating system development and are looking for contributors, especially for tasks suited to people getting started in this space, please create a PR against the next
branch with the tasks you want to include in the next issue.
Other Projects
In this section, we describe updates to Rust OS 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.
cdrzewiecki/celos
(Section written by @drzewiec)
It's been a while since my last project update! That's partly because life has been busy, but also because this update concerns a huge feature. I'm very pleased to report that I have been able to add preemptive multitasking to CelOS.
This was feature that took a good bit of foundation to be able to implement (hence why it took me so long). I had to spend a good bit of time getting memory allocation (both physical and virtual) into a happier place, as well as add support for ACPI and the APIC. And, of course, there were many snags along the way as I learned (at least some of) the traps that are easy to step into when doing something as delicate as context switching.
Now that I have finished this key feature, I plan to work on setting up the other infrastructure needed to begin writing services in userspace (such as message passing and synchronization primitives). And, hopefully soon, finally make the jump into ring 3!
As always, many thanks to @phil-opp for his hard work on supporting the Rust osdev community, and for writing the apic crate which helped serve as a sanity check while I wrote my own driver for the IOAPIC and LAPIC. Thanks as well to the maintainers of the excellent acpi crate, you guys are doing incredible work out there!
Blog Post: GNU ld Discards Section Containing Code – Section Flags in Assembly are Important
(Section written by @phip1611)
In late August/early September, I encountered problems when building my Rust kernel. I faced
unintuitive interaction between my global assembly code and the linker. I specified a custom
section in assembly with executable code with .section .bootcode
. The linker never linked
the code where I specified it in my linker script. It's address was not what it is supposed to be.
readelf
didn't show the section inside the binary either. The section was discarded no matter
how hard I tried to modify the linker, thus, KEEP((.bootcode));
also didn't work. An experienced
colleague ensured me that my linker script is correct.
Section names such as .init
or .text.bootcode
worked by the way. Only my custom name was
rejected somehow. In the end, I figured out writing .section .bootcode, "ax"
does the trick. The
difference is small, but the impact to the object file and final executable of those section flags
is big. I could find the answer in the ELF specification. A section needs to be allocatable
(a
-flag) so that it can be properly placed in a LOAD segment/program header. The section names
.init
and .text.*
have this pre-configured but my custom section name .bootcode
has not.
I traced it down to a minimal reproducible example that can be found on GitHub. A comprehensive write-up can be found on my website Phip's Blog.
phil-opp/blog_os
(Section written by @phil-opp)
This month, we merged a pull request that fixes numerous grammar and punctuation errors across all posts of the "Writing an OS in Rust" series. Thanks to @hecatia-elegua for this contribution!
We also received multiple pull requests to add and update translations:
- Fix Japanese translation of "Double Faults"
- Update the chinese translation
- [Translation][Korean] post-04
We are still looking for reviewers for the last two PRs. If you speak Chinese or Korean, it would be great if you could take a look!
Thanks to @ykomatsu, @liuyuran, and @JOE1994 for contributing these translations!
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.