Quantcast
Viewing latest article 4
Browse Latest Browse All 22

Bare Metal Rust: Low-level CPU I/O ports

Want to build your own kernel in Rust? See the Bare Metal Rust page for more resources and more posts in this series.

Rust is a really fun language: It allows me to work on low-level kernel code, but it also allows me to wrap my code up in clean, high-level APIs. If you this sounds interesting, you should really check out Philipp Oppermann's blog posts about writing a basic x86_64 operating system kernel in Rust. He walks you through booting the kernel, entering long mode, getting Rust running, and printing text to the screen.

Once you get a basic kernel running, you'll probably want to start working on basic I/O, which requires interrupts. And this point, you'll find that pretty much every tutorial dives right into the in and out instructions. For example, if you look at the OSDev.org introduction to interrupts, the very first code you'll see is (comments added):

moval,20h;Moveinterruptacknowledgmentcodeintoal.out20h,al;WritealtoPIConport0x20.

Here, we're talking to the PIC ("Programmable Interrupt Controller"), and we're telling it that we've finished handling a processor interrupt. To do this, we need to write an 8-bit status code to the I/O port at address 0x20.

Traditionally, we would wrap this up in an outb ("out byte") function, which might look something like this in Rust:

// The asm! macro requires a nightly build of Rust, and// we need to opt-in explicitly.#![feature(asm)]unsafefnoutb(value:u8,port:u16){asm!("outb %al, %dx"::"{dx}"(port),"{al}"(value)::"volatile");}

This writes an 8-byte value to the specified port. It uses the unstable Rust extension asm!, which allows us to use GCC/LLVM-style inline assembly. We'd invoke it like this:

outb(0x20,0x20);

But let's see if we can wrap a higher-level API around an I/O port.

Read more…


Viewing latest article 4
Browse Latest Browse All 22

Trending Articles