Notes on coding a bare bones RISC-V OS
by Anne Macedo
I’m currently making a bare-bones operating system for RISC-V using Rust. These are a few notes for this project.
Current pipeline
I’ve built a docker image for toolchain with the tag sucymanbaravan/osdev-utils:riscv
and it contains the toolchain including gdb.
To build and run it:
BSP=mangopi make clean
BSP=mangopi make qemu
To debug it:
docker exec -it `docker ps -a | grep qemu | awk '{print $1}'` riscv64-unknown-linux-gnu-gdb target/riscv64gc-unknown-none-elf/release/kernel
on gdb:
(gdb) target remote :1234
Remote debugging using :1234
(gdb) disass _start
Dump of assembler code for function _start:
0x0000000080000000 <+0>: csrr t0,mhartid
0x0000000080000004 <+4>: bnez t0,0x8000003a <_start+58>
(gdb) set print asm-demangle on
(gdb) info functions
All defined functions:
File library/core/src/any.rs:
201: static fn core::any::{impl#0}::type_id<core::panic::panic_info::{impl#0}::internal_constructor::NoPayload>();
Rustup config
default host triple: riscv64gc-unknown-linux-gnu
default toolchain: nightly
profile: default
modify PATH variable: yes
However the rustc toolchain was built for RISC-V… shouldn’t it be built for cross compilation?
So I rerun rustup to x86_64 and
rustup target add riscv64gc-unknown-linux-gnu
Okay, so I understood: I need the toolchain! If I install with the riscv triple I’m not getting just the toolchain.
rustup toolchain install nightly-riscv64gc-unknown-linux-gnu
Still downloads the riscv non-cross-compile binary…
On the rust-gdb script:
# Run GDB with the additional arguments that load the pretty printers
# Set the environment variable `RUST_GDB` to overwrite the call to a
# different/specific command (defaults to `gdb`).
RUST_GDB="${RUST_GDB:-gdb}"
RUST_GDB=`which riscv64-unknown-linux-gnu-gdb` rust-gdb
RUST_GDB=`which riscv64-unknown-linux-gnu-gdb` rust-gdb target/riscv64gc-unknown-none-elf/release/kernel
RUST_GDB=`which riscv64-unknown-linux-gnu-gdb` rust-gdb target/riscv64gc-unknown-none-elf/debug/kernel
It seems that I was compiling as release, once I removed –release I got a debug binary :)
YAY
(gdb) l _start_rust
Python Exception <class 'ModuleNotFoundError'>: No module named 'gdb'
26 /// The Rust entry of the `kernel` binary.
27 ///
28 /// The function is called from the assembly `_start` function.
29 #[no_mangle]
30 pub unsafe fn _start_rust() -> ! {
31 crate::kernel_init()
32 }
Make it shorter (after adding stuff to dockerfile)
docker exec -it `docker ps -a | grep qemu | awk '{print $1}'` rust-gdb target/riscv64gc-unknown-none-elf/debug/kernel
Trying to fix the memory regions:
(gdb) info files
Symbols from "/work/tutorial/target/riscv64gc-unknown-none-elf/debug/kernel".
Remote target using gdb-specific protocol:
`/work/tutorial/target/riscv64gc-unknown-none-elf/debug/kernel', file type elf64-littleriscv.
Entry point: 0x80000000
0x0000000000000000 - 0x0000000080000000 is .boot_core_stack
0x0000000080000000 - 0x0000000080000eb4 is .text
0x0000000080000eb8 - 0x0000000080001255 is .rodata
0x0000000080001258 - 0x000000008000135c is .eh_frame
0x0000000080001360 - 0x0000000080001360 is .bss
0x0000000080001360 - 0x0000000080001361 is .sbss
0x0000000080001368 - 0x0000000080001620 is .sdata
While running this, GDB does not access memory from...
Local exec file:
`/work/tutorial/target/riscv64gc-unknown-none-elf/debug/kernel', file type elf64-littleriscv.
Entry point: 0x80000000
0x0000000000000000 - 0x0000000080000000 is .boot_core_stack
0x0000000080000000 - 0x0000000080000eb4 is .text
0x0000000080000eb8 - 0x0000000080001255 is .rodata
0x0000000080001258 - 0x000000008000135c is .eh_frame
0x0000000080001360 - 0x0000000080001360 is .bss
0x0000000080001360 - 0x0000000080001361 is .sbss
0x0000000080001368 - 0x0000000080001620 is .sdata
.boot_core_stack seems to be in the wrong position, it should be after .sdata
References
[1] rust-mangopi-OS-tutorials-riscv
[2] rust-raspberrypi-OS-tutorials
[4] Operating Systems in Rust #1: Hello RISC-V
[5] The Adventures of OS - RISC-V OS using Rust
[7] RISC-V support
tags: os-dev - riscv