【问题标题】:How to enable MMU in QEMU (virt machine a57 cpu)如何在 QEMU 中启用 MMU(虚拟机 a57 cpu)
【发布时间】:2019-07-31 14:06:35
【问题描述】:

我正在 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 的代码。

【问题讨论】:

  • 我不知道它是否相关,但 0x400800c8 超出了您提供给 QEMU 的 1 GB 内存
  • 物理地址,DRAM从0x4000 0000到0x8000 0000。

标签: assembly qemu bare-metal mmu armv8


【解决方案1】:

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

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

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

【讨论】:

  • 0x400800c8对应的VA(address in linker script)为0xffff 0000 0008 00c8。所以我尝试配置 TTBR1_EL1 而不是 TTBR0_EL1。我可以通过 GDB 中的虚拟地址正确访问内存,您可以在我修改过的问题中看到。如果我将 VA 设置为 0x8 00c8 并配置 TTBR0_EL1,这将是同样的错误。
  • 是的,您可以访问 0xffff0000000800c8。但这不是您要从中执行的 PC,即 0x400800c8。 PC总是包含一个虚拟地址;在 MMU 关闭的情况下,会进行 1:1 转换,因此生成的物理地址与虚拟地址相同。
  • 我将 0x4000 0000 - 0x4020 0000(DRAM) 映射到 0x4000 0000 - 0x4020 0000(VA)。而且,哇,没关系。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 2018-08-05
  • 2011-08-12
  • 2021-09-03
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多