AArch64架构树莓派4B裸机OS启用MMU后死机求助
树莓派4B AArch64裸机MMU启用后真实硬件死机(QEMU正常)
问题描述
我正在为AArch64/Arm64架构的树莓派4B开发小型裸机操作系统,遇到以下差异问题:
- QEMU环境:测试完全正常,启用MMU后能进入
main函数并正常访问内存,setup_mmu函数可打印"before enable mmu"和"after enable mmu" - 真实硬件:仅能收到"before enable mmu",启用MMU后系统直接死机,无后续输出
QEMU启动参数:
qemu-system-aarch64 -M raspi4b -kernel mykernel.elf -cpu cortex-a72 -nographic -no-reboot -serial none -serial mon:stdio
我的目标是实现1:1恒等映射:用1个Level 0页表指向1个Level 1页表,Level 1页表包含4个条目,每个对应1GB内存块,映射全部4GB内存。MMU初始化时内核运行在EL1级别。
相关代码片段
mmu.cc
static uint64_t __attribute((aligned(0x1000), section(".bss.page_tables"))) level0_page_table[1] = {0}; static uint64_t __attribute((aligned(0x1000), section(".bss.page_tables"))) level1_page_table[4] = {0}; static void setup_page_tables(void) { level0_page_table[0] = (uint64_t)(&level1_page_table) | TABLE_DESCRIPTOR; level1_page_table[0] = (uint64_t)(0x00000000) | BLOCK_ENTRY | CODE_ATTR; level1_page_table[1] = (uint64_t)(0x40000000) | BLOCK_ENTRY | CODE_ATTR; level1_page_table[2] = (uint64_t)(0x80000000) | BLOCK_ENTRY | CODE_ATTR; level1_page_table[3] = (uint64_t)(0xC0000000) | BLOCK_ENTRY | CODE_ATTR; } static void enable_mmu(void) { uint64_t sctlr; __asm__ volatile ("mrs %[SCTLR], SCTLR_EL1\n" "orr %[SCTLR], %[SCTLR], %[CONFIG]\n" "msr SCTLR_EL1, %[SCTLR]" : [SCTLR] "+r"(sctlr) : [CONFIG] "r"(SCTLR_CONFIG) : "memory" ); } static void invalidate_tlb(void) { __asm__ volatile ("dsb ISHST\n" "tlbi VMALLE1\n" "dsb ISH\n" "isb" : : : ); } extern "C" void setup_mmu(void) { write_mair_el1(MAIR_ATTRIBUTES); write_tcr_el1(TCR_ATTRIBUTES); setup_page_tables(); write_ttbr0_el1((uint64_t)&level0_page_table); write_ttbr1_el1((uint64_t)&level0_page_table); invalidate_tlb(); Serial::puts("before enable mmu"); enable_mmu(); Serial::puts("after enable mmu"); }
mmu.h(节选)
#define MAIR_ATTRIBUTES ((0x04 << (MT_DEVICE_nGnRE * 8)) | \ (0xffUL << (MT_NORMAL * 8))) #define TCR_ATTRIBUTES (TxSZ(BITS_16) \ | TG(GRANULE_4KB) \ | IPA_SIZE(PA_BITS_48) \ | SH(INNER_SHAREABLE) \ | ORGN(NORM_MEM_OUTER_WB_WA_CACHE) \ | IRGN(NORM_MEM_INNER_WB_WA_CACHE)) #define TABLE_DESCRIPTOR 0b11 #define TABLE_ENTRY 0b11 #define BLOCK_ENTRY 0b01 #define CODE_ATTR (AF_BIT \ | SH_BITS(INNER_SHAREABLE) \ | AP_BITS(RW_EL1) \ | AttrIndx(MT_NORMAL))
startup.S
#include "sys_regs.h" #include "gic.h" .section ".text.boot" .global _start .type _start, function _start: mrs x0, MPIDR_EL1 and x0, x0, #0xFF cbz x0, elcheck // core is 0 b loop elcheck: bl get_current_el cmp x0, #1 b.eq el1_entry_aarch64 // in el1 cmp x0, #2 b.eq el2_entry_aarch64 // in el2 el3_entry_aarch64: ldr x0, =SCR_EL3_VALUE msr SCR_EL3, x0 ldr x0, =SPSR_EL3_VALUE msr SPSR_EL3, x0 adr x0, el2_entry_aarch64 msr ELR_EL3, x0 eret el2_entry_aarch64: ldr x0, =HCR_EL2_VALUE msr HCR_EL2, x0 ldr x0, =SPSR_EL2_VALUE msr SPSR_EL2, x0 adr x0, el1_entry_aarch64 msr ELR_EL2, x0 eret el1_entry_aarch64: ldr x0, =SPSR_EL1_VALUE msr SPSR_EL1, x0 bl irq_disable stack_entry: ldr x0, =__el1_stack_end mov sp, x0 serial_entry: bl serial_init mmu_entry: bl setup_mmu /* some more setup */ run: bl main
linker.ld
ENTRY(_start) SECTIONS { . = 0x0; __start = .; .header : { KEEP(*(.header)) } . = ALIGN(0x1000); .text : ALIGN(4k) { _stext = .; KEEP(*(.text.boot)) *(.text) _etext = .; } .rodata : ALIGN(4k) { *(.rodata) } .data : ALIGN(4K) { *(.data) __el1_stack_top = .; . = . + 0x4000; /* 16KB stack */ __el1_stack_end = .; __el2_stack_top = .; . = . + 0x4000; /* 16KB stack */ __el2_stack_end = .; } .bss : ALIGN(4K) { __bss_start = .; *(.bss) *(.bss.page_tables) __bss_end = .; } __bss_size = __bss_end - __bss_start; __end = .; _kernel_size = __end - __start; }
内容的提问来源于stack exchange,提问作者CallmeEchoo
相关产品推荐
相关产品推荐

