linux 上的 MMU 初始化

MMU initialization on linux

我正在用 Rust 编写我的 linux RISC V 模拟器。

我偶然发现了 mmu 初始化。

OpenSBI 工作正常,打印信息并将控制转移到 linux 内核。 但是仿真器在 satp 设置后尝试读取下一条指令时崩溃 arch/riscv/kernel/head.S:119 中的 ffffffe00000008c。 (在 SATP_MODE_BARE 和 SATP_MODE_SV39 之间转移)

模拟器内存​​布局:

0x80000000 (2M) - opensbi image  
0x80200000 (64M) - linux image  
0x100000000 (1k) - device tree binary

early_pg_dir:

Root page: 0000000000080a04  
MMU Mappings:
    Virtual            Physical 
0000000040000000 -> 0000000082200000 (2M) // probably dtb 
ffffffe000000000 -> 0000000080200000 (2M)
ffffffe000200000 -> 0000000080400000 (2M)
ffffffe000400000 -> 0000000080600000 (2M) 
ffffffe000600000 -> 0000000080800000 (2M)
ffffffe000800000 -> 0000000080a00000 (2M)
ffffffe000a00000 -> 0000000080c00000 (2M) 
ffffffe000c00000 -> 0000000080e00000 (2M)
ffffffe000e00000 -> 0000000081000000 (2M)

trampoline_pg_dir:

Root page: 00000000000810be
MMU Mappings:
     Virtual            Physical  
ffffffe000000000 -> 0000000080200000 (2M)

我尝试通过在 gdb 中使用 qemu 单步执行来调试这个问题,但它也会在地址模式更改时崩溃和烧毁。 如果我理解正确的话:系统不能在没有身份映射或特殊页面错误处理程序的情况下切换寻址模式。

所以trampoline_pg_dir应该是恒等映射?

u/stepinfusion 在 reddit

If we are reading the same version of head.S, it looks to me that the instruction at ...008c is head.S:97, the first time satp is modified. head.S:119 is the ret instruction at ...00ac.

I don't know this code very well but it looks like it's supposed to trap at head.S:97 and stvec is pointing to the next instruction's virtual address. It's an interesting way to switch from running in physical space to virtual space without an identity mapping.