环境搭建
工具
在Linux中安装如下工具。
$ sudo apt-get install qemu-system-misc gcc-riscv64-linux-gnu gdb-multiarch libncurses5-dev build-essential bison flex libssl-dev dc
源码
下载opensbi,我们这里下载OpenSBI v1.5版本。
$ git clone https://github.com/riscv-software-src/opensbi.git
编译
$ make PLATFORM=generic CROSS_COMPILE=riscv64-linux-gnu-
在build/platform/generic/firmware
目录下生成三种类型的固件:
- fw_dynamic:带有动态信息的固件,从上一阶段(即OpenSBI之前的启动阶段,如FSBL)获取下一阶段(例如u-boot或者kernel)的跳转地址信息。比如FSBL可以加载OpenSBI固件和其他镜像固件,并将u-boot或者kernel的跳转地址信息传递给OpenSBI,这里就需要使用
fw_dynamic
固件。 - fw_jump:指定下一阶段的跳转地址,不需要包含下一阶段的镜像固件
- fw_payload:包括下一阶段的镜像固件,即将OpenSBI、U-Boot和Kernel打包在一起
运行
使用qemu模拟OpenSBI的运行。
$ qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin
# 或者
$ make PLATFORM=generic run
-M
:指定模拟的机器类型,这里选择RISC-V VirtIO board-m
:指定虚拟机的内存大小-nographic
:qemu在无窗口的模式下运行,所有输出都将通过串口进行-bios
:指定BIOS固件
如果能够打印出版本信息,说明opensbi启动成功。
OpenSBI v1.5
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
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 : uart8250
Platform HSM Device : ---
Platform PMU Device : ---
Platform Reboot Device : ---
Platform Shutdown Device : ---
Platform Suspend Device : ---
Platform CPPC Device : ---
Firmware Base : 0x80000000
Firmware Size : 327 KB
Firmware RW Offset : 0x40000
Firmware RW Size : 71 KB
Firmware Heap Offset : 0x49000
Firmware Heap Size : 35 KB (total), 2 KB (reserved), 9 KB (used), 23 KB (free)
Firmware Scratch Size : 4096 B (total), 408 B (used), 3688 B (free)
Runtime SBI Version : 2.0
接下来介绍如何使用OpenSBI启动U-Boot和Linux Kernel。
调试
由于需要关闭优化,重新编译如下:
$ make PLATFORM=generic CROSS_COMPILE=riscv64-linux-gnu- DEBUG=1
使用GDB进行调试,执行命令如下:
$ qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-s -S
重新打开一个终端,连接tcp端口1234即可,执行命令:
$ gdb-multiarch build/platform/generic/firmware/fw_jump.elf \
-ex "target remote localhost:1234"
输入si
、c
、b
等命令开始调试。
U-Boot
下载U-Boot代码。
$ git clone https://github.com/u-boot/u-boot.git
进入u-boot目录,编译。
$ make CROSS_COMPILE=riscv64-linux-gnu- qemu-riscv64_smode_defconfig
$ make CROSS_COMPILE=riscv64-linux-gnu- -j16
在顶级目录下生成u-boot.bin
。
然后重新编译OpenSBI,提供u-boot固件路径,如下:
$ make PLATFORM=generic CROSS_COMPILE=riscv64-linux-gnu- FW_PAYLOAD_PATH=../u-boot/u-boot.bin
回到opensbi目录,使用make PLATFORM=generic run
再次运行即可。
这里我们也可以使用fw_jump
固件类型,只是在qemu启动中提供-kernel
参数即可:
$ qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel ../u-boot/u-boot.bin
不出意外,正常opensbi执行完成会启动到u-boot界面,如下所示:
......
Boot HART ID : 0
Boot HART Domain : root
Boot HART Priv Version : v1.10
Boot HART Base ISA : rv64imafdc
Boot HART ISA Extensions : none
Boot HART PMP Count : 16
Boot HART PMP Granularity : 2 bits
Boot HART PMP Address Bits: 54
Boot HART MHPM Info : 0 (0x00000000)
Boot HART Debug Triggers : 0 triggers
Boot HART MIDELEG : 0x0000000000000222
Boot HART MEDELEG : 0x000000000000b109
U-Boot 2024.07-rc5-00012-g8937bb265a (Jul 01 2024 - 19:25:43 +0800)
CPU: riscv
Model: riscv-virtio,qemu
DRAM: 256 MiB
Core: 22 devices, 10 uclasses, devicetree: board
Flash: 32 MiB
Loading Environment from nowhere... OK
In: serial,usbkbd
Out: serial,vidconsole
Err: serial,vidconsole
No USB controllers found
Net: No ethernet found.
Working FDT set to 8eefcc90
Hit any key to stop autoboot: 0
Kernel
rootfs使用buildroot编译构建。
$ git clone git://git.buildroot.net/buildroot.git
$ cd buildroot
$ make qemu_riscv64_virt_defconfig
$ utils/config -e BR2_TARGET_ROOTFS_CPIO
$ utils/config -e BR2_TARGET_ROOTFS_CPIO_GZIP
$ make olddefconfig
$ make
编译得到output/images/rootfs.cpio.gz
。
kernel构建这里下载linux-5.17.2.tar.xz。
$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.17.2.tar.xz
编译kernel,如下:
$ export ARCH=riscv
$ export CROSS_COMPILE=riscv64-linux-gnu-
$ make defconfig
$ make -j16
编译得到arch/riscv/boot/Image
。
回到opensbi目录,使用fw_jump
固件类型,在qemu启动中提供-kernel
参数以及rootfs即可:
$ qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel ../linux-5.17.2/arch/riscv/boot/Image \
-drive file=../buildroot/output/images/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-append "root=/dev/vda rw console=ttyS0"
或者将rootfs
使用-initrd
参数提供:
$ qemu-system-riscv64 -M virt -m 256M -nographic \
-bios build/platform/generic/firmware/fw_jump.bin \
-kernel ../linux-5.17.2/arch/riscv/boot/Image \
-initrd ../buildroot/output/images/rootfs.cpio.gz
-append "root=/dev/vda rw console=ttyS0"
正常的话Linux可以启动成功:
......
Boot HART ID : 0
Boot HART Domain : root
Boot HART Priv Version : v1.10
Boot HART Base ISA : rv64imafdc
Boot HART ISA Extensions : none
Boot HART PMP Count : 16
Boot HART PMP Granularity : 2 bits
Boot HART PMP Address Bits: 54
Boot HART MHPM Info : 0 (0x00000000)
Boot HART Debug Triggers : 0 triggers
Boot HART MIDELEG : 0x0000000000000222
Boot HART MEDELEG : 0x000000000000b109
[ 0.000000] Linux version 5.17.2 (test@test) (riscv64-linux-gnu-gcc (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #2 SMP Mon Jul 1 19:57:55 +08 2024
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[ 0.000000] Machine model: riscv-virtio,qemu
[ 0.000000] efi: UEFI not found.
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] Normal empty
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x000000008fffffff]
[ 0.000000] SBI specification v2.0 detected
[ 0.000000] SBI implementation ID=0x1 Version=0x10005
[ 0.000000] SBI TIME extension detected
[ 0.000000] SBI IPI extension detected
[ 0.000000] SBI RFENCE extension detected
[ 0.000000] SBI HSM extension detected
[ 0.000000] riscv: ISA extensions acdfimsu
[ 0.000000] riscv: ELF capabilities acdfim
[ 0.000000] percpu: Embedded 17 pages/cpu s30824 r8192 d30616 u69632
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 64135
[ 0.000000] Kernel command line:
[ 0.000000] Dentry cache hash table entries: 32768 (order: 6, 262144 bytes, linear)
[ 0.000000] Inode-cache hash table entries: 16384 (order: 5, 131072 bytes, linear)
[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] fixmap : 0xffff8d7ffee00000 - 0xffff8d7fff000000 (2048 kB)
[ 0.000000] pci io : 0xffff8d7fff000000 - 0xffff8d8000000000 ( 16 MB)
[ 0.000000] vmemmap : 0xffff8d8000000000 - 0xffff8f8000000000 (2097152 MB)
[ 0.000000] vmalloc : 0xffff8f8000000000 - 0xffffaf8000000000 (33554432 MB)
[ 0.000000] lowmem : 0xffffaf8000000000 - 0xffffaf800fe00000 ( 254 MB)
[ 0.000000] kernel : 0xffffffff80000000 - 0xffffffffffffffff (2047 MB)
[ 0.000000] Memory: 232608K/260096K available (6082K kernel code, 4861K rwdata, 2048K rodata, 2154K init, 326K bss, 27488K reserved, 0K cma-reserved)
......