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 映射.
我正在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 映射.