给hypercraft添加gdb调试接口 - bet4it/arceos GitHub Wiki
解决RISC-V下的hypercraft在开启NET之后遇到的问题
在arceos的hypervisor
分支下使用命令make A=apps/hv HV=y ARCH=riscv64 run
可以启动hypercraft运行Linux。
运行需要的linux.bin
和rootfs.img
可以在这里下载。
不过如果同时开启网络,make A=apps/hv ARCH=riscv64 HV=y NET=y run
这个命令会报错:
[ 0.106251 0 axruntime::lang_items:5] panicked at 'Unhandled trap Exception(LoadPageFault) @ 0xffffffc080207a68:
TrapFrame {
regs: GeneralRegisters {
ra: 0xffffffc080207776,
sp: 0xffffffc080253f60,
gp: 0x0,
tp: 0x0,
t0: 0xfff,
t1: 0x8027e000,
t2: 0x7d82000,
s0: 0xffffffc080258812,
s1: 0x1,
a0: 0xffffffc080255668,
a1: 0xffffffc080259288,
a2: 0x5555555555555555,
a3: 0x2,
a4: 0xffffffc08025a000,
a5: 0x1,
a6: 0xc,
a7: 0xb,
s2: 0xffffffc080257bb8,
s3: 0x1f,
s4: 0xffffffc010001000,
s5: 0xffffffc08025a000,
s6: 0xffffffc08027d138,
s7: 0x74726976,
s8: 0x10001000,
s9: 0x1000,
s10: 0xffffffc0802124f8,
s11: 0xffffffc000000000,
t3: 0xffffffc08027c000,
t4: 0x22000,
t5: 0xff,
t6: 0x5,
},
sepc: 0xffffffc080207a68,
sstatus: 0x8000000200006100,
}', modules/axhal/src/arch/riscv/trap.rs:41:13
可以把调试选项打开make A=apps/hv ARCH=riscv64 HV=y NET=y MODE=debug LOG=trace run
,分析可知是因为在开启了HV之后,分页机制不会开启:
#[cfg(not(feature = "hv"))]
{
#[cfg(feature = "paging")]
{
info!("Initialize kernel page table...");
remap_kernel_memory().expect("remap kernel memoy failed");
}
}
但设备支持都建立在开启分页的基础上,通过phys_to_virt
计算分页之后的虚拟地址然后进行MMIO相关操作,计算方法是物理地址加上PHYS_VIRT_OFFSET
就等于虚拟地址。
解决这个问题有两种思路:
- 在开启HV之后也开启分页机制。
- 让设备在不开启分页机制的情况下也能正确找到MMIO的地址。
这里我采用第一种方案,把前面那个hv的cfg
注释掉,可以发现已经能输出Hello, hv!
了,不过还是出现刚才的报错。
一个错误是现在linux.dtb
和linux.bin
是通过QEMU命令行硬编码到0x90000000和0x90200000这两个位置,setup_gpm
接受的参数也直接是物理地址,可我们开启分页之后物理地址都不可用了,这里需要提供转换后的虚拟地址,同时需要映射这个虚拟地址和物理地址之间的关系。
增加映射目前我是通过在qemu-virt-riscv.toml
中的mmio-regions
添加一项来实现的,不过严格来说这一块并不算MMIO的区域,不知道还有没有什么更好的方法。
另一个错误是在Linux运行过程中会通过Page Fault对PLIC进行访问,因为Linux是直接访问的物理地址,我们需要在收到这个地址之后转换成虚拟地址再访问。
不过这里的问题是如何在hypercraft中使用PHYS_VIRT_OFFSET
或者phys_to_virt
,目前是通过直接硬编码实现的。