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

QEMU Raspi3 AARCH64多核启用指导:除核心0外其他核心挂起问题

在QEMU模拟树莓派3b时启用多核功能

问题背景

在QEMU RISC-V环境中成功启用过多核,但模拟Raspi3b时,使用-smp 4参数启动后,仅核心0能正常运行,其他核心均卡在WFE循环中无法进入内核逻辑。

当前配置信息

QEMU启动命令

qemu-system-aarch64 \
    -M raspi3b  \
    -m 1024M    \
    -smp 4 \
    -S -s \
    -kernel kernel8.img \
    -serial stdio 

初始启动代码

_start:
    //single core: only hart 0 jump to kernel
    mrs x0, mpidr_el1
    and x0, x0, #0b11
 
    cbz x0, _core_0
 
    //cbz x0, 1f
other_cores:
    wfe
    b other_cores
 
 
_core_0:
    mrs x0, CurrentEL
    and x0, x0, #0b1100
    cmp x0, #0b1000
    ......

GDB调试输出

(gdb) info threads

Id   Target Id                    Frame
1    Thread 1.1 (CPU#0 [running]) main () at main.c:44
2    Thread 1.2 (CPU#1 [running]) 0x000000000000030c in ?? ()
3    Thread 1.3 (CPU#2 [running]) 0x000000000000030c in ?? ()
4    Thread 1.4 (CPU#3 [running]) 0x000000000000030c in ?? ()

QEMU版本

QEMU emulator version 6.2.0
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers

问题原因

AArch64架构下,树莓派3的非0核心启动后会自动进入WFE(等待事件)状态,需要核心0主动发送SEV(发送事件)信号唤醒它们;同时原有代码未给非0核心分配独立栈空间和执行初始化逻辑,导致它们被唤醒后无法正常运行。

解决步骤

1. 为每个核心分配独立栈空间

在汇编代码或链接脚本中定义每个核心的专属栈,避免栈冲突:

.section .bss.stack
// 存储每个核心的栈顶地址
stack_top_array:
    .quad stack_core0_top
    .quad stack_core1_top
    .quad stack_core2_top
    .quad stack_core3_top

// 核心0栈(16KB)
stack_core0:
    .space 16384
stack_core0_top:

// 核心1栈(16KB)
stack_core1:
    .space 16384
stack_core1_top:

// 核心2栈(16KB)
stack_core2:
    .space 16384
stack_core2_top:

// 核心3栈(16KB)
stack_core3:
    .space 16384
stack_core3_top:

2. 修改启动代码,支持多核唤醒与初始化

更新启动汇编,让非0核心在被唤醒后执行通用初始化,再进入内核主函数:

_start:
    // 读取当前核心ID
    mrs x0, mpidr_el1
    and x0, x0, #0b11          // 提取低2位作为核心编号(0-3)
    
    // 为当前核心设置栈指针
    adr x1, stack_top_array
    ldr x2, [x1, x0, lsl #3]   // 每个栈顶地址占8字节,左移3位等价于乘8
    mov sp, x2
    
    // 核心0进入专属初始化流程
    cbz x0, _core_0_init

// 非0核心等待唤醒
other_cores_wait:
    wfe
    b _core_common_init

// 核心0执行基础初始化(MMU、GIC、时钟等)
_core_0_init:
    mrs x0, CurrentEL
    and x0, x0, #0b1100
    cmp x0, #0b1000
    // ... 保留原有核心0的初始化逻辑 ...
    
    // 初始化完成后,发送事件唤醒所有等待的核心
    sev

// 所有核心通用初始化流程
_core_common_init:
    // 执行通用初始化:设置异常向量表、启用FPU、配置中断等
    // ... 添加你的通用初始化代码 ...
    
    // 跳转到内核主函数
    b main

3. 验证效果

重新编译内核并启动QEMU,使用GDB调试时执行info threads,所有核心应都进入main()或通用初始化流程,不再卡在WFE循环地址。

内容的提问来源于stack exchange,提问作者Michaelbuzz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 14:54:08