RISC-V PLIC 深度解析:从 Spec 到 Zephyr 驱动实现

PLIC简介

RISC-V架构本身只定义了处理器如何响应中断,并没有规定具体SoC中外设中断如何连接到CPU。

例如,一个SoC中可能存在:

  • UART
  • GPIO
  • SPI
  • DMA
  • Ethernet
  • PCIe

这些外设都会产生中断请求,如果每个外设直接连接CPU,会导致硬件连接复杂。

因此,RISC-V定义了 PLIC(Platform-Level Interrupt Controller ,平台级中断控制器),用于管理平台外部中断。

PLIC主要完成:

  • 汇聚多个Interrupt Source
  • 保存中断Pending状态
  • 根据Priority进行仲裁
  • 根据Hart Context分发中断
  • 通过Claim/Complete完成中断处理

PLIC在RISC-V中断体系中的位置

RISC-V中断主要分为两类:

  • Local Interrupt:CPU本地中断
  • External Interrupt:外部设备中断

PLIC负责的是External Interrupt。

外设产生中断后,首先进入PLIC。

PLIC完成仲裁后,将结果发送给CPU,CPU通过External Interrupt入口进入异常处理流程。

PLIC核心硬件模型

PLIC内部主要包含几个部分:

复制代码
Interrupt Source -> Interrupt Gateway -> Pending Register -> Priority Comparator -> Enable Register -> Threshold -> Claim / Complete

3.1 Interrupt Source

每一个外设中断对应一个Source ID。

例如:

复制代码
Source ID

1   UART
2   GPIO
3   DMA
4   SPI

PLIC通过Source ID区分不同外设。

Zephyr中对应:

复制代码
local_irq

3.2 Priority Register

每个Interrupt Source拥有一个优先级。

例如:

复制代码
DMA IRQ

priority = 7


UART IRQ

priority = 3

当多个中断同时Pending时,PLIC选择Priority最高的中断。

3.3 Pending Register

当外设产生中断后,PLIC记录Pending状态。

例如:

复制代码
GPIO IRQ5 triggered


Pending[5] = 1

表示:

该中断已经发生,但是还没有被CPU处理。

3.4 Enable Register

PLIC支持不同Hart Context独立控制中断是否开启。

例如:

复制代码
IRQ1 IRQ2 IRQ3


Context0      1    0    1


Context1      0    1    1

Context0接收IRQ1和IRQ3。

Context1接收IRQ2和IRQ3。

3.5 Hart Context

PLIC中一个重要概念是:

Interrupt Target不是简单的CPU,而是Hart Context。

一个Hart可能存在多个Context:

复制代码
Hart0

 |
 +---- M-mode Context
 |
 +---- S-mode Context



Hart1

 |
 +---- M-mode Context
 |
 +---- S-mode Context

因此PLIC寄存器不是简单:

复制代码
PLIC + IRQ

而是:

复制代码
PLIC

 |
 +---- Context0
 |
 +---- Context1
 |
 +---- Context2

最后就是中断完成,completion

Zephyr中的PLIC驱动

Zephyr通过Interrupt Controller Driver实现PLIC支持。

驱动文件:

复制代码
drivers/interrupt_controller/intc_plic.c

首先定义DeviceTree匹配:

表示:

DeviceTree中的:

复制代码
compatible = "sifive,plic-1.0.0";

会匹配该驱动,比如下面的cpu处情况,这里的 cpu-intc 并不是 PLIC,而是 CPU 内部的中断入口(Hart Local Interrupt Controller,很多资料也简称 HLIC):

它负责接收 CPU 本地能够处理的所有中断,例如:

  • Machine Software Interrupt(MSI)
  • Machine Timer Interrupt(MTI)
  • Machine External Interrupt(MEI)

也就是说,CPU-INTC 是 CPU 与外部中断控制器之间的连接点

中断控制器处:

PLIC 最多支持 1024 个 Interrupt Source

&hlic0 0x0b 表示:PLIC 可以向 CPU0 的 Local Interrupt Controller 发送 Interrupt ID = 11

11在 RISC-V Privileged Spec 中就是:Machine External Interrupt (MEI)

0x09 表示:Supervisor External Interrupt (SEI)

CLINT 与 PLIC 最大区别是:

  • PLIC 管理 External Interrupt
  • CLINT 管理 Software InterruptTimer Interrupt

它们都通过 interrupts-extended 连接到 CPU Local Interrupt Controller,但负责的中断类型完全不同。

PLIC寄存器模型与Zephyr映射

PLIC使用Memory-Mapped Register访问。

Zephyr根据PLIC Spec定义寄存器偏移:

Zephyr如何创建PLIC设备

Zephyr Device Model通过DeviceTree自动生成设备。

  • plic_config
  • plic_data
  • device对象

PLIC初始化流程

入口:

复制代码
static int plic_init(const struct device *dev)

初始化主要完成三件事:

关闭所有中断,避免系统启动过程中产生未知中断。清除Priority。设置Threshold。

初始化完成后:

复制代码
所有IRQ disabled

Priority = 0

Threshold = 0

PLIC中断使能流程

上文最后也有调用 config->irq_config_func()

应用调用:

PLIC中断处理流程

这是PLIC最核心的部分。

硬件流程:

复制代码
Peripheral -> PLIC Pending -> Priority Arbitration -> Hart External Interrupt -> CPU Trap

Zephyr流程:

复制代码
plic_irq_handler() -> claim register read -> get IRQ number -> _sw_isr_table -> ISR callback -> complete interrupt

总结:从Spec到Zephyr源码

PLIC硬件概念和Zephyr实现对应关系:

|-------------------|-----------------------------|
| PLIC Spec | Zephyr |
| Interrupt Source | local_irq |
| Priority Register | config->prio |
| Enable Register | config->irq_en |
| Hart Context | hart_context |
| Threshold | get_threshold_priority_addr |
| Claim/Complete | claim_complete_addr |
| Interrupt Handler | plic_irq_handler |

相关推荐
恒锐丰-罗生16 分钟前
宽压大电流同步降压优选|CN3906 DC-DC 电源芯片,车载 / 工控 / IoT 全能供电方案
嵌入式硬件·硬件工程
happygrilclh3 小时前
STM32,串口单字节中断接受,每次上电后,会收到一个0x00的解决办法。
单片机·嵌入式硬件
智闲电子设计4 小时前
STM32 独立看门狗 IWDG 实战:系统跑飞,它来兜底复位
stm32·单片机·嵌入式硬件
zcmodeltech6 小时前
智能制造教学实训沙盘模型多系统协同控制系统设计:基于STM32与Modbus RTU的工业机器人-智慧工厂-数字孪生全场景联动方案
数据库·stm32·嵌入式硬件·机器人·制造·多分类
程序员与背包客_CoderZ6 小时前
Linux D-Bus通信协议详解:从入门到C/C++编码实战
linux·服务器·c语言·c++·嵌入式硬件·嵌入式软件·dbus
嵌入式阿蔡7 小时前
HAL库 vs LL库 vs 寄存器:到底用哪个?
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
天空'之城8 小时前
单片机基础核心知识点汇总(三)
单片机·嵌入式硬件
嵌入式阿蔡9 小时前
CAN总线入门:从协议帧到STM32实战
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
恒锐丰科技韩生9 小时前
率能 SS8847E|2.7~15V 双通道 H 桥电机驱动 ETSSOP16 散热封装 家电 / 打印 / 舞台灯光专用
嵌入式硬件·硬件工程
离凌寒10 小时前
一、对stm32mp157配置freertos后,任务挂掉无法启动问题总结
stm32·单片机·嵌入式硬件