Linux驱动之异常处理体系结构简析
2024-08-20 来源:cnblogs
异常的概念在单片机中也接触过,它的意思是让CPU可以暂停当前的事情,跳到异常处理程序去执行。以前写单片机裸机程序属于前后台程序,前台指的就是mian函数里的while(1)大循环,后台指的就是产生异常后的处理程序。ARM9有以下几种异常模式:
ARM架构的异常向量的地址可以是0x00000000,也可以是0xffff0000,Linux使用地址0xffff0000。在初始化时先将中断向量表放到0xffff0000处,在init/main.c的start_kernel函数里的trap_init();函数中处理具体代码为:
718 void __init early_trap_init(void)
719 {
...
...
/*将中断向量表的拷贝到vectors处*/
732 memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);//vectors=CONFIG_VECTORS_BASE=0xffff0000在配置内核时生成
//位于includelinuxAutoconf.h中
/*将中断向量表的跳转地址的处理代码拷贝到vectors+0x200处*/
733 memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
...
...
745 }
下面将以IRQ异常处理为例子描述完整的异常处理流程
1、IRQ异常处理过程,这个异常的产生通常是可以由硬件配置的,S3C2440的中断结构最终都会反应在IRQ异常上
继续看到异常向量表,我们以产生IRQ异常为例:它位于archarmkernelentry-armv.S中,可以看到它跳转到了vector_irq + stubs_offset 处
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start//计算跳转地址的偏移量
.globl __vectors_start
__vectors_start:
swi SYS_ERROR0 //复位异常处理程序
b vector_und + stubs_offset
ldr pc, .LCvswi + stubs_offset //软件中断异常处理程序
b vector_pabt + stubs_offset
b vector_dabt + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_irq + stubs_offset //跳转到IRQ的异常处理程序,b是位置无关码,其中vector_irq调用了vector_stub宏
b vector_fiq + stubs_offset
搜索vector_irq 发现没有搜到,它其实是调用vector_stub宏生成的。这个宏后面介绍,先看到vector_stub irq,它最终生成vector_irq
.globl __stubs_start //调用vector_stub宏定义的变量的开始地址
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4//调用vector_stub宏定义了vector_irq变量,IRQ异常跳转到这里开始执行。
.long __irq_usr @ 0 (USR_26 / USR_32)
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
接着介绍vector_stub的调用过程
vector_irq:
.if 4
sub lr, lr, 4//lr = lr-4
.endif
@
@ Save r0, lr_ @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr//保存r0与lr寄存器到IRQ模式的堆栈 mrs lr, spsr //将spsr赋给lr str lr, [sp, #8] @ save spsr //将lr入栈,即spsr入栈 @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr eor r0, r0, #(mode ^ SVC_MODE) msr spsr_cxsf, r0 //将r0的值赋给spsr_cxsf,此时的状态还是处于IRQ模式 @ @ the branch table must immediately follow this code @ and lr, lr, #0x0f //lr=lr&0x0f,lr起始就是spsr的值,它保存了进入IRQ模式前的CPU模式,其实是5位控制的,这里只用到4位,用来跳转到不同的处理函数 mov r0, sp //将管理模式的sp的值给r0 ldr lr, [pc, lr, lsl #2] //lr = *(pc+lr<<2)。如果在进入IRQ之前是用户模式即是从应用层进入的,那么lr = pc = __irq_usr.否则是管理模式也就是处于内核层时发生了IRQ异常 lr = pc+12=__irq_svc movs pc, lr @ branch to handler in SVC mode//将lr的值给pc,同时将spsr的值赋给cpsr,此时才是进入了管理模式 .endm 这个宏执行完成之后将进入SVC模式,然后调用__irq_usr或者__irq_svc。以__irq_usr为例继续说明异常函数调用过程 __irq_usr: usr_entry //入口的一些处理,保存寄存器到堆栈 get_thread_info tsk //得到线程信息 irq_handler //真正的异常处理 b ret_to_user //切换回异常前的状态,将堆栈的寄存器出栈 可以看到这个函数显示保存一些寄存器数据然后调用irq_handler这个真正的异常处理函数,先是判断INTPND寄存器是否有某一位被置1,如果置1,说明有中断发生,然后从INTOFFSET寄存器取得记录的中断号,经过处理后放入r0,然后irq_handler最终调用了这个C函数。最后再将寄存器恢复到异常前的状态。IRQ异常处理结束 .macro irq_handler get_irqnr_preamble r5, lr 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrne lr, 1b bne asm_do_IRQ//最终调用了asm_do_IRQ。这个是C函数 #ifdef CONFIG_SMP /* * XXX * * this macro assumes that irqstat (r6) and base (r5) are * preserved from get_irqnr_and_base above */ test_for_ipi r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_IPI #ifdef CONFIG_LOCAL_TIMERS test_for_ltirq r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_local_timer #endif #endif .endm
- 基于迅为iTOP-3568开发板的Linux驱动开发实战:menuconfig图形化配置实验
- 迅为工业RK3568 itop-3568开发板Linux驱动开发实战:RK3568内核模块符号导出详解
- STM32MP157 Linux系统移植开发篇12:Linux内核MIPI LCD驱动移植
- 迅为imx6ull开发板Linux I2C驱动实验-应用程序与I2C通信
- 迅为IMX6ULL开发板Linux驱动初探-最简单的设备驱动-helloworld
- 迅为IMX6ULL开发板-Linux MISC驱动-编写实验程序
- iMX6ULL终结者Linux WIFI驱动实验rtl8723 Wifi联网测试
- 迅为i.MX6ULL终结者Linux MISC驱动运行测试
- 迅为IMX6ULL开发板Linux RS232/485驱动实验(上)
- IMX6ULL开发板Linux_WIFI驱动实验
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 蓝牙信道探测技术原理与开发套件实践
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析




