2.9.2. Baremetal setup getting started
Every .c
file inside baremetal/ and .S
file inside baremetal/arch/<arch>/
generates a separate baremetal image.
For example, to run baremetal/arch/aarch64/dump_regs.c in QEMU do:
./setup ./build --arch aarch64 --download-dependencies qemu-baremetal ./run --arch aarch64 --baremetal baremetal/arch/aarch64/dump_regs.c
And the terminal prints the values of certain system registers. This example prints registers that are only accessible from EL1 or higher, and thus could not be run in userland.
In addition to the examples under baremetal/, several of the userland examples can also be run in baremetal! This is largely due to the awesomeness of Newlib.
The examples that work include most C examples that don’t rely on complicated syscalls such as threads, and almost all the Userland assembly examples.
The exact list of userland programs that work in baremetal is specified in path_properties.py with the baremetal
property, but you can also easily find it out with a baremetal test dry run:
./test-executables --arch aarch64 --dry-run --mode baremetal
For example, we can run the C hello world userland/c/hello.c simply as:
./run --arch aarch64 --baremetal userland/c/hello.c
and that outputs to the serial port the string:
hello
which QEMU shows on the host terminal.
To modify a baremetal program, simply edit the file, e.g.
vim userland/c/hello.c
and rebuild:
./build-baremetal --arch aarch64 ./run --arch aarch64 --baremetal userland/c/hello.c
./build qemu-baremetal
that we run previously is only needed for the initial build. That script calls build-baremetal for us, in addition to building prerequisites such as QEMU and crosstool-NG.
./build-baremetal
uses crosstool-NG, and so it must be preceded by build-crosstool-ng, which ./build qemu-baremetal
also calls.
Now let’s run userland/arch/aarch64/add.S:
./run --arch aarch64 --baremetal userland/arch/aarch64/add.S
This time, the terminal does not print anything, which indicates success: if you look into the source, you will see that we just have an assertion there.
You can see a sample assertion fail in userland/c/assert_fail.c:
./run --arch aarch64 --baremetal userland/c/assert_fail.c
and the terminal contains:
lkmc_exit_status_134 error: simulation error detected by parsing logs
and the exit status of our script is 1:
echo $?
You can run all the baremetal examples in one go and check that all assertions passed with:
./test-executables --arch aarch64 --mode baremetal
To use gem5 instead of QEMU do:
./setup ./build --download-dependencies gem5-baremetal ./run --arch aarch64 --baremetal userland/c/hello.c --emulator gem5
and then as usual open a shell with:
./gem5-shell
Or as usual, tmux users can do both in one go with:
./run --arch aarch64 --baremetal userland/c/hello.c --emulator gem5 --tmux
TODO: the carriage returns are a bit different than in QEMU, see: Section 33.6, “gem5 baremetal carriage return”.
Note that ./build-baremetal
requires the --emulator gem5
option, and generates separate executable images for both, as can be seen from:
echo "$(./getvar --arch aarch64 --baremetal userland/c/hello.c --emulator qemu image)" echo "$(./getvar --arch aarch64 --baremetal userland/c/hello.c --emulator gem5 image)"
This is unlike the Linux kernel that has a single image for both QEMU and gem5:
echo "$(./getvar --arch aarch64 --emulator qemu image)" echo "$(./getvar --arch aarch64 --emulator gem5 image)"
The reason for that is that on baremetal we don’t parse the device tress from memory like the Linux kernel does, which tells the kernel for example the UART address, and many other system parameters.
gem5
also supports the RealViewPBX
machine, which represents an older hardware compared to the default VExpress_GEM5_V1
:
./build-baremetal --arch aarch64 --emulator gem5 --machine RealViewPBX ./run --arch aarch64 --baremetal userland/c/hello.c --emulator gem5 --machine RealViewPBX
see also: Section 24.18, “gem5 ARM platforms”.
This generates yet new separate images with new magic constants:
echo "$(./getvar --arch aarch64 --baremetal userland/c/hello.c --emulator gem5 --machine VExpress_GEM5_V1 image)" echo "$(./getvar --arch aarch64 --baremetal userland/c/hello.c --emulator gem5 --machine RealViewPBX image)"
But just stick to newer and better VExpress_GEM5_V1
unless you have a good reason to use RealViewPBX
.
When doing baremetal programming, it is likely that you will want to learn userland assembly first, see: Section 28, “Userland assembly”.
For more information on baremetal, see the section: Section 33, “Baremetal”.
The following subjects are particularly important: