QEMU模拟器源码编译与使用
- 1 编译MySBI+BenOS
- 2 编译QEMU
- 3 QEMU运行MySBI+BenOS
- 4 使用gdb调试QEMU
- 5 通过QEMU调试指令
- 6 小结
本文属于 《RISC-V指令集差分测试(DiffTest)系列教程》之一,欢迎查看其它文章。
1 编译MySBI+BenOS
参考《NEMU模拟器源码编译与使用》中,第2节内容。
生成了,如下文件:
- benos.bin,BenOS可执行文件
- benos.elf,BenOS带调试信息的ELF文件
- mysbi.bin,MySBI固件的可执行文件
- mysbi.elf,MySBI带调试信息的ELF文件
- benos_payload.bin,把benos.bin和mysbi.bin整合到一个可执行二进制文件中。
需要在QEMU中运行的文件有:mysbi.bin、benos.bin、benos.elf。
2 编译QEMU
参考《在QEMU上运行OpenSBI+Linux+Rootfs》中,第1节内容。
3 QEMU运行MySBI+BenOS
将mysbi.bin、benos.bin、benos.elf,拷贝到qemu-7.1.0/build/目录下。
在QEMU中,运行MySBI+BenOS
./qemu-system-riscv64 -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf
运行效果,如下所示:
我们的BenOS,通过串口打印出了信息:Welcome RISC-V!
BenOS代码kernel.c,实现代码,如下所示:
#include "uart.h"
void kernel_main(void)
{
uart_init();
uart_send_string("Welcome RISC-V!\r\n");
while (1) {
;
}
}
后续打印信息,QEMU是以打印Kernel panic结束,如下:
Oops - Load page fault
Call Trace:
[<0x00000000802039e0>] trigger_load_access_fault+0x8/0x10
sepc: 00000000802039e0 ra : 0000000080202584 sp : 000000008020aff0
gp : 0000000000000000 tp : 0000000000000000 t0 : 0000000000000005
t1 : 0000000000000005 t2 : 0000000080200020 t3 : 000000008020b000
s1 : 0000000080200010 a0 : 0000000080000000 a1 : 0000000000000000
a2 : 0000000000000000 a3 : 0000000080210008 a4 : 0000000081000000
a5 : 0000000081000000 a6 : 0000000000000000 a7 : 0000000000000001
s2 : 0000000000000000 s3 : 0000000000000000 s4 : 0000000000000000
s5 : 0000000000000000 s6 : 0000000000000000 s7 : 0000000000000000
s8 : 0000000080200040 s9 : 0000000000000000 s10: 0000000000000000
s11: 0000000000000000 t3 : 00510133000012b7 t4: 0000000000000000
t5 : 0000000000000000 t6 : 0000000000000000
sstatus:0x0000000200000120 sbadaddr:0x0000000080000000 scause:0x000000000000000d
Kernel panic
此时,无法退出QEMU。可以通过以下命令,来退出QEMU:
kill $(ps aux | grep qemu | grep -v grep | awk '{print $2}')
4 使用gdb调试QEMU
上述步骤,编译的QEMU,直接就可以gdb调试,只是有一些还是有所优化,如果要完全无优化,可能还需要自己配置再重新编译。
直接在上述命令前,加gdb --args
:
gdb --args ./qemu-system-riscv64 -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf
启动调试,如下所示:
在/target/riscv/translate.c:1052行,打断点:b translate.c:1052
,然后
r
运行,即可在该断点处停住。
gdb调试QEMU代码成功。
5 通过QEMU调试指令
我们使用QEMU内置的RISCV调试器,来调试MySBI固件代码mysbi.elf。
我们在,上述QEMU启动命令中,加入-S -s
,以启动gdb server:
./qemu-system-riscv64 -S -s -nographic -machine virt -m 128M -bios mysbi.bin -device loader,file=benos.bin,addr=0x80200000 -kernel benos.elf
-s
参数也可以用-gdb tcp:1234
代替,含义一样;此参数相当于,启动了一个端口1234的TCP服务器。
需要注意,对于-gdb tcp:1234
参数,有些QEMU版本可能不支持,跑不起来。
在另外一个终端中,输入如下命令启动gdb:
gdb-multiarch --tui benos.elf
在gdb命令行中,输入以下命令:
target remote localhost:1234 # 连接gdb server
b _start # 在_start处打断点
c # 运行
可以看到在src/boot.S文件中,第6行_start处停住了。
QEMU调试MySBI固件代码成功。
6 小结
QEMU通过-S -s
启动了gdb server,通讯方式是TCP,端口1234。
那么,如果我们知道与gdb server的数据包协议,是不是就可以编写一个程序,去控制QEMU的单步执行,以及获取CPU寄存器、内存等,是的,这是可行的。
这个设想,正是后续文章中,介绍的NEMU与QEMU通过socket方式,做DiffTest的底层原理。