QEMU中如何开启MMU(虚拟机a57cpu)

How to enable MMU in QEMU (virt machine a57 cpu)

我正在QEMU上写一个裸机ARMv8程序,但是当我启用MMU时,它无法继续执行任何指令。

QEMU 选项是“-machine virt -cpu cortex-a57 -smp 1 -m 1G -nographic -serial mon:stdio -kernel a.bin”

这是我的代码https://github.com/zhulangpi/NBOS/blob/mmu/arch/start.S

我尝试将 0x4000 0000~0x7fbf ffff(DRAM) 映射到 0xffff 0000 0000 0000~0xffff 0000 3fbf ffff(总共 1020MB)。

我使用GDB通过连接QEMU调试二进制映像,当我启用MMU时,如果我执行下一条指令,它显示:

(gdb) x/x 0x400800c8
0x400800c8:     0xd28014b4

(gdb) si

0x00000000400800c8 in ?? ()
=> 0x00000000400800c8:  Cannot access memory at address 0x400800c8

0x400800c8为PA对应的VA(链接描述文件中的地址)为0xffff 0000 0008 00c8.

我可以通过GDB中的虚拟地址正确访问内存如下,

(gdb) x/x 0xffff0000000800c8
0xffff0000000800c8 <_start+200>:        0xd28014b4

我的MMU配置如下,

    adrp    x0,  pg_tbl_start    //defined in linker script
    msr ttbr1_el1, x0

    ldr x0, =(TCR_VALUE)        //(TCR_T0SZ | TCR_T1SZ | TCR_TG0_4K | TCR_TG1_4K)
    msr tcr_el1, x0

    ldr x0, =(MAIR_VALUE)       //(0<<(8*1))|(0x44<<(8*0))
    msr mair_el1, x0

    //Initialize VBAR_EL1
    ldr x0, =vector_table_el1
    msr vbar_el1,   x0  

    /* configure init kernel task stack */
    ldr x0, =__init_stack_top   //defined in linker script
    mov sp, x0                  //sp_el1

    mrs x0, s3_1_c15_c2_1
    orr x0, x0, #(0x1<<6)       //cpuectlr.smpen = 1
    msr s3_1_c15_c2_1, x0

    mrs x0, sctlr_el1
    orr x0, x0, #1              // M bit, mmu
    msr sctlr_el1, x0           //enable the MMU

我希望能正确访问内存和设备。 或者有人可以告诉我如何在 qemu 虚拟机中启用 mmu 的代码。

这里发生的事情是,一旦您打开 MMU,就会通过对程序计数器值(在您的情况下为 0x400800c8)进行虚拟到物理的转换来执行下一条指令提取。如果此转换失败,那么 CPU 将出现异常,并且 gdbstub 也将无法从该地址读取内存(因为它也在虚拟地址上运行)。

更具体地说,地址 0x400800c8 位于物理地址范围的低半部分(其第 55 位为 0),因此 EL1 转换将使用 tables 指向的页面 TTBR0_EL1。但是你还没有初始化 TTBR0_EL1,所以它仍然是零。该地址的所有页面 table 条目都将读取为零,这是 "invalid" 描述符,因此 MMU 转换将失败。

您可以通过正确设置您的页面 table 来解决此问题,这样您的 startup/initialization 代码是 运行 的地址就有一个 1:1 映射.