11 KiB
Baremetal RISC-V
Ok this chuck guy knows his stuff it seems https://www.youtube.com/watch?v=qLzD33xVcRE
barmetal.ld
contains the linker scripts.
The SECTIONS
keyword indicates the beginning of the linker script sections where he specifies the memory layout, and the sections of the program.
{
. = 0x800000000;
}
This sets the location counter to the 0x800000000 memory address. This means that the following sections of the linker script will be placed as if starting from this address in memory. This is important because we need to know where in memory to load our application, so that the cpu boots we know what address will be loaded into the program counter to start executing instructions.
ADD MORE DETAILS
QEMU
Run this command
qemu-system-riscv32 -nographic -serial mon:stdio -machine virt
If you encounter
qemu-system-riscv32: Unable to load the RISC-V firmware "opensbi-riscv32-generic-fw_dynamic.bin"
Well it's going to suck a little. Running sudo apt install opensbi
only appears to include qemu-system-riscv64 builds. I tried building from source and hit a ton of issues, so instead I untarred a binary release in my home directory
wget https://github.com/riscv-software-src/opensbi/releases/download/v1.5.1/opensbi-1.5.1-rv-bin.tar.xz
tar -xf opensbi-1.5.1-rv-bin.tar.xz -C ~/
ls ~/opensbi-1.5.1-rv-bin
qemu-system-riscv32 -nographic -serial mon:stdio -machine virt -bios ~/opensbi-1.5.1-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin
Now we can continue...
We start qemu in -nographic
mode. We redirect the console input/output to our terminal -serial mon:stdio
, and we start the virt
machine type that we will do the simulation under.
OpenSBI v1.5.1
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
Platform Name : riscv-virtio,qemu
Platform Features : medeleg
Platform HART Count : 1
Platform IPI Device : aclint-mswi
Platform Timer Device : aclint-mtimer @ 10000000Hz
Platform Console Device : semihosting
Platform HSM Device : ---
Platform PMU Device : ---
Platform Reboot Device : syscon-reboot
Platform Shutdown Device : syscon-poweroff
Platform Suspend Device : ---
Platform CPPC Device : ---
Firmware Base : 0x80000000
Firmware Size : 319 KB
Firmware RW Offset : 0x40000
Firmware RW Size : 63 KB
Firmware Heap Offset : 0x47000
Firmware Heap Size : 35 KB (total), 2 KB (reserved), 9 KB (used), 23 KB (free)
Firmware Scratch Size : 4096 B (total), 240 B (used), 3856 B (free)
Runtime SBI Version : 2.0
Domain0 Name : root
Domain0 Boot HART : 0
Domain0 HARTs : 0*
Domain0 Region00 : 0x00100000-0x00100fff M: (I,R,W) S/U: (R,W)
Domain0 Region01 : 0x02000000-0x0200ffff M: (I,R,W) S/U: ()
Domain0 Region02 : 0x0c200000-0x0c20ffff M: (I,R,W) S/U: (R,W)
Domain0 Region03 : 0x80040000-0x8004ffff M: (R,W) S/U: ()
Domain0 Region04 : 0x80000000-0x8003ffff M: (R,X) S/U: ()
Domain0 Region05 : 0x0c000000-0x0c1fffff M: (I,R,W) S/U: (R,W)
Domain0 Region06 : 0x00000000-0xffffffff M: () S/U: (R,W,X)
Domain0 Next Address : 0x00000000
Domain0 Next Arg1 : 0x87000000
Domain0 Next Mode : S-mode
Domain0 SysReset : yes
Domain0 SysSuspend : yes
Boot HART ID : 0
Boot HART Domain : root
Boot HART Priv Version : v1.10
Boot HART Base ISA : rv32imafdc
Boot HART ISA Extensions : zicntr
Boot HART PMP Count : 16
Boot HART PMP Granularity : 2 bits
Boot HART PMP Address Bits: 32
Boot HART MHPM Info : 0 (0x00000000)
Boot HART Debug Triggers : 0 triggers
Boot HART MIDELEG : 0x00000222
Boot HART MEDELEG : 0x0000b109
We see that our Firmware Base : 0x80000000
is address where the firmware should be loaded from. You can also see that Domain0 Region04 : 0x80000000-0x8003ffff M: (R,X) S/U: ()
this region is marked as X for executable.
How do we know that the serial UART is at 0x10000000? This UART is defined as a NS16550 Uart in https://www.qemu.org/docs/master/system/riscv/virt.html
Looking at the UART16550 Core technical manual we see that Transmitter Holding Register (THR)
is at Address 0. Lastly, we want to enter the qemu console, so Ctrl-A C
will take us to the qemu console. We want to inspect the info mtree
output we can see that the 0000000010000000-0000000010000007 (prio 0, i/o): serial
serial device memory location starts at 0x10000000. So since the register the THR is at 0, we know we can use that as our UART target.
(qemu) info mtree
(qemu) info mtree
address-space: memory
0000000000000000-ffffffffffffffff (prio 0, i/o): system
0000000000001000-000000000000ffff (prio 0, rom): riscv_virt_board.mrom
0000000000100000-0000000000100fff (prio 0, i/o): riscv.sifive.test
0000000000101000-0000000000101023 (prio 0, i/o): goldfish_rtc
0000000002000000-0000000002003fff (prio 0, i/o): riscv.aclint.swi
0000000002004000-000000000200bfff (prio 0, i/o): riscv.aclint.mtimer
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport_window
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport
000000000c000000-000000000c20ffff (prio 0, i/o): riscv.sifive.plic
0000000010000000-0000000010000007 (prio 0, i/o): serial
0000000010001000-00000000100011ff (prio 0, i/o): virtio-mmio
0000000010002000-00000000100021ff (prio 0, i/o): virtio-mmio
0000000010003000-00000000100031ff (prio 0, i/o): virtio-mmio
0000000010004000-00000000100041ff (prio 0, i/o): virtio-mmio
0000000010005000-00000000100051ff (prio 0, i/o): virtio-mmio
0000000010006000-00000000100061ff (prio 0, i/o): virtio-mmio
0000000010007000-00000000100071ff (prio 0, i/o): virtio-mmio
0000000010008000-00000000100081ff (prio 0, i/o): virtio-mmio
0000000010100000-0000000010100007 (prio 0, i/o): fwcfg.data
0000000010100008-0000000010100009 (prio 0, i/o): fwcfg.ctl
0000000010100010-0000000010100017 (prio 0, i/o): fwcfg.dma
0000000020000000-0000000021ffffff (prio 0, romd): virt.flash0
0000000022000000-0000000023ffffff (prio 0, romd): virt.flash1
0000000030000000-000000003fffffff (prio 0, i/o): alias pcie-ecam @pcie-mmcfg-mmio 0000000000000000-000000000fffffff
0000000040000000-000000007fffffff (prio 0, i/o): alias pcie-mmio @gpex_mmio_window 0000000040000000-000000007fffffff
0000000080000000-0000000087ffffff (prio 0, ram): riscv_virt_board.ram
0000000300000000-00000003ffffffff (prio 0, i/o): alias pcie-mmio-high @gpex_mmio_window 0000000300000000-00000003ffffffff
address-space: I/O
0000000000000000-000000000000ffff (prio 0, i/o): io
address-space: cpu-memory-0
0000000000000000-ffffffffffffffff (prio 0, i/o): system
0000000000001000-000000000000ffff (prio 0, rom): riscv_virt_board.mrom
0000000000100000-0000000000100fff (prio 0, i/o): riscv.sifive.test
0000000000101000-0000000000101023 (prio 0, i/o): goldfish_rtc
0000000002000000-0000000002003fff (prio 0, i/o): riscv.aclint.swi
0000000002004000-000000000200bfff (prio 0, i/o): riscv.aclint.mtimer
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport_window
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport
000000000c000000-000000000c20ffff (prio 0, i/o): riscv.sifive.plic
0000000010000000-0000000010000007 (prio 0, i/o): serial
0000000010001000-00000000100011ff (prio 0, i/o): virtio-mmio
0000000010002000-00000000100021ff (prio 0, i/o): virtio-mmio
0000000010003000-00000000100031ff (prio 0, i/o): virtio-mmio
0000000010004000-00000000100041ff (prio 0, i/o): virtio-mmio
0000000010005000-00000000100051ff (prio 0, i/o): virtio-mmio
0000000010006000-00000000100061ff (prio 0, i/o): virtio-mmio
0000000010007000-00000000100071ff (prio 0, i/o): virtio-mmio
0000000010008000-00000000100081ff (prio 0, i/o): virtio-mmio
0000000010100000-0000000010100007 (prio 0, i/o): fwcfg.data
0000000010100008-0000000010100009 (prio 0, i/o): fwcfg.ctl
0000000010100010-0000000010100017 (prio 0, i/o): fwcfg.dma
0000000020000000-0000000021ffffff (prio 0, romd): virt.flash0
0000000022000000-0000000023ffffff (prio 0, romd): virt.flash1
0000000030000000-000000003fffffff (prio 0, i/o): alias pcie-ecam @pcie-mmcfg-mmio 0000000000000000-000000000fffffff
0000000040000000-000000007fffffff (prio 0, i/o): alias pcie-mmio @gpex_mmio_window 0000000040000000-000000007fffffff
0000000080000000-0000000087ffffff (prio 0, ram): riscv_virt_board.ram
0000000300000000-00000003ffffffff (prio 0, i/o): alias pcie-mmio-high @gpex_mmio_window 0000000300000000-00000003ffffffff
address-space: gpex-root
0000000000000000-ffffffffffffffff (prio 0, i/o): bus master container
memory-region: pcie-mmcfg-mmio
0000000000000000-000000001fffffff (prio 0, i/o): pcie-mmcfg-mmio
memory-region: gpex_mmio_window
0000000000000000-ffffffffffffffff (prio 0, i/o): gpex_mmio_window
0000000000000000-ffffffffffffffff (prio 0, i/o): gpex_mmio
memory-region: system
0000000000000000-ffffffffffffffff (prio 0, i/o): system
0000000000001000-000000000000ffff (prio 0, rom): riscv_virt_board.mrom
0000000000100000-0000000000100fff (prio 0, i/o): riscv.sifive.test
0000000000101000-0000000000101023 (prio 0, i/o): goldfish_rtc
0000000002000000-0000000002003fff (prio 0, i/o): riscv.aclint.swi
0000000002004000-000000000200bfff (prio 0, i/o): riscv.aclint.mtimer
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport_window
0000000003000000-000000000300ffff (prio 0, i/o): gpex_ioport
000000000c000000-000000000c20ffff (prio 0, i/o): riscv.sifive.plic
0000000010000000-0000000010000007 (prio 0, i/o): serial
0000000010001000-00000000100011ff (prio 0, i/o): virtio-mmio
0000000010002000-00000000100021ff (prio 0, i/o): virtio-mmio
0000000010003000-00000000100031ff (prio 0, i/o): virtio-mmio
0000000010004000-00000000100041ff (prio 0, i/o): virtio-mmio
0000000010005000-00000000100051ff (prio 0, i/o): virtio-mmio
0000000010006000-00000000100061ff (prio 0, i/o): virtio-mmio
0000000010007000-00000000100071ff (prio 0, i/o): virtio-mmio
0000000010008000-00000000100081ff (prio 0, i/o): virtio-mmio
0000000010100000-0000000010100007 (prio 0, i/o): fwcfg.data
0000000010100008-0000000010100009 (prio 0, i/o): fwcfg.ctl
0000000010100010-0000000010100017 (prio 0, i/o): fwcfg.dma
0000000020000000-0000000021ffffff (prio 0, romd): virt.flash0
0000000022000000-0000000023ffffff (prio 0, romd): virt.flash1
0000000030000000-000000003fffffff (prio 0, i/o): alias pcie-ecam @pcie-mmcfg-mmio 0000000000000000-000000000fffffff
0000000040000000-000000007fffffff (prio 0, i/o): alias pcie-mmio @gpex_mmio_window 0000000040000000-000000007fffffff
0000000080000000-0000000087ffffff (prio 0, ram): riscv_virt_board.ram
0000000300000000-00000003ffffffff (prio 0, i/o): alias pcie-mmio-high @gpex_mmio_window 0000000300000000-00000003ffffffff