Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
中断
th-thread 源码学习-中断系统
发布于 2025-11-07 10:55:39 浏览:102
订阅该版
[tocm] # 1 站在内核的角度看中断 代码版本为5.2.2 中断细节与硬件强相关,那么就需要统一接口,让各自的硬件实现各自的中断细节。 站在内核的角度,我们不关心整个中断控制器的细节,从整个中断架构可以视为如下 ```c /* 初始化中断控制(硬件相关) */ void rt_hw_interrupt_init(void) /* 给 中断号 绑定 中断服务函数 */ rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name) /* 屏蔽/打开 中断号 对应的的 中断源(硬件相关) */ void rt_hw_interrupt_mask (int vector) void rt_hw_interrupt_umask(int vector) /** * 屏蔽/打开 当前 cpu 的 全局中断 * 对于单核 等于 rt_hw_local_irq_enable/rt_hw_local_irq_disable * 对于多核 依赖 rt_hw_local_irq_enable/rt_hw_local_irq_disable 实现 */ void rt_hw_interrupt_enable (rt_base_t level) rt_base_t rt_hw_interrupt_disable(void) /* 中断通知, 进入中断和退出中断时触发的函数 */ rt_weak void rt_interrupt_enter(void) rt_weak void rt_interrupt_leave(void) /* 记录中断嵌套层数 */ rt_uint8_t rt_interrupt_get_nest(void) void rt_hw_local_irq_enable (rt_base_t level) /* 恢复 IRQ 和 FIQ 的状态为 level 中保存的值 */ rt_base_t rt_hw_local_irq_disable(void) /* 屏蔽 IRQ 和 FIQ, 返回屏蔽之前的 IRQ 和 FIQ 状态 */ ``` # 2 从 qemu_arm64 gicv2 的视角看中断 详细参考文档 << ARM Generic Interrupt Controller Architecture Specification >> 重点4.12和4.13章节 << Arm Architecture Reference Manual for A-profile architecture >> ## 2.1 gic 初始化 ```c /** * 设置中断向量表 * * dist寄存器配置: * 设置全局中断触发模式为低电平触发 * 设置全局中断路由到cpu0 * 设置所有中断优先级为0xa0 * 禁用所有中断 * 设置所有中断为group0 * 使能group0和group1的中断转发 * * cpu寄存器配置: * 设置cpu中断掩码为0xf0 * 设置优先级分组为只有子优先级 * 使能cpu接口到cpu的中断信号 */ void rt_hw_interrupt_init(void) { rt_hw_vector_init(); ... arm_gic_dist_init(0, gic_dist_base, gic_irq_start); arm_gic_cpu_init (0, gic_cpu_base); ... } ``` ## 2.2 中断号函数绑定 ```c /** * 给中断源安装一个中断服务函数 * isr_table是一个中断服务函数表, 索引为中断号 * * 把当前中断的目的cpu设置为当前cpu */ rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name) { ... rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); isr_table[vector].handler = handler; isr_table[vector].param = param; ... rt_hw_interrupt_set_target_cpus(vector, 1 << rt_hw_cpu_id()); /* 硬件相关 */ ... } ``` ## 2.3 中断源开关 ```c /** * dist寄存器 GICD_ICENABLERn 频闭中断源 */ void rt_hw_interrupt_mask(int vector) { arm_gic_mask(0, vector); } /** * dist寄存器 GICD_ISENABLERn 打开中断源 */ void rt_hw_interrupt_umask(int vector) { arm_gic_umask(0, vector); } ``` ## 2.4 系统全局中断开关 ```c /** * 对于多核 硬件部分的开关中断函数名为 rt_hw_local_irq_disable/rt_hw_local_irq_enable * 对于单核 硬件部分的开关中断函数名为 rt_hw_interrupt_disable/rt_hw_interrupt_enable */ #ifdef RT_USING_SMP #define rt_hw_interrupt_disable rt_hw_local_irq_disable #define rt_hw_interrupt_enable rt_hw_local_irq_enable #endif /** * void rt_hw_interrupt_enable(rt_base_t level); * 恢复 IRQ 和 FIQ 的状态为 level 中保存的值 */ .globl rt_hw_interrupt_enable rt_hw_interrupt_enable: and x0, x0, #0xc0 cmp x0, #0xc0 /* branch if one of the bits not set(zero) */ bne 1f ret 1: isb dsb nsh and x0, x0, #0xc0 mrs x1, DAIF bic x1, x1, #0xc0 orr x0, x0, x1 msr DAIF, x0 ret /** * rt_base_t rt_hw_interrupt_disable(); * 屏蔽 IRQ 和 FIQ, 返回屏蔽之前的 IRQ 和 FIQ 状态 */ .globl rt_hw_interrupt_disable rt_hw_interrupt_disable: mrs x0, DAIF and x0, x0, #0xc0 cmp x0, #0xc0 bne 1f ret 1: msr DAIFSet, #3 dsb nsh isb ret ``` # 3 从 qemu_arm64 gicv2 的视角 看中断的流程 ## 3.1 中断向量表 ```asm system_vectors: .align 11 .set VBAR, system_vectors .org VBAR ... /* Exception from CurrentEL (EL1) with SP_ELn */ .org (VBAR + 0x200 + 0) b vector_exception /* Synchronous */ .org (VBAR + 0x280 + 0) b vector_irq /* IRQ/vIRQ */ .org (VBAR + 0x300 + 0) b vector_fiq /* FIQ/vFIQ */ .org (VBAR + 0x380 + 0) b vector_serror ... ``` ```asm START_POINT(vector_irq) ... /* handline IRQ */ mov x0, EFRAMEX bl rt_hw_trap_irq ... START_POINT_END(vector_irq) ``` ## 3.2 中断处理 ```c void rt_hw_trap_irq(struct rt_hw_exp_stack *regs) { ... _rt_hw_trap_irq(&this_ctx); ... } ``` ```c static void _rt_hw_trap_irq(rt_interrupt_context_t irq_context) { ... ir = rt_hw_interrupt_get_irq(); /* 从gicv2 cpu 的 GICC_IAR 读取中断号,让中断 pending to active */ ir_self = ir & 0x3ffUL; isr_func = isr_table[ir_self].handler; param = isr_table[ir_self].param; isr_func(ir_self, param); ... rt_hw_interrupt_ack(ir); /* 1 GICD_ICPENDRn寄存器 remove pending state。 2 GICC_EOIR寄存器 remove active state*/ } ``` ### 3.2.3 中断处理流程 ``` 中断发生 ↓ CPU 跳转到 vector_irq ↓ SAVE_IRQ_CONTEXT (保存上下文) ↓ rt_interrupt_enter (中断嵌套计数++) ↓ rt_hw_trap_irq ↓ ├─ rt_hw_interrupt_get_irq() ← 读取中断号(INTACK) ├─ 查找 isr_table[irq].handler ├─ 执行中断服务函数 └─ rt_hw_interrupt_ack(ir) ← 应答中断(EOI) ↓ rt_interrupt_leave (中断嵌套计数--) ↓ rt_hw_vector_irq_sched (检查是否需要调度) ↓ RESTORE_IRQ_CONTEXT (恢复上下文) ↓ eret (返回被中断的代码) ```
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
laidene
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注TA
发私信
相关文章
1
使用CmBacktrace定位错误异常,请教分析原因
2
ARM9、raspberry-pi中断问题
3
内联函数不压栈,会因为中断导致栈内现场被破坏吗
4
rt_hw_context_switch_interrupt的逻辑
5
中断的入口程序在哪个文件里?
6
我想实现一个定时器中断,发现rt_hw_interrupt_install未定义
7
临界区和关中断,是否需要同时使用?
8
gpio 引脚一直进中断,请问怎么办呢?
9
RT-Thread那些API可以在中断程序中调用?
10
spi dma 中断接收的问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
6
五分钟玩转RT-Thread新社区
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
Bootloader
AT
Hardfault
ART-Pi
CAN总线
FinSH
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
FAL
rt-smart
RTC
cubemx
I2C_IIC
BSP
UART
WIZnet_W5500
PWM
ESP8266
ota在线升级
packages_软件包
GD32
flash
freemodbus
潘多拉开发板_Pandora
keil_MDK
编译报错
ADC
flashDB
rt_mq_消息队列_msg_queue
ulog
MicroPython
msh
socket
Debug
SFUD
中断
at_device
QEMU
本月问答贡献
出出啊
1532
个答案
346
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
822
个答案
180
次被采纳
crystal266
555
个答案
162
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
super_gith
3
篇文章
3
次点赞
wdfk_prog
2
篇文章
19
次点赞
killer22
1
篇文章
3
次点赞
LoongYang
1
篇文章
3
次点赞
waner
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部