RISC-V64 架构的多核唤醒机制基于 OpenSBI (Supervisor Binary Interface) 标准,通过 HSM (Hart State Management) 扩展来管理硬件线程(Hart)的启动和状态。RISC-V 提供了简单统一的多核启动接口。
- HSM (Hart State Management): RISC-V标准的硬件线程管理接口
- SBI调用: 通过
ecall指令与Machine模式的OpenSBI固件通信 - Hart状态管理: 包括STARTED、STOPPED、START_PENDING等状态
Hart状态枚举 (3rd/opensbi_interface/src/include/opensbi_interface.h):
enum {
HSM_HART_STATE_STARTED = 0,
HSM_HART_STATE_STOPPED = 1,
HSM_HART_STATE_START_PENDING = 2,
HSM_HART_STATE_STOP_PENDING = 3,
HSM_HART_STATE_SUSPENDED = 4,
HSM_HART_STATE_SUSPEND_PENDING = 5,
HSM_HART_STATE_RESUME_PENDING = 6,
};SBI返回值结构:
struct sbiret {
long error; // 错误码
long value; // 返回值
};在 src/arch/riscv64/arch_main.cpp 的 ArchInit() 函数中:
void ArchInit(int argc, const char **argv) {
// 1. 解析设备树获取基本信息
KernelFdtSingleton::create(reinterpret_cast<uint64_t>(argv));
// 2. 初始化基本信息
BasicInfoSingleton::create(argc, argv);
// 3. 解析内核ELF信息
KernelElfSingleton::create(BasicInfoSingleton::instance().elf_addr);
// 4. 通过SBI唤醒所有Hart
for (size_t i = 0; i < BasicInfoSingleton::instance().core_count; i++) {
auto ret = sbi_hart_start(i, reinterpret_cast<uint64_t>(_boot), 0);
if ((ret.error != SBI_SUCCESS) &&
(ret.error != SBI_ERR_ALREADY_AVAILABLE)) {
klog::Warn("hart %d start failed: %d\n", i, ret.error);
}
}
}位于 src/arch/riscv64/boot.S,实现简洁的64位启动序列:
.section .text.boot
.global _boot
_boot:
// 检查设备树地址是否有效
beqz a1, 2f
// 初始化全局指针寄存器 (可选)
#if USE_NO_RELAX == 0
.option push
.option norelax
1: auipc gp, %pcrel_hi(__global_pointer$)
addi gp, gp, %pcrel_lo(1b)
.option pop
#endif
2: // 根据Hart ID设置独立栈
add t0, a0, 1 // t0 = hart_id + 1
slli t0, t0, 12 // t0 *= 4096 (4KB per hart)
la sp, stack_top // 加载栈顶基址
add sp, sp, t0 // sp = stack_top + hart_id * 4KB
// 保存Hart ID到tp寄存器 (用于获取当前核心ID)
mv tp, a0
// 保存SBI传递的参数到栈
addi sp, sp, -8*2 // 开辟栈空间
sd a0, 0(sp) // 保存Hart ID
sd a1, 8(sp) // 保存设备树地址
// 跳转到C代码入口
call _start
// 如果返回则进入等待状态
wfisbi_hart_start() 函数实现 (3rd/opensbi_interface/src/opensbi_interface.c):
struct sbiret sbi_hart_start(unsigned long hartid, unsigned long start_addr,
unsigned long opaque) {
return ecall(hartid, start_addr, opaque, 0, 0, 0,
SBI_EXT_HSM_HART_START, SBI_EXT_HSM);
}Hart启动后通过 src/main.cpp 的 _start() 函数进入:
void _start(int argc, const char **argv) {
if (argv != nullptr) {
// BSP路径 (设备树地址有效)
CppInit();
main(argc, argv);
CppDeInit();
} else {
// AP路径 (设备树地址为空)
main_smp(argc, argv);
}
// 进入死循环
while (true) { ; }
}AP执行 main_smp() -> ArchInitSMP() (当前为空实现):
void ArchInitSMP(int, const char **) {}RISC-V使用 tp (Thread Pointer) 寄存器存储当前Hart ID:
// 在boot.S中设置
mv tp, a0 // 将Hart ID保存到tp寄存器// 在C代码中获取
static __always_inline auto GetCurrentCoreId() -> size_t {
return Tp::Read();
}通过内联汇编实现:
// 读取tp寄存器
static __always_inline auto Read() -> typename RegInfo::DataType {
typename RegInfo::DataType value{};
__asm__ volatile("mv %0, tp" : "=r"(value) : :);
return value;
}
// 写入tp寄存器
static __always_inline void Write(typename RegInfo::DataType value) {
__asm__ volatile("mv tp, %0" : : "r"(value) :);
}通过解析设备树获取系统CPU核心数:
[[nodiscard]] auto GetCoreCount() const -> size_t {
size_t core_count = 0;
auto offset = -1;
while (true) {
offset = fdt_next_node(fdt_header_, offset, nullptr);
if (offset < 0) break;
const auto *prop = fdt_get_property(fdt_header_, offset, "device_type", nullptr);
if (prop != nullptr) {
const char *device_type = reinterpret_cast<const char *>(prop->data);
if (strcmp(device_type, "cpu") == 0) {
++core_count;
}
}
}
return core_count;
}BasicInfo::BasicInfo(int, const char **argv) {
// 从设备树获取内存信息
auto [memory_base, memory_size] =
KernelFdtSingleton::instance().GetMemory();
physical_memory_addr = memory_base;
physical_memory_size = memory_size;
// 内核地址和大小
kernel_addr = reinterpret_cast<uint64_t>(__executable_start);
kernel_size = reinterpret_cast<uint64_t>(end) -
reinterpret_cast<uint64_t>(__executable_start);
// 设备树地址
fdt_addr = reinterpret_cast<uint64_t>(argv);
// CPU核心数
core_count = KernelFdtSingleton::instance().GetCoreCount();
}每个Hart分配4KB独立栈空间:
// Hart栈地址计算: stack_top + (hart_id + 1) * 4KB
add t0, a0, 1 // hart_id + 1
slli t0, t0, 12 // * 4096
la sp, stack_top // 栈基址
add sp, sp, t0 // 最终栈指针
.section .bss.boot
.align 16
.global stack_top
stack_top:
.space 4096 * 4 // 总共16KB栈空间// 启动Hart
struct sbiret sbi_hart_start(unsigned long hartid,
unsigned long start_addr,
unsigned long opaque);
// 停止Hart
struct sbiret sbi_hart_stop(void);
// 获取Hart状态
struct sbiret sbi_hart_get_status(unsigned long hartid);
// Hart挂起
struct sbiret sbi_hart_suspend(uint32_t suspend_type,
unsigned long resume_addr,
unsigned long opaque);enum {
SBI_SUCCESS = 0,
SBI_ERR_FAILED = -1,
SBI_ERR_NOT_SUPPORTED = -2,
SBI_ERR_INVALID_PARAM = -3,
SBI_ERR_DENIED = -4,
SBI_ERR_INVALID_ADDRESS = -5,
SBI_ERR_ALREADY_AVAILABLE = -6, // Hart已经启动
SBI_ERR_ALREADY_STARTED = -7,
SBI_ERR_ALREADY_STOPPED = -8,
SBI_ERR_NO_SHMEM = -9,
};- 基于标准SBI HSM扩展的多核启动
- 简洁的64位启动序列,无需模式切换
- 通过设备树动态获取CPU核心数
- 基于tp寄存器的高效核心ID管理
- 完整的Hart状态管理支持
- 使用OpenSBI固件接口
- ArchInitSMP()函数为空实现,缺少AP特定初始化
- 缺少Hart间通信机制(IPI)
- 固定的栈大小分配(4KB per Hart)
- 简化的错误处理机制
- 依赖外部OpenSBI固件支持
系统提供Hart状态查询功能:
auto status = sbi_hart_get_status(hart_id);
if (status.error == SBI_SUCCESS) {
klog::Info("Hart %d status: %s\n", hart_id,
HSM_HART_STATES_NAME[status.value]);
}支持的状态包括:
- STARTED: Hart正在运行
- STOPPED: Hart已停止
- START_PENDING: Hart启动中
- STOP_PENDING: Hart停止中
- SUSPENDED: Hart已挂起
- SUSPEND_PENDING: Hart挂起中
- RESUME_PENDING: Hart恢复中
AArch64 架构的多核唤醒机制基于 PSCI (Power State Coordination Interface) 标准,通过 SMC (Secure Monitor Call) 指令与 EL3 固件通信来管理 CPU 核心的电源状态。PSCI 提供了标准化的多核管理接口,简化了操作系统的多核启动流程。
- 标准化接口: ARM 标准的电源管理和多核控制接口
- SMC调用: 通过 Secure Monitor Call 与 EL3 固件通信
- 电源状态管理: 支持 CPU ON/OFF、SUSPEND/RESUME 等状态转换
PSCI错误码 (3rd/cpu_io/include/aarch64/cpu.hpp):
enum ErrorCode {
SUCCESS = 0,
NOT_SUPPORTED = -1,
INVALID_PARAMETERS = -2,
DENIED = -3,
ALREADY_ON = -4, // CPU已经启动
ON_PENDING = -5, // CPU启动中
INTERNAL_FAILURE = -6,
NOT_PRESENT = -7,
DISABLED = -8,
INVALID_ADDRESS = -9,
};SMC返回值结构:
struct SMCReturnValue {
uint64_t a0; // 返回码/状态
uint64_t a1; // 附加返回值
uint64_t a2; // 附加返回值
uint64_t a3; // 附加返回值
};MPIDR_EL1寄存器字段 (多处理器亲和性寄存器):
struct MPIDR_EL1Info {
struct Aff3 { /* 位[39:32] 亲和性级别3 */ };
struct Aff2 { /* 位[23:16] 亲和性级别2 */ };
struct Aff1 { /* 位[15:8] 亲和性级别1 */ };
struct Aff0 { /* 位[7:0] 亲和性级别0 */ };
struct MT { /* 位[24] 多线程标志 */ };
struct U { /* 位[30] 单/多处理器标志 */ };
};在 src/arch/aarch64/arch_main.cpp 的 ArchInit() 函数中:
void ArchInit(int argc, const char **argv) {
// 1. 解析设备树获取系统信息
KernelFdtSingleton::create(strtoull(argv[2], nullptr, 16));
// 2. 初始化串口
auto [serial_base, serial_size, irq] =
KernelFdtSingleton::instance().GetSerial();
Pl011Singleton::create(serial_base);
// 3. 初始化基本信息
BasicInfoSingleton::create(argc, argv);
// 4. 解析内核ELF信息
KernelElfSingleton::create(BasicInfoSingleton::instance().elf_addr);
// 5. 检查PSCI支持
KernelFdtSingleton::instance().CheckPSCI();
// 6. 启动所有CPU核心
for (size_t i = 0; i < BasicInfoSingleton::instance().core_count; i++) {
auto ret = cpu_io::psci::CpuOn(i, reinterpret_cast<uint64_t>(_boot), 0);
if ((ret != cpu_io::psci::SUCCESS) && (ret != cpu_io::psci::ALREADY_ON)) {
klog::Warn("cpu %d start failed: %d\n", i, ret);
}
}
}位于 src/arch/aarch64/boot.S,实现简洁的AArch64启动序列:
.section .text.boot
.global _boot
_boot:
// 获取CPU ID (从MPIDR_EL1寄存器)
mrs x10, mpidr_el1
and x10, x10, #0xFF // 提取Aff0字段作为CPU ID
// 根据CPU ID设置独立栈
add x10, x10, #1 // x10 = cpu_id + 1
lsl x10, x10, #12 // x10 *= 4096 (4KB per CPU)
ldr x11, =stack_top // 加载栈顶基址
add x11, x11, x10 // 计算该CPU的栈顶
mov sp, x11 // 设置栈指针
// 保存传递的参数到栈
stp x0, x1, [sp, #-16]! // 保存参数并调整栈指针
// 跳转到C代码入口
bl _start
// 如果返回则进入死循环
b .cpu_io::psci::CpuOn() 函数实现:
static __always_inline auto CpuOn(uint64_t target_cpu,
uint64_t entry_point_address,
uint64_t context_id) -> enum ErrorCode {
return (ErrorCode)SecureMonitorCall(kCPU_ON_64, target_cpu,
entry_point_address, context_id,
0, 0, 0, 0).a0;
}其中kCPU_ON_64 = 0xC4000003是PSCI标准定义的64位CPU启动功能码。
static __always_inline auto SecureMonitorCall(uint64_t a0, uint64_t a1,
uint64_t a2, uint64_t a3,
uint64_t a4, uint64_t a5,
uint64_t a6, uint64_t a7)
-> const SMCReturnValue {
SMCReturnValue result;
register uint64_t x0 __asm__("x0") = a0;
register uint64_t x1 __asm__("x1") = a1;
register uint64_t x2 __asm__("x2") = a2;
register uint64_t x3 __asm__("x3") = a3;
register uint64_t x4 __asm__("x4") = a4;
register uint64_t x5 __asm__("x5") = a5;
register uint64_t x6 __asm__("x6") = a6;
register uint64_t x7 __asm__("x7") = a7;
__asm__ volatile("smc #0"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3)
: "r"(x4), "r"(x5), "r"(x6), "r"(x7)
: "memory");
result.a0 = x0; // 返回码
result.a1 = x1; // 附加返回值
result.a2 = x2;
result.a3 = x3;
return result;
}CPU启动后通过 src/main.cpp 的 _start() 函数进入:
void _start(int argc, const char **argv) {
if (argv != nullptr) {
// BSP路径 (参数有效)
CppInit();
main(argc, argv);
CppDeInit();
} else {
// AP路径 (参数为空)
main_smp(argc, argv);
}
// 进入死循环
while (true) { ; }
}AP执行 main_smp() -> ArchInitSMP() (当前为空实现)
AArch64使用MPIDR_EL1 (Multiprocessor Affinity Register) 获取CPU亲和性信息:
// 获取当前CPU ID
static __always_inline auto GetCurrentCoreId() -> size_t {
return MPIDR_EL1::Aff0::Get(); // 返回亲和性级别0值
}- Aff0 [7:0]: 核心级别 - 同一集群内的核心编号
- Aff1 [15:8]: 集群级别 - 集群编号
- Aff2 [23:16]: 更高级别亲和性
- Aff3 [39:32]: 最高级别亲和性
// 读取MPIDR_EL1寄存器
static __always_inline auto Read() -> typename RegInfo::DataType {
typename RegInfo::DataType value{};
__asm__ volatile("mrs %0, MPIDR_EL1" : "=r"(value) : :);
return value;
}
// 提取Aff0字段
static __always_inline auto Get() -> typename RegInfo::DataType {
return static_cast<typename RegInfo::DataType>(
(Read() & RegInfo::kBitMask) >> RegInfo::kBitOffset);
}验证设备树中的PSCI配置:
void CheckPSCI() const {
// 1. 查找PSCI节点
auto offset = fdt_path_offset(fdt_header_, "/psci");
if (offset < 0) {
klog::Err("Error finding /psci node: %s\n", fdt_strerror(offset));
return;
}
// 2. 检查调用方法
const auto *method_prop = fdt_get_property(fdt_header_, offset, "method", &len);
const char *method_str = reinterpret_cast<const char *>(method_prop->data);
klog::Debug("PSCI method: %s\n", method_str);
// 当前只支持SMC方法
if (strcmp(method_str, "smc") != 0) {
klog::Err("Unsupported PSCI method: %s\n", method_str);
}
// 3. 验证功能ID
assert_function_id("cpu_on", 0xC4000003);
assert_function_id("cpu_off", 0x84000002);
assert_function_id("cpu_suspend", 0xC4000001);
}每个CPU分配4KB独立栈空间:
// CPU栈地址计算: stack_top + (cpu_id + 1) * 4KB
add x10, x10, #1 // cpu_id + 1
lsl x10, x10, #12 // * 4096
ldr x11, =stack_top // 栈基址
add x11, x11, x10 // 最终栈指针
.section .bss.boot
.align 16
.global stack_top
stack_top:
.space 4096 * 4 // 总共16KB栈空间// CPU启动
auto CpuOn(uint64_t target_cpu, uint64_t entry_point_address,
uint64_t context_id) -> enum ErrorCode;
// CPU关闭
auto CpuOff() -> enum ErrorCode;
// CPU挂起
auto CpuSuspend(PowerState power_state, uint64_t entry_point_address,
uint64_t context_id) -> enum ErrorCode;CPU标识符遵循MPIDR格式:
- 位[39:32]: Aff3 - 匹配目标CPU的MPIDR Aff3
- 位[23:16]: Aff2 - 匹配目标CPU的MPIDR Aff2
- 位[15:8]: Aff1 - 匹配目标CPU的MPIDR Aff1
- 位[7:0]: Aff0 - 匹配目标CPU的MPIDR Aff0
- 位[63:40] 和 位[31:24]: 必须为0
struct PowerState {
uint32_t reserved1 : 6; // [31:26] 保留
uint32_t power_level : 2; // [25:24] 电源级别
uint32_t reserved0 : 7; // [23:17] 保留
uint32_t state_type : 1; // [16] 状态类型
struct StateID state_id; // [15:0] 状态ID
} __attribute__((packed));- 基于ARM标准PSCI接口的多核启动
- 通过SMC与EL3固件安全通信
- 基于MPIDR_EL1的层次化CPU标识
- 设备树驱动的动态配置
- 完整的CPU电源状态管理
- ArchInitSMP()函数为空实现,缺少AP特定初始化
- 只支持SMC调用方法,不支持HVC
- 固定的栈大小分配(4KB per CPU)
- 简化的错误处理机制
// 检查PSCI版本
auto version = SecureMonitorCall(kVERSION, 0, 0, 0, 0, 0, 0, 0);
klog::Info("PSCI Version: %d.%d\n",
(version.a0 >> 16) & 0xFFFF, version.a0 & 0xFFFF);
// 检查功能支持
auto features = SecureMonitorCall(kFEATURES, kCPU_ON_64, 0, 0, 0, 0, 0, 0);
if (features.a0 == SUCCESS) {
klog::Info("PSCI CPU_ON_64 supported\n");
}// 获取CPU亲和性信息
auto affinity_info = SecureMonitorCall(kAFFINITY_INFO_64, target_cpu,
0, 0, 0, 0, 0, 0);
klog::Info("CPU %d affinity state: %d\n", target_cpu, affinity_info.a0);常见的PSCI错误码处理:
- ALREADY_ON: CPU已经在运行,可以忽略
- ON_PENDING: CPU正在启动过程中,需要等待
- NOT_PRESENT: CPU不存在,检查设备树配置
- INVALID_PARAMETERS: 参数错误,检查target_cpu格式
- DENIED: 权限不足,检查EL3固件配置