4、RISC-V架构基础:特权级架构(M/S/U)、CSR寄存器、中断控制器(PLIC/CLINT)概述
将CFS调度器从x86移植到RISC-V,首先需要理解RISC-V的核心架构基础。与x86的复杂指令集和环形特权级(Ring 0~3)不同,RISC-V采用精简指令集和清晰的特权级分层。本章将重点剖析RISC-V的特权级架构、控制状态寄存器(CSR)以及中断控制器(PLIC/CLINT),为后续调度器上下文切换、中断处理与时钟管理的移植工作奠定基础。
4.1 特权级架构:M/S/U三层模型
RISC-V定义了三个特权级,从高到低依次为机器模式(M Mode)、监管模式(S Mode)和用户模式(U Mode)。这种分层设计直接决定了操作系统内核与用户程序的隔离方式,以及调度器在哪个层级运行。
| 特权级 | 编码 | 名称 | 主要用途 | x86对应 |
|---|---|---|---|---|
| M | 11 | 机器模式 (Machine Mode) | 固件、BootROM、安全监控、异常处理最底层 | Ring -1 (SMM) |
| S | 01 | 监管模式 (Supervisor Mode) | 操作系统内核、页表管理、中断处理 | Ring 0 |
| U | 00 | 用户模式 (User Mode) | 应用程序运行 | Ring 3 |
下图展示了RISC-V的三级特权模型及其与操作系统各组件的对应关系:
4.2 CSR寄存器:调度器操作的核心接口
控制状态寄存器(CSR)是RISC-V架构中用于配置和控制处理器状态的关键寄存器。与x86的MSR类似,CSR通过专用的csrrw、csrrs、csrrc等指令进行读写。对于CFS调度器移植,以下CSR至关重要:
- sstatus (Supervisor Status Register):控制全局中断使能、用户模式访问权限等。调度器在切换进程时需要保存和恢复该寄存器。
- stvec (Supervisor Trap Vector Base Address Register):设置S Mode异常/中断入口地址。调度器初始化时需将其指向
handle_arch_irq或do_IRQ。 - sscratch (Supervisor Scratch Register):通常用于保存每个CPU的核心数据结构指针(如
cpu_struct),在中断入口快速获取当前CPU信息。 - sepc (Supervisor Exception Program Counter):保存发生异常或中断时的返回地址。上下文切换时需保存到任务栈中。
- scause (Supervisor Cause Register):记录异常或中断的原因。调度器据此判断是时钟中断、IPI还是其他事件。
- stimecmp (Supervisor Timer Compare Register):S Mode下的定时器比较寄存器,用于触发时钟中断。这是CFS调度器获取时间片和进行负载均衡的关键硬件资源。
| CSR名称 | 地址 | 读写权限 | 调度器相关用途 |
|---|---|---|---|
| sstatus | 0x100 | SRW | 保存/恢复中断状态,控制S Mode全局中断 |
| stvec | 0x105 | SRW | 设置中断向量表基址,指向调度器中断入口 |
| sscratch | 0x140 | SRW | 保存每CPU数据结构指针,加速中断处理 |
| sepc | 0x141 | SRW | 保存异常返回地址,上下文切换时使用 |
| scause | 0x142 | SR | 判断中断类型(时钟/外部/软件) |
| stimecmp | 0x14D | SRW | 设置时钟中断触发阈值,驱动调度器tick |
stimecmp与硬件时间计数器time(通过rdtime伪指令读取)共同控制。调度器需要将stimecmp设置为当前时间加上时间片长度,以产生下一个tick中断。
下图展示了调度器在中断处理流程中与关键CSR的交互关系:
4.3 中断控制器:PLIC与CLINT
RISC-V的中断系统由两个主要控制器组成:CLINT(Core Local Interruptor)和PLIC(Platform Level Interrupt Controller)。它们分别负责核内中断和平台级外设中断的管理。
4.3.1 CLINT:核内中断与定时器
CLINT是每个RISC-V处理器核内部的中断控制器,主要负责:
- 软件中断(MSIP/SIP):用于核间通信(IPI),在SMP系统中唤醒其他CPU核心执行调度。
- 定时器中断(MTIP/STIP):基于
mtime和mtimecmp(M Mode)或stimecmp(S Mode)产生。CFS调度器依赖STIP获取周期性时钟中断。
在Linux内核中,CLINT的驱动通常由M Mode固件(如OpenSBI)封装,S Mode通过ECALL调用固件接口来设置定时器或发送IPI。调度器移植时,需要关注riscv_ipi_send()和riscv_timer_set()等底层函数的实现。
4.3.2 PLIC:平台级外设中断
PLIC负责管理所有平台级外设中断(如UART、网卡、磁盘控制器),并将中断路由到指定的CPU核。其核心特性包括:
- 中断优先级:支持多级优先级配置,高优先级中断可抢占低优先级。
- 中断使能:每个中断源可独立使能/禁用。
- 中断阈值:只有优先级高于阈值的中断才会被转发到CPU。
- 中断声明与完成:CPU读取claim寄存器获取中断号,处理完成后写入complete寄存器。
| 特性 | CLINT | PLIC |
|---|---|---|
| 管理范围 | 核内中断(定时器、软件中断) | 平台级外设中断 |
| 中断类型 | 本地中断,每个核独立 | 全局中断,可路由到任意核 |
| 调度器相关性 | 高(时钟tick、IPI调度) | 中(外设I/O完成唤醒进程) |
| 访问方式 | MMIO + CSR(stimecmp) | MMIO(memory-mapped I/O) |
| x86对应 | LAPIC(本地APIC) | IOAPIC(I/O APIC) |
mtimecmp(M Mode寄存器),必须通过SBI(Supervisor Binary Interface)调用固件服务。这意味着调度器中的时钟初始化代码需要从直接写硬件寄存器改为调用sbi_set_timer()函数。
下图展示了CLINT与PLIC在RISC-V系统中的位置及其与CPU核的关系:
4.4 中断委托机制:M Mode到S Mode
RISC-V支持将某些中断和异常从M Mode委托到S Mode处理,从而减少固件介入,提升性能。对于调度器而言,监管外部中断(SEIP)、监管定时器中断(STIP)和监管软件中断(SSIP)通常被委托到S Mode。
委托通过以下CSR配置:
- medeleg (Machine Exception Delegation Register):将异常委托给S Mode。
- mideleg (Machine Interrupt Delegation Register):将中断委托给S Mode。
在调度器移植中,需要确保固件(OpenSBI)正确配置了这些委托寄存器,使得时钟中断(STIP)和IPI(SSIP)能够直接到达S Mode的stvec入口,而不经过M Mode的额外处理。
- 确认
mideleg中STIP和SSIP位已置位(通常由OpenSBI在启动时完成)。 - 设置
stvec指向内核中断入口函数(如handle_arch_irq)。 - 在S Mode下使能全局中断(设置
sstatus.SIE位)。 - 通过SBI调用设置初始
stimecmp值,启动第一个时钟tick。