You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 14:42:05