RISC-V
OS in Rust
Homework
- Homeworks are due on the Friday after the week they correspond to lecture.
- So 9 days after the corresponding lab.
Requirements
Code
Don’t be like me
Loops are more stable than recursion I guess.
Other stuff
- I graciously borrrowed some code from this repository.
- helloworld_in_riscv_and_rust_baremetal
- Just kidding don’t use that, use this instead.
- I made a cool version.
The working parts
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── link.x
├── memory.x
└── src
└── main.rs
1 directory, 5 files- Some of this shouldn’t be new to you.
- Some should:
The internals
- Without dwelling on the details, these
.xfiles are for the linker- Remember our good friend the linker.
link.xwas written by someone that understands linkers.memory.xwas written by a script from a crate written by someone that understands linkers.
- From our perspective, they “just work”
- But how?
Starting Point
- At first, probably nothing works.
- Or at least,
cargo bdoesn’t work.
- Or at least,
$ cargo b
Compiling osirs v0.1.0 (/home/user/tmp/hwr5)
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "/tmp/rustcwuxfha/symbols.o" "<1 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-L" "/tmp/rustcwuxfha/raw-dylibs" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/user/tmp/hwr5/target/debug/deps/osirs-80f8eb3240ba748e" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: /usr/bin/ld: /home/user/tmp/hwr5/target/debug/deps/osirs-80f8eb3240ba748e.9chdw59nqscmfe0ef1hrxy2nb.rcgu.o: in function `_start':
/home/user/tmp/hwr5/src/main.rs:7: multiple definition of `_start'; /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'
/usr/bin/ld: (.text+0x21): undefined reference to `__libc_start_main'
collect2: error: ld returned 1 exit status
= note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
= note: use the `-l` flag to specify native libraries to link
= note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
error: could not compile `osirs` (bin "osirs") due to 1 previous errorrustc
- I found it easier to get to work with
rustc- Cargo hater Calvin
- Recall a way we ran the executable in the lab.
- We can just go straight to
rustc
- Only one catch.
- Well, two.
- We want to link files.
- Specifically, the
.xfiles.
![]()
Naively
- You can give
rustca shot straight-away.
$ rustc src/main.rs
error: unwinding panics are not supported without std
|
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
error: aborting due to 1 previous error- We recall we “fixed” the problem with panics by modifying
Cargo.toml. rustcdoesn’t care about yourCargo.toml!- We instead have to specify an argument to
rustc. - We do so similarly to the
link-arg, with the-Cflag.- We furnish basically the same thing we placed in
Cargo.toml.
- We furnish basically the same thing we placed in
- Get this working and see if you can get the following error message:
$ rustc src/main.rs -C panic=abort
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "/tmp/rustceBlIYK/symbols.o" "<1 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-L" "/tmp/rustceBlIYK/raw-dylibs" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: /usr/bin/ld: main.main.5f6bf0c8e9d0afce-cgu.0.rcgu.o: in function `_start':
main.5f6bf0c8e9d0afce-cgu.0:(.text._start+0x0): multiple definition of `_start'; /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1b): undefined reference to `main'
/usr/bin/ld: (.text+0x21): undefined reference to `__libc_start_main'
collect2: error: ld returned 1 exit status
= note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
= note: use the `-l` flag to specify native libraries to link
error: aborting due to 1 previous error- Ah hah! A linker error! Just as we hoped.
-T
- The linker complains it’s missing something, and it’s not sure what.
- We are sure, it’s the
.xfiles. - To furnish a file by name to the linker, we provide it as a
link-argprefixed with-T
MacOS Users!
This will not work on MacOS, to our knowledge.
Here is a guide to follow that should work: MacOS
- If you link both
.xfiles, you will get a different error message.
$ rustc -C link-args=-Tmemory.x -C link-args=-Tlink.x -C panic=abort src/main.rs
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "/tmp/rustczhisJl/symbols.o" "<1 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-L" "/tmp/rustczhisJl/raw-dylibs" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "-Tmemory.x" "-Tlink.x"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: /usr/bin/ld: main.main.5f6bf0c8e9d0afce-cgu.0.rcgu.o: in function `_start':
main.5f6bf0c8e9d0afce-cgu.0:(.text._start+0x0): multiple definition of `_start'; /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here
/usr/bin/ld:
.got section detected in the input files. Dynamic relocations are not
supported. If you are linking to C code compiled using the `gcc` crate
then modify your build script to compile the C code _without_ the
-fPIC flag. See the documentation of the `gcc::Config.fpic` method for
details.
/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o: in function `_init':
(.init+0xb): relocation truncated to fit: R_X86_64_REX_GOTPCRELX against undefined symbol `__gmon_start__'
collect2: error: ld returned 1 exit status
error: aborting due to 1 previous errorRISC-V
- RISC-V is what it would be like if hardware were good.
- By which I mean open-source.
| Good (Open Source) | Bad (Not) | |
|---|---|---|
| Windows | x | |
| Linux | x | |
| ICC (Intel C Compiler) | x | |
| GCC | x | |
| x86-64 | x | |
| ARM64 | x | |
| RISC-V | x |
- Also unlike x86 and ARM, it is easy to develop for RISC-V, and that is what we’ve done.
$ grep riscv link.x
By default uses the riscv crates default trap handler
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned");
ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned");
ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned");
ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned");
ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned");
ERROR(riscv-rt): `_stext` must be 4-byte aligned");
BUG(riscv-rt): .data is not 4-byte aligned");
BUG(riscv-rt): the LMA of .data is not 4-byte aligned");
BUG(riscv-rt): .bss is not 4-byte aligned");
BUG(riscv-rt): start of .heap is not 4-byte aligned");
ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region.
ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts.- By golly, our
.xfiles are for RISC-V!- And therefore good.
Target
- We recall the notion of a target triple
- From the linker lab
- We note:
- There are references to x86 (in my case) in the error logs.
- There are references to RISC-V in the linker files.
- We have to pick one, and…
- I didn’t provide appropriate linker files for x86
- Because it’s bad!
- You will additionlly need to specify a target.
riscv64imac-unknown-none-elf- You will figure it out.
- And you will know when you have, because you will see no errors and a
mainwill have appeared.
- And you will know when you have, because you will see no errors and a
Main
- Go ahead and run
main, what could go wrong.
- If, like me, you foolish use an architecture other than RISC-V as your daily driver (that’s a metaphor, not a reference to device drivers),
mainwon’t work on your system.
QEMU
- Well, it will, you just have to bamboozle your system into pretending to be a good system, like RISC-V
- We don’t allow our feelings to be hurt by RISC-V being described as “miscellaneous”.
- I didn’t properly sandbox my system before debugging so I think this is all you need but I may be wrong if I lost a dependency somewhere.
Run QEMU
- You can simply launch
qemuwith no strings attached.
- For me this popped open a new window.
- This is good, as otherwise you have to deal with processes and I don’t have time to teach that.
- If you type “quit” after the prompt of
(qemu)it should close.
Run main
- You can specify that you totally wrote a working OS, honest, by providing
qemuwith a specified kernel, like ourmain
Forward Pointer
We will properly introduce kernels in the next lecture.
- This will probably work.
$ qemu-system-riscv64 -kernel main
qemu-system-riscv64: Some ROM regions are overlapping
These ROM regions might have been loaded by direct user request or by default.
They could be BIOS/firmware images, a guest kernel, initrd or some other file loaded into guest memory.
Check whether you intended to load all this guest code, and whether it has been built to load to the correct addresses.
The following two regions overlap (in the memory address space):
/usr/share/qemu/opensbi-riscv64-generic-fw_dynamic.elf ELF program header segment 1 (addresses 0x0000000080000000 - 0x0000000080016ce8)
main ELF program header segment 0 (addresses 0x0000000080000000 - 0x0000000080000004)- And by probably I mean with a probability of zero.
BIOS
Forward Pointer
We will properly introduce the BIOS in the next lecture.
- The BIOS can be thought of as a tiny bit of read-only memory (ROM) that lives on a computer.
- When the computer first turns on, it immediately begins reading instructions from the BIOS (presumably over the bus, or through some other means).
- The BIOS will then instruct the device how to procede.
- We don’t need any of that, we already wrote an infinite loop and can just start there!
Machine
- You may get an error not unlike this one:
$ qemu-system-riscv64 -bios none -kernel main
qemu-system-riscv64: Invalid HTIF fromhost or tohost address- You also may not get this error.
- It is caused by not telling QEMU which specific, physical machine to pretend to be.
- I recommend
sifive_u, which I believe is the most popular physical chip for developmental purposes.
Fin
For me that worked, hopefully for you too! If not, you have officially entered the fun zone.
TODO
For this homework, add a README.md to the crate describing how to get it to work.
- It should be like this document, but concise.
- Use cool markdown checkboxes.