1

我正在 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 virt 机器中启用 mmu 的代码。

4

1 回答 1

1

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

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

您可以通过正确设置页表来解决此问题,以便您的启动/初始化代码正在运行的地址存在 1:1 映射。

于 2019-08-01T12:02:23.893 回答