给hypercraft添加gdb调试接口 - bet4it/arceos GitHub Wiki

解决RISC-V下的hypercraft在开启NET之后遇到的问题

在arceos的hypervisor分支下使用命令make A=apps/hv HV=y ARCH=riscv64 run可以启动hypercraft运行Linux。

运行需要的linux.binrootfs.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就等于虚拟地址。

解决这个问题有两种思路:

  1. 在开启HV之后也开启分页机制。
  2. 让设备在不开启分页机制的情况下也能正确找到MMIO的地址。

这里我采用第一种方案,把前面那个hv的cfg注释掉,可以发现已经能输出Hello, hv!了,不过还是出现刚才的报错。

一个错误是现在linux.dtblinux.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,目前是通过直接硬编码实现的。