SimpleKernel 实现了跨多个架构的完整中断处理系统,每个架构都有其特定的中断控制器和处理机制。
| 特性 |
RISC-V 64 |
AArch64 |
| 中断控制器 |
PLIC/CLINT |
GIC |
| 中断描述符 |
CSR + trap handler |
异常向量表 |
| 定时器 |
SBI Timer |
Generic Timer |
| 外部中断 |
PLIC中断路由 |
GIC分发 |
| 多核启动 |
SBI Hart管理 |
PSCI |
| 特权级别 |
M/S/U Mode |
EL0-3 |
┌─────────────────────────────────────────────────────────────┐
│ RISC-V 中断处理系统 │
├─────────────────────────────────────────────────────────────┤
│ InterruptBase (抽象基类) │
│ ├── Do(cause, context) │
│ └── RegisterInterruptFunc(cause, func) │
├─────────────────────────────────────────────────────────────┤
│ Interrupt (RISC-V实现) │
│ ├── trap 处理程序入口 │
│ ├── 异常/中断分发机制 │
│ ├── 中断处理函数数组管理 │
│ └── PLIC 中断控制器集成 │
├─────────────────────────────────────────────────────────────┤
│ PLIC (Platform-Level Interrupt Controller) │
│ ├── 外部中断源管理 │
│ ├── 优先级仲裁机制 │
│ ├── 中断路由配置 │
│ └── 中断完成确认 │
├─────────────────────────────────────────────────────────────┤
│ SBI 定时器集成 │
│ ├── 机器模式定时器中断 │
│ ├── 监管模式定时器代理 │
│ └── 时间片调度支持 │
├─────────────────────────────────────────────────────────────┤
│ 设备树(DT)中断配置 │
│ ├── PLIC 基地址解析 │
│ ├── 中断号映射 │
│ └── 设备中断配置 │
└─────────────────────────────────────────────────────────────┘
// 中断使能配置
void SetupInterrupts() {
// 使能监管模式外部中断、定时器中断和软件中断
cpu_io::SIE::SEIE::Set(); // 外部中断使能
cpu_io::SIE::STIE::Set(); // 定时器中断使能
cpu_io::SIE::SSIE::Set(); // 软件中断使能
// 设置 trap 处理程序入口
cpu_io::STVEC::Write(reinterpret_cast<uint64_t>(TrapEntry));
// 全局中断使能
cpu_io::SSTATUS::SIE::Set();
}
extern "C" void TrapEntry(); // 汇编实现的trap入口
// trap 分发函数
extern "C" uint64_t TrapHandler(uint64_t cause, uint64_t epc,
uint64_t context) {
// 检查是否为中断(最高位为1)
if (cause & (1ULL << 63)) {
uint64_t interrupt_cause = cause & ~(1ULL << 63);
return InterruptSingleton::instance().Do(
interrupt_cause,
reinterpret_cast<uint8_t*>(context)
);
} else {
// 处理异常(最高位为0)
return HandleException(cause, epc, context);
}
}
外部设备 → PLIC → Hart 中断线 → 读取 SCAUSE → 分发处理
SBI定时器 → M模式中断 → 代理到S模式 → SCAUSE[5] → 处理函数
class Interrupt : public InterruptBase {
static constexpr size_t kInterruptMaxCount = 64;
static std::array<InterruptFunc, kInterruptMaxCount> interrupt_handlers;
public:
uint64_t Do(uint64_t cause, uint8_t *context) override {
if (cause < kInterruptMaxCount && interrupt_handlers[cause]) {
return interrupt_handlers[cause](cause, context);
}
klog::Warn("Unhandled interrupt: cause=%lu\n", cause);
return 0;
}
};
void SetupPlic() {
auto plic_base = GetPlicBaseFromDT(); // 从设备树获取基地址
// 1. 设置所有中断源优先级(非零值启用)
for (uint32_t irq = 1; irq <= kMaxInterruptSources; irq++) {
WritePlicReg(plic_base, PLIC_PRIORITY_BASE + irq * 4, 1);
}
// 2. 为当前hart启用所有中断源
uint32_t hart_id = cpu_io::GetCurrentCoreId();
uint64_t enable_reg = plic_base + PLIC_ENABLE_BASE +
hart_id * PLIC_ENABLE_STRIDE;
// 启用中断源 1-63 (每个bit代表一个中断源)
WritePlicReg(enable_reg, 0x0, 0xFFFFFFFE); // bits 1-31
WritePlicReg(enable_reg, 0x4, 0xFFFFFFFF); // bits 32-63
// 3. 设置中断优先级阈值(0表示接受所有优先级)
uint64_t threshold_reg = plic_base + PLIC_THRESHOLD_BASE +
hart_id * PLIC_THRESHOLD_STRIDE;
WritePlicReg(threshold_reg, 0x0, 0);
}
uint64_t PlicInterruptHandler(uint64_t cause, uint8_t *context) {
uint32_t hart_id = cpu_io::GetCurrentCoreId();
uint64_t plic_base = GetPlicBaseFromDT();
// 1. 声明(claim)中断 - 获取最高优先级的待处理中断
uint64_t claim_reg = plic_base + PLIC_CLAIM_BASE +
hart_id * PLIC_CLAIM_STRIDE;
uint32_t irq = ReadPlicReg(claim_reg, 0x0);
if (irq == 0) {
klog::Warn("Spurious PLIC interrupt\n");
return 0;
}
klog::Debug("PLIC interrupt: IRQ %u\n", irq);
// 2. 调用特定设备的中断处理程序
auto device_handler = GetDeviceHandler(irq);
if (device_handler) {
device_handler(irq, context);
}
// 3. 完成(complete)中断 - 通知PLIC中断处理完成
WritePlicReg(claim_reg, 0x0, irq);
return 0;
}
constexpr uint64_t kTimerIntervalCycles = 10000000; // 10M cycles ≈ 100Hz
void SetupTimer() {
// 设置下一次定时器中断时间
uint64_t current_time = cpu_io::Time::Read();
sbi::SetTimer(current_time + kTimerIntervalCycles);
// 注册定时器中断处理函数 (监管模式定时器中断 = 5)
InterruptSingleton::instance().RegisterInterruptFunc(
5, TimerInterruptHandler
);
}
uint64_t TimerInterruptHandler(uint64_t cause, uint8_t *context) {
static uint64_t tick_count = 0;
tick_count++;
// 设置下一次定时器中断
uint64_t current_time = cpu_io::Time::Read();
sbi::SetTimer(current_time + kTimerIntervalCycles);
// 降低日志输出频率
if (tick_count % 100 == 0) {
klog::Info("Timer interrupt %lu, cause %lu\n", tick_count, cause);
}
return 0;
}
void SetupUartInterrupt() {
// 从设备树获取UART中断号
uint32_t uart_irq = GetUartIrqFromDT();
// 在PLIC中启用UART中断
EnablePlicInterrupt(uart_irq);
// 注册UART中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
uart_irq, UartInterruptHandler
);
// 配置UART硬件启用中断
ConfigureUartInterrupts();
}
uint64_t UartInterruptHandler(uint64_t cause, uint8_t *context) {
// 读取UART中断状态
auto uart_base = GetUartBaseFromDT();
uint32_t interrupt_status = ReadUartReg(uart_base, UART_IIR_OFFSET);
// 处理接收中断
if (interrupt_status & UART_IIR_RDI) {
while (ReadUartReg(uart_base, UART_LSR_OFFSET) & UART_LSR_DR) {
char received_char = ReadUartReg(uart_base, UART_RBR_OFFSET);
klog::Info("UART received: '%c' (0x%02X)\n",
received_char, received_char);
// 回显字符
WriteUartReg(uart_base, UART_THR_OFFSET, received_char);
}
}
return 0;
}
void InterruptInit(int, const char **) {
// 1. 解析设备树获取中断配置
auto kernel_fdt = KernelFdtSingleton::instance();
// 2. 设置trap向量
cpu_io::STVEC::Write(reinterpret_cast<uint64_t>(TrapEntry));
// 3. 初始化PLIC
SetupPlic();
// 4. 注册定时器中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
5, TimerInterruptHandler // 监管模式定时器中断
);
// 5. 注册外部中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
9, PlicInterruptHandler // 监管模式外部中断
);
// 6. 启用中断
cpu_io::SIE::SEIE::Set(); // 外部中断
cpu_io::SIE::STIE::Set(); // 定时器中断
cpu_io::SSTATUS::SIE::Set(); // 全局中断使能
// 7. 启动定时器
SetupTimer();
// 8. 启动其他hart
StartSecondaryHarts();
klog::Info("RISC-V interrupt system initialized\n");
}
void InterruptInitSMP(int, const char **) {
// 1. 设置trap向量
cpu_io::STVEC::Write(reinterpret_cast<uint64_t>(TrapEntry));
// 2. 启用中断
cpu_io::SIE::SEIE::Set();
cpu_io::SIE::STIE::Set();
cpu_io::SSTATUS::SIE::Set();
// 3. 启动定时器
SetupTimer();
klog::Info("RISC-V SMP hart %lu initialized\n",
cpu_io::GetCurrentCoreId());
}
- PLIC优先级仲裁:硬件级中断优先级管理
- SBI定时器:高精度定时器服务
- 设备树配置:动态硬件配置发现
- 多hart支持:原生多核中断处理
- CSR直接访问:避免特权级切换开销
- PLIC声明/完成机制:确保中断不丢失
- OpenSBI集成:利用固件服务
- trap统一入口:简化异常和中断处理
┌─────────────────────────────────────────────────────────────┐
│ AArch64 中断处理系统 │
├─────────────────────────────────────────────────────────────┤
│ InterruptBase (抽象基类) │
│ ├── Do(cause, context) │
│ └── RegisterInterruptFunc(cause, func) │
├─────────────────────────────────────────────────────────────┤
│ Interrupt (AArch64实现) │
│ ├── 异常向量表(Vector Table) │
│ ├── 异常级别管理 (EL0-EL3) │
│ ├── 中断处理函数数组管理 │
│ └── GIC 中断控制器集成 │
├─────────────────────────────────────────────────────────────┤
│ GIC (Generic Interrupt Controller) │
│ ├── SGI (Software Generated Interrupts) │
│ ├── PPI (Private Peripheral Interrupts) │
│ ├── SPI (Shared Peripheral Interrupts) │
│ └── 中断优先级和路由管理 │
├─────────────────────────────────────────────────────────────┤
│ Generic Timer │
│ ├── 虚拟定时器 (EL1 Virtual Timer) │
│ ├── 物理定时器 (EL1 Physical Timer) │
│ ├── 高分辨率时间计数 │
│ └── 定时器中断生成 │
├─────────────────────────────────────────────────────────────┤
│ 设备树(DT)中断配置 │
│ ├── GIC 基地址解析 │
│ ├── 中断号映射关系 │
│ ├── 设备中断配置 │
│ └── PSCI 多核启动管理 │
└─────────────────────────────────────────────────────────────┘
// 异常向量表入口定义
extern "C" void vector_table(); // 汇编实现的向量表
// 向量表包含16个入口,每个入口128字节
struct ExceptionVectors {
// Current EL with SP0
void curr_el_sp0_sync(); // 同步异常
void curr_el_sp0_irq(); // IRQ中断
void curr_el_sp0_fiq(); // FIQ中断
void curr_el_sp0_serror(); // SError异常
// Current EL with SPx
void curr_el_spx_sync();
void curr_el_spx_irq();
void curr_el_spx_fiq();
void curr_el_spx_serror();
// Lower EL using AArch64
void lower_el_aarch64_sync();
void lower_el_aarch64_irq();
void lower_el_aarch64_fiq();
void lower_el_aarch64_serror();
// Lower EL using AArch32
void lower_el_aarch32_sync();
void lower_el_aarch32_irq();
void lower_el_aarch32_fiq();
void lower_el_aarch32_serror();
};
// C++异常处理函数
extern "C" void sync_exception_handler(uint64_t esr, uint64_t elr,
uint64_t context) {
uint32_t ec = (esr >> 26) & 0x3F; // Exception Class
uint32_t iss = esr & 0xFFFFFF; // Instruction Specific Syndrome
klog::Error("Sync exception: EC=0x%X, ISS=0x%X, ELR=0x%lX\n",
ec, iss, elr);
// 根据异常类型进行处理
switch (ec) {
case 0x15: // SVC instruction execution in AArch64 state
HandleSvc(iss, context);
break;
case 0x21: // Instruction abort from lower EL
HandleInstructionAbort(iss, elr);
break;
case 0x25: // Data abort from lower EL
HandleDataAbort(iss, elr);
break;
default:
klog::Error("Unhandled sync exception\n");
break;
}
}
extern "C" void irq_exception_handler(uint64_t context) {
// 读取中断确认寄存器获取中断ID
uint32_t intid = GicSingleton::instance().GetInterruptId();
if (intid == 1023) { // Spurious interrupt
klog::Warn("Spurious interrupt\n");
return;
}
// 调用注册的中断处理函数
InterruptSingleton::instance().Do(intid,
reinterpret_cast<uint8_t*>(context));
// 发送End of Interrupt信号
GicSingleton::instance().EndOfInterrupt(intid);
}
外部设备 → GIC分发器 → CPU接口 → 异常向量表 → IRQ处理器
class Interrupt : public InterruptBase {
static constexpr size_t kInterruptMaxCount = 1024; // GIC支持1024个中断
static std::array<InterruptFunc, kInterruptMaxCount> interrupt_handlers;
public:
uint64_t Do(uint64_t cause, uint8_t *context) override {
if (cause < kInterruptMaxCount && interrupt_handlers[cause]) {
return interrupt_handlers[cause](cause, context);
}
klog::Warn("Unhandled interrupt: INTID=%lu\n", cause);
return 0;
}
// 设置中断为SPI类型
void SPI(uint32_t intid, uint32_t cpu_id) {
GicSingleton::instance().SetInterruptType(intid,
Gic::InterruptType::SPI);
GicSingleton::instance().SetTargetCpu(intid, cpu_id);
GicSingleton::instance().EnableInterrupt(intid);
}
// 设置中断为PPI类型
void PPI(uint32_t intid, uint32_t cpu_id) {
GicSingleton::instance().SetInterruptType(intid,
Gic::InterruptType::PPI);
GicSingleton::instance().EnableInterrupt(intid);
}
};
class Gic {
public:
static constexpr uint32_t kSGIBase = 0; // SGI: 0-15
static constexpr uint32_t kPPIBase = 16; // PPI: 16-31
static constexpr uint32_t kSPIBase = 32; // SPI: 32-1019
void SetUP() {
auto gic_base = GetGicBaseFromDT(); // 从设备树获取基地址
// 1. 初始化分发器(Distributor)
InitDistributor(gic_base);
// 2. 初始化CPU接口
InitCpuInterface(gic_base);
// 3. 启用分发器
EnableDistributor();
}
private:
void InitDistributor(uint64_t dist_base) {
// 禁用分发器进行配置
WriteReg(dist_base + GICD_CTLR, 0);
// 配置所有SPI为边沿触发,高优先级
for (uint32_t i = kSPIBase; i < 1020; i += 32) {
WriteReg(dist_base + GICD_ICFGR + (i/16)*4, 0x55555555);
}
// 设置所有中断优先级
for (uint32_t i = 0; i < 1020; i += 4) {
WriteReg(dist_base + GICD_IPRIORITYR + i, 0xA0A0A0A0);
}
// 设置SPI目标CPU为CPU0
for (uint32_t i = kSPIBase; i < 1020; i += 4) {
WriteReg(dist_base + GICD_ITARGETSR + i, 0x01010101);
}
}
void InitCpuInterface(uint64_t cpu_base) {
// 设置优先级掩码(允许所有优先级)
WriteReg(cpu_base + GICC_PMR, 0xFF);
// 启用CPU接口
WriteReg(cpu_base + GICC_CTLR, GICC_CTLR_ENABLE);
}
};
uint32_t Gic::GetInterruptId() {
uint64_t cpu_base = GetGicCpuBaseFromDT();
// 读取中断确认寄存器
uint32_t iar = ReadReg(cpu_base + GICC_IAR);
return iar & 0x3FF; // INTID在低10位
}
void Gic::EndOfInterrupt(uint32_t intid) {
uint64_t cpu_base = GetGicCpuBaseFromDT();
// 写入中断结束寄存器
WriteReg(cpu_base + GICC_EOIR, intid);
}
void Gic::EnableInterrupt(uint32_t intid) {
uint64_t dist_base = GetGicDistBaseFromDT();
uint32_t reg_offset = (intid / 32) * 4;
uint32_t bit_offset = intid % 32;
// 设置使能位
WriteReg(dist_base + GICD_ISENABLER + reg_offset,
1U << bit_offset);
}
void SetupTimer() {
// 从设备树获取定时器中断ID
auto timer_intid = KernelFdtSingleton::instance()
.GetAarch64Intid("arm,armv8-timer") + Gic::kPPIBase;
// 配置为PPI类型中断
InterruptSingleton::instance().PPI(timer_intid,
cpu_io::GetCurrentCoreId());
// 注册定时器中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
timer_intid, timer_handler);
// 配置虚拟定时器
cpu_io::CNTV_CTL_EL0::ENABLE::Clear(); // 先禁用
cpu_io::CNTV_CTL_EL0::IMASK::Set(); // 屏蔽中断
// 设置定时器间隔 (2秒)
uint64_t interval_clk = 2 * cpu_io::CNTFRQ_EL0::Read();
cpu_io::CNTV_TVAL_EL0::Write(interval_clk);
// 启用定时器和中断
cpu_io::CNTV_CTL_EL0::ENABLE::Set(); // 启用定时器
cpu_io::CNTV_CTL_EL0::IMASK::Clear(); // 取消中断屏蔽
}
uint64_t timer_handler(uint64_t cause, uint8_t *context) {
static uint64_t tick_count = 0;
tick_count++;
// 重新设置下一次定时器中断
uint64_t interval_clk = 2 * cpu_io::CNTFRQ_EL0::Read();
cpu_io::CNTV_TVAL_EL0::Write(interval_clk);
// 降低日志输出频率
if (tick_count % 10 == 0) {
klog::Info("Timer interrupt %lu, INTID %lu\n", tick_count, cause);
}
return 0;
}
void SetupUartInterrupt() {
// 从设备树获取UART中断ID
auto uart_intid = KernelFdtSingleton::instance()
.GetAarch64Intid("arm,pl011") + Gic::kSPIBase;
// 配置为SPI类型中断,路由到当前CPU
InterruptSingleton::instance().SPI(uart_intid,
cpu_io::GetCurrentCoreId());
// 注册UART中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
uart_intid, uart_handler);
}
uint64_t uart_handler(uint64_t cause, uint8_t *context) {
auto uart_base = GetUartBaseFromDT();
// 读取中断状态
uint32_t mis = ReadReg(uart_base + PL011_MIS);
// 处理接收中断
if (mis & PL011_MIS_RXMIS) {
while (!(ReadReg(uart_base + PL011_FR) & PL011_FR_RXFE)) {
char received_char = ReadReg(uart_base + PL011_DR) & 0xFF;
klog::Info("UART received: '%c' (0x%02X)\n",
received_char, received_char);
// 回显字符
WriteReg(uart_base + PL011_DR, received_char);
}
// 清除接收中断
WriteReg(uart_base + PL011_ICR, PL011_ICR_RXIC);
}
// 处理发送中断
if (mis & PL011_MIS_TXMIS) {
// 发送缓冲区空,可以发送更多数据
WriteReg(uart_base + PL011_ICR, PL011_ICR_TXIC);
}
return 0;
}
void InterruptInit(int, const char **) {
// 1. 设置异常向量表基地址
cpu_io::VBAR_EL1::Write(reinterpret_cast<uint64_t>(vector_table));
// 2. 初始化GIC
InterruptSingleton::instance().SetUP();
// 3. 配置定时器中断
auto timer_intid = KernelFdtSingleton::instance()
.GetAarch64Intid("arm,armv8-timer") + Gic::kPPIBase;
InterruptSingleton::instance().PPI(timer_intid,
cpu_io::GetCurrentCoreId());
InterruptSingleton::instance().RegisterInterruptFunc(
timer_intid, timer_handler);
// 4. 配置UART中断
auto uart_intid = KernelFdtSingleton::instance()
.GetAarch64Intid("arm,pl011") + Gic::kSPIBase;
InterruptSingleton::instance().SPI(uart_intid,
cpu_io::GetCurrentCoreId());
InterruptSingleton::instance().RegisterInterruptFunc(
uart_intid, uart_handler);
// 5. 启用中断
cpu_io::EnableInterrupt();
// 6. 启动定时器
SetupTimer();
// 7. 启动其他CPU核心
StartSecondaryCpus();
klog::Info("AArch64 interrupt system initialized\n");
}
void InterruptInitSMP(int, const char **) {
// 1. 设置异常向量表
cpu_io::VBAR_EL1::Write(reinterpret_cast<uint64_t>(vector_table));
// 2. 初始化GIC CPU接口
InterruptSingleton::instance().SetUP();
// 3. 配置定时器中断
auto timer_intid = KernelFdtSingleton::instance()
.GetAarch64Intid("arm,armv8-timer") + Gic::kPPIBase;
InterruptSingleton::instance().PPI(timer_intid,
cpu_io::GetCurrentCoreId());
InterruptSingleton::instance().RegisterInterruptFunc(
timer_intid, timer_handler);
// 4. 启用中断
cpu_io::EnableInterrupt();
// 5. 启动定时器
SetupTimer();
klog::Info("AArch64 SMP CPU %u initialized\n",
cpu_io::GetCurrentCoreId());
}
void StartSecondaryCpus() {
size_t core_count = BasicInfoSingleton::instance().core_count;
for (size_t i = 1; i < core_count; i++) { // 跳过CPU 0
// 使用PSCI启动CPU
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);
} else {
klog::Info("CPU %d started successfully\n", i);
}
}
}
- 异常级别隔离:EL0-EL3提供完整的特权级保护
- GIC硬件优先级:高效的中断仲裁和路由
- Generic Timer:高精度系统定时器
- PSCI标准:标准化的多核电源管理
- 向量表对齐:2KB对齐要求确保性能
- 中断类型分类:SGI/PPI/SPI满足不同场景需求
- 设备树集成:动态硬件配置发现
- 编译器限制:手动异常处理避免属性限制
| 特性 |
RISC-V PLIC |
AArch64 GIC |
| 中断数量 |
可配置(通常1024) |
1024个INTID |
| 优先级支持 |
可配置级别 |
256级 |
| 多核支持 |
每hart独立 |
分发器+CPU接口 |
| 中断类型 |
外部中断 |
SGI/PPI/SPI |
| EOI机制 |
PLIC Complete |
GIC EOIR寄存器 |
| 架构 |
定时器类型 |
精度 |
编程接口 |
| RISC-V |
Machine Timer |
固定频率 |
SBI调用 |
| AArch64 |
Generic Timer |
系统频率 |
系统寄存器 |
- RISC-V: 设备树解析 + CSR配置
- AArch64: 异常向量表 + GIC多阶段初始化
- RISC-V: 简洁的CSR接口,SBI服务集成
- AArch64: 硬件优先级仲裁,多级异常处理
这种多架构设计确保了SimpleKernel在不同硬件平台上的高效运行,同时保持了统一的编程接口。
┌─────────────────────────────────────────────────────────────┐
│ RISC-V 64 中断处理系统 │
├─────────────────────────────────────────────────────────────┤
│ InterruptBase (抽象基类) │
│ ├── Do(cause, context) │
│ └── RegisterInterruptFunc(cause, func) │
├─────────────────────────────────────────────────────────────┤
│ Interrupt (RISC-V实现) │
│ ├── 中断/异常分离处理 │
│ ├── CSR scause 解码 │
│ ├── 中断处理函数数组 │
│ └── 异常处理函数数组 │
├─────────────────────────────────────────────────────────────┤
│ PLIC (Platform-Level Interrupt Controller) │
│ ├── 外部中断路由 │
│ ├── 中断优先级管理 │
│ ├── 多 Hart 中断分发 │
│ └── 中断完成确认 │
├─────────────────────────────────────────────────────────────┤
│ OpenSBI 接口 │
│ ├── SBI 定时器服务 │
│ ├── Hart 启动管理 │
│ ├── 系统调用接口 │
│ └── 调试控制台 │
├─────────────────────────────────────────────────────────────┤
│ 设备特定中断 │
│ ├── 定时器中断 (SBI Timer) │
│ ├── 串口中断 (NS16550A) │
│ ├── 外部中断 (PLIC) │
│ └── 断点异常 (ebreak) │
└─────────────────────────────────────────────────────────────┘
// 中断/异常处理相关的CSR寄存器
- stvec: Supervisor Trap Vector Base Address (陷阱向量基址)
- scause: Supervisor Cause Register (陷阱原因)
- sstatus: Supervisor Status Register (监管者状态)
- sie: Supervisor Interrupt Enable (监管者中断使能)
- sip: Supervisor Interrupt Pending (监管者中断挂起)
- sepc: Supervisor Exception Program Counter (异常PC)
- stval: Supervisor Trap Value (陷阱值)
void Interrupt::Do(uint64_t cause, uint8_t *context) {
// 解析 scause 寄存器
auto interrupt = cpu_io::Scause::Interrupt::Get(cause); // 最高位
auto exception_code = cpu_io::Scause::ExceptionCode::Get(cause); // 低位
if (interrupt) {
// 处理中断 (异步事件)
if (exception_code < kInterruptMaxCount) {
interrupt_handlers_[exception_code](exception_code, context);
}
} else {
// 处理异常 (同步事件)
if (exception_code < kExceptionMaxCount) {
exception_handlers_[exception_code](exception_code, context);
}
}
}
// 设置陷阱向量 - 直接模式
__attribute__((interrupt("supervisor")))
alignas(4) void TarpEntry() {
InterruptSingleton::instance().Do(
static_cast<uint64_t>(cpu_io::Scause::Read()), nullptr
);
}
// 初始化时设置
cpu_io::Stvec::SetDirect(reinterpret_cast<uint64_t>(TarpEntry));
enum SupervisorInterrupts {
kSupervisorSoftwareInterrupt = 1, // S模式软件中断
kSupervisorTimerInterrupt = 5, // S模式定时器中断
kSupervisorExternalInterrupt = 9, // S模式外部中断
};
enum SupervisorExceptions {
kInstructionAddressMisaligned = 0, // 指令地址不对齐
kInstructionAccessFault = 1, // 指令访问错误
kIllegalInstruction = 2, // 非法指令
kBreakpoint = 3, // 断点异常
kLoadAddressMisaligned = 4, // 加载地址不对齐
kLoadAccessFault = 5, // 加载访问错误
kStoreAddressMisaligned = 6, // 存储地址不对齐
kStoreAccessFault = 7, // 存储访问错误
kEnvironmentCall = 8, // 环境调用
kInstructionPageFault = 12, // 指令页错误
kLoadPageFault = 13, // 加载页错误
kStorePageFault = 15, // 存储页错误
};
namespace {
uint64_t kInterval = 0; // 定时器间隔
}
void InterruptInit(int, const char **) {
// 从设备树获取时钟频率
kInterval = KernelFdtSingleton::instance().GetTimebaseFrequency();
klog::Info("kInterval: 0x%X\n", kInterval);
// 注册定时器中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
kSupervisorTimerInterrupt,
[](uint64_t exception_code, uint8_t *) -> uint64_t {
// 设置下一次定时器中断
sbi_set_timer(cpu_io::Time::Read() + kInterval);
klog::Info("Handle %s\n", kInterruptNames[exception_code]);
return 0;
}
);
// 启用定时器中断
cpu_io::Sie::Stie::Set();
// 设置首次定时器中断
sbi_set_timer(kInterval);
}
// 设置定时器中断时间 (绝对时间)
sbi_set_timer(cpu_io::Time::Read() + kInterval);
// 读取当前时间
uint64_t current_time = cpu_io::Time::Read();
void InterruptInit(int, const char **) {
// 从设备树获取PLIC信息
auto [plic_addr, plic_size, ndev, context_count] =
KernelFdtSingleton::instance().GetPlic();
// 初始化PLIC实例
PlicSingleton::create(plic_addr, ndev, context_count);
// 注册外部中断处理函数
InterruptSingleton::instance().RegisterInterruptFunc(
kSupervisorExternalInterrupt,
[](uint64_t exception_code, uint8_t *) -> uint64_t {
// 查询中断源
auto source_id = PlicSingleton::instance().Which();
klog::Debug("External interrupt from source %d\n", source_id);
// 执行中断处理
PlicSingleton::instance().Do(source_id, nullptr);
// 完成中断处理
PlicSingleton::instance().Done(source_id);
return 0;
}
);
// 启用外部中断
cpu_io::Sie::Seie::Set();
}
class Plic {
private:
static constexpr uint64_t kSourcePriorityOffset = 0x000000; // 优先级
static constexpr uint64_t kPendingBitsOffset = 0x001000; // 挂起位
static constexpr uint64_t kEnableBitsOffset = 0x002000; // 使能位
static constexpr uint64_t kContextOffset = 0x200000; // 上下文
static constexpr uint64_t kContextSize = 0x1000; // 上下文大小
static constexpr uint64_t kPriorityThresholdOffset = 0x0; // 优先级阈值
static constexpr uint64_t kClaimCompleteOffset = 0x4; // 声明/完成
};
// 1. 中断触发 → PLIC 路由到指定 Hart
// 2. Hart 接收外部中断 → 查询中断源
auto source_id = PlicSingleton::instance().Which();
// 3. 执行设备特定的中断处理
PlicSingleton::instance().Do(source_id, nullptr);
// 4. 通知 PLIC 中断处理完成
PlicSingleton::instance().Done(source_id);
void InterruptInit(int, const char **) {
// 从设备树获取串口信息
auto [base, size, irq] = KernelFdtSingleton::instance().GetSerial();
// 初始化串口驱动
Ns16550aSingleton::create(base);
// 注册串口中断处理函数
PlicSingleton::instance().RegisterInterruptFunc(
irq, // 串口IRQ号
[](uint64_t, uint8_t *) -> uint64_t {
// 读取串口字符并回显
sk_putchar(Ns16550aSingleton::instance().TryGetChar(), nullptr);
return 0;
}
);
// 为当前核心启用串口中断
PlicSingleton::instance().Set(
cpu_io::GetCurrentCoreId(), // Hart ID
irq, // 中断源ID
1, // 优先级
true // 启用
);
}
// 注册断点异常处理
InterruptSingleton::instance().RegisterInterruptFunc(
kBreakpoint,
[](uint64_t exception_code, uint8_t *) -> uint64_t {
// ebreak 指令是2字节,需要跳过
cpu_io::Sepc::Write(cpu_io::Sepc::Read() + 2);
klog::Info("Handle %s\n", kExceptionNames[exception_code]);
return 0;
}
);
Interrupt::Interrupt() {
// 默认异常处理 - 系统停机
for (auto &i : exception_handlers_) {
i = [](uint64_t cause, uint8_t *context) -> uint64_t {
klog::Err("Default Exception handler [%s] 0x%X, 0x%p\n",
kExceptionNames[cause], cause, context);
while (1) ; // 停机等待
return 0;
};
}
}
void InterruptInit(int, const char **) {
// 1. 获取系统配置信息
kInterval = KernelFdtSingleton::instance().GetTimebaseFrequency();
// 2. 注册所有中断/异常处理函数
RegisterTimerInterrupt();
RegisterExternalInterrupt();
RegisterSerialInterrupt();
RegisterBreakpointException();
// 3. 初始化硬件控制器
InitializePlic();
InitializeSerial();
// 4. 设置陷阱向量和启用中断
cpu_io::Stvec::SetDirect(reinterpret_cast<uint64_t>(TarpEntry));
cpu_io::Sstatus::Sie::Set(); // 启用监管者中断
cpu_io::Sie::Ssie::Set(); // 启用软件中断
cpu_io::Sie::Stie::Set(); // 启用定时器中断
cpu_io::Sie::Seie::Set(); // 启用外部中断
// 5. 启动定时器
sbi_set_timer(kInterval);
// 6. 启动其他核心
for (size_t i = 0; i < 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);
}
}
}
void InterruptInitSMP(int, const char **) {
// 1. 设置陷阱向量 (与BSP相同)
cpu_io::Stvec::SetDirect(reinterpret_cast<uint64_t>(TarpEntry));
// 2. 启用中断 (与BSP相同)
cpu_io::Sstatus::Sie::Set();
cpu_io::Sie::Ssie::Set();
cpu_io::Sie::Stie::Set();
cpu_io::Sie::Seie::Set();
// 3. 启动定时器 (使用全局间隔)
sbi_set_timer(kInterval);
klog::Info("Hello InterruptInitSMP\n");
}
// Hart 管理
sbi_hart_start(hart_id, start_addr, priv); // 启动指定Hart
sbi_hart_stop(); // 停止当前Hart
sbi_hart_get_status(hart_id); // 获取Hart状态
// 定时器服务
sbi_set_timer(stime_value); // 设置定时器
uint64_t time = cpu_io::Time::Read(); // 读取当前时间
// 调试服务
sbi_debug_console_write_byte(ch); // 调试控制台输出
// 系统重置
sbi_system_reset(reset_type, reset_reason); // 系统重置
auto ret = sbi_hart_start(i, start_addr, 0);
switch (ret.error) {
case SBI_SUCCESS:
klog::Info("Hart %zu started successfully\n", i);
break;
case SBI_ERR_ALREADY_AVAILABLE:
klog::Debug("Hart %zu already running\n", i);
break;
default:
klog::Warn("Hart %zu start failed: %ld\n", i, ret.error);
break;
}
class KernelFdt {
public:
// 获取时钟频率
uint64_t GetTimebaseFrequency();
// 获取PLIC信息 <地址, 大小, 设备数, 上下文数>
std::tuple<uint64_t, uint64_t, size_t, size_t> GetPlic();
// 获取串口信息 <地址, 大小, IRQ号>
std::tuple<uint64_t, uint64_t, uint32_t> GetSerial();
};
// 使用示例
auto [plic_addr, plic_size, ndev, context_count] =
KernelFdtSingleton::instance().GetPlic();
auto [serial_base, serial_size, serial_irq] =
KernelFdtSingleton::instance().GetSerial();
// 4字节对齐的中断处理函数数组
alignas(4) std::array<InterruptFunc, kInterruptMaxCount> interrupt_handlers_;
alignas(4) std::array<InterruptFunc, kExceptionMaxCount> exception_handlers_;
// 4字节对齐的陷阱入口
__attribute__((interrupt("supervisor"))) alignas(4) void TarpEntry();
// 分离的处理数组避免无效的范围检查
static std::array<InterruptFunc, kInterruptMaxCount> interrupt_handlers_;
static std::array<InterruptFunc, kExceptionMaxCount> exception_handlers_;
// 利用RISC-V CSR指令的原子性
auto cause = cpu_io::Scause::Read(); // 原子读取
cpu_io::Sepc::Write(pc + 2); // 原子写入
| 组件 |
BSP (主核心) |
AP (应用核心) |
| 设备树解析 |
✅ |
❌ (共享) |
| 中断处理函数注册 |
✅ |
❌ (共享) |
| PLIC初始化 |
✅ |
❌ (共享) |
| 串口配置 |
✅ |
❌ (共享) |
| CSR配置 |
✅ |
✅ |
| 定时器启动 |
✅ |
✅ |
| 其他核心启动 |
✅ |
❌ |
- 每核独立CSR: 每个Hart有自己的CSR副本
- 共享PLIC: 所有Hart共享PLIC,通过上下文隔离
- 共享处理函数: 中断处理函数在所有核心间共享
- 原子操作: CSR访问具有硬件原子性保证
// 中断注册调试信息
klog::Info("RegisterInterruptFunc [%s] 0x%X, 0x%p\n",
kInterruptNames[exception_code], cause, func);
// PLIC外部中断调试
klog::Debug("External interrupt from source %d\n", source_id);
// CSR状态监控
klog::Debug("scause: 0x%lX, sepc: 0x%lX\n",
cpu_io::Scause::Read(), cpu_io::Sepc::Read());
// 异常处理时的详细信息输出
klog::Err("Exception [%s] at PC 0x%lX, tval: 0x%lX\n",
kExceptionNames[cause],
cpu_io::Sepc::Read(),
cpu_io::Stval::Read());
// 监管者模式中断 (scause[63]=1)
#define S_SOFTWARE_INTERRUPT 1 // 软件中断
#define S_TIMER_INTERRUPT 5 // 定时器中断
#define S_EXTERNAL_INTERRUPT 9 // 外部中断
// 监管者模式异常 (scause[63]=0)
#define INSTRUCTION_MISALIGNED 0 // 指令不对齐
#define INSTRUCTION_ACCESS_FAULT 1 // 指令访问错误
#define ILLEGAL_INSTRUCTION 2 // 非法指令
#define BREAKPOINT 3 // 断点
#define LOAD_MISALIGNED 4 // 加载不对齐
#define LOAD_ACCESS_FAULT 5 // 加载访问错误
#define STORE_MISALIGNED 6 // 存储不对齐
#define STORE_ACCESS_FAULT 7 // 存储访问错误
#define ECALL_FROM_U_MODE 8 // 用户模式环境调用
#define ECALL_FROM_S_MODE 9 // 监管者模式环境调用
#define INSTRUCTION_PAGE_FAULT 12 // 指令页错误
#define LOAD_PAGE_FAULT 13 // 加载页错误
#define STORE_PAGE_FAULT 15 // 存储页错误
// PLIC 上下文计算 (通常为 2 * hart_count)
Context 0: Hart 0 M-mode
Context 1: Hart 0 S-mode
Context 2: Hart 1 M-mode
Context 3: Hart 1 S-mode
...