Linux驱动之异常处理体系结构简析
异常的概念在单片机中也接触过,它的意思是让CPU可以暂停当前的事情,跳到异常处理程序去执行。以前写单片机裸机程序属于前后台程序,前台指的就是mian函数里的while(1)大循环,后台指的就是产生异常后的处理程序。ARM9有以下几种异常模式:

ARM架构的异常向量的地址可以是0x00000000,也可以是0xffff0000,Linux使用地址0xffff0000。在初始化时先将中断向量表放到0xffff0000处,在init/main.c的start_kernel函数里的trap_init();函数中处理具体代码为:
void __init early_trap_init(void)
{
...
...
/*将中断向量表的拷贝到vectors处*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);//vectors=CONFIG_VECTORS_BASE=0xffff0000在配置内核时生成
//位于include\linux\Autoconf.h中
/*将中断向量表的跳转地址的处理代码拷贝到vectors+0x200处*/
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
...
...
}
下面将以IRQ异常处理为例子描述完整的异常处理流程
1、IRQ异常处理过程,这个异常的产生通常是可以由硬件配置的,S3C2440的中断结构最终都会反应在IRQ异常上
继续看到异常向量表,我们以产生IRQ异常为例:它位于arch\arm\kernel\entry-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, //调用vector_stub宏定义了vector_irq变量,IRQ异常跳转到这里开始执行。 .long __irq_usr @ (USR_26 / USR_32)
.long __irq_invalid @ (FIQ_26 / FIQ_32)
.long __irq_invalid @ (IRQ_26 / IRQ_32)
.long __irq_svc @ (SVC_26 / SVC_32)
.long __irq_invalid @
.long __irq_invalid @
.long __irq_invalid @
.long __irq_invalid @
.long __irq_invalid @
.long __irq_invalid @
.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
sub lr, lr, //lr = lr-4
.endif @
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr//保存r0与lr寄存器到IRQ模式的堆栈
mrs lr, spsr //将spsr赋给lr
str lr, [sp, #] @ 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 #] //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
: 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
Linux驱动之异常处理体系结构简析的更多相关文章
- Linux驱动之中断处理体系结构简析
S3C2440中的中断处理最终是通过IRQ实现的,在Linux驱动之异常处理体系结构简析已经介绍了IRQ异常的处理过程,最终分析到了一个C函数asm_do_IRQ,接下来继续分析asm_do_IRQ, ...
- Linux驱动之输入子系统简析
输入子系统由驱动层.输入子系统核心.事件处理层三部分组成.一个输入事件,如鼠标移动.键盘按下等通过Driver->Inputcore->Event handler->userspac ...
- Linux 目录结构学习与简析 Part2
linux目录结构学习与简析 by:授客 QQ:1033553122 ---------------接Part 1-------------- #1.查看CPU信息 #cat /proc/cpuinf ...
- Linux网络性能优化方法简析
Linux网络性能优化方法简析 2010-12-20 10:56 赵军 IBMDW 字号:T | T 性能问题永远是永恒的主题之一,而Linux在网络性能方面的优势则显而易见,这篇文章是对于Linux ...
- Linux 目录结构学习与简析 Part1
linux目录结构学习与简析 by:授客 QQ:1033553122 说明: / linux系统目录树的起点 =============== /bin User Bi ...
- Linux内核poll/select机制简析
0 I/O多路复用机制 I/O多路复用 (I/O multiplexing),提供了同时监测若干个文件描述符是否可以执行IO操作的能力. select/poll/epoll 函数都提供了这样的机制,能 ...
- Linux Hugetlbfs内核源码简析-----(二)Hugetlbfs挂载
本文只讨论执行"mount none /mnt/huge -t hugetlbfs"命令后,mount系统调用的执行过程(基于Linux-3.4.51),不涉及进程相关的细节. m ...
- Linux之用户和用户组简析
学习网址:http://c.biancheng.net/linux_tutorial/60/
- Linux驱动之触摸屏程序编写
本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 ...
随机推荐
- 解决ansible上传速度慢的问题
问题: 假如有A.B.C.D....等机器,机器A为Ansible服务器,机器B.C.D...等为Ansible管理的节点服务器,A机器与其他机器都不在同一个网络,也就是A机器必须添加VPN之后才能与 ...
- opencv简介
Open Source Computer Vision Library.OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而 ...
- 【转载】robocopy的用法
经常进行文件管理操作的朋友们,不满意于Windows系统内置的复制功能,因为它太龟速了.于是大家就使用FastCopy.TeraCopy之类的软件来加速复制,但是你是否知道Windows 7已经内置快 ...
- [UE4]Throbber,横向动态图标
一.Throbber跟Circular Throbber一样,都是用来提示玩家后台有数据正在加载中. 二.Throbber是横向显示动态图标.其他方面跟Circular Throbber一样.Circ ...
- firefox修改语言
下面咱们就可以开始更改设置来让咱们安装好的语言成为默认的语言. 首先在空窗口里输入以下地址:about:config,进入设置页面. 2 请大家定位到general.useragent.locale这 ...
- rabbitmq (一)用法
首先,主机一是window系统,虚拟机二 ubuntu, ubuntu部署了rabbitmq服务端.默认监听5672端口. 由于rabbitmq内部有严格的权限系统,使用之前必须配置好权限. 默认网页 ...
- 一个简单的通讯服务框架(大家发表意见一起研究)JAVA版本
最近研究下java语言,根据一般使用的情况,写了个连接通讯服务的框架: 框架结构 C-Manager-S; 把所有通讯内容抽取成三个方法接口:GetData,SetData,带返还的Get; 所有数据 ...
- httpput
String doHttpPut(String rpmName, String cookie) throws UnsupportedEncodingException, IOException, Cl ...
- virtual 函数只有在用指针或引用的方式访问,才会导致多态。
只有用指针和引用,才会动态绑定.才会在运行时候从虚表中找对应的成员函数. 如果只是用.访问成员函数,是静态绑定,在编译时刻就固定好的. 另外,父类的虚函数,子类不管加不加virtual关键字,都是虚函 ...
- 生活实遇记-Kindle好久没用,屏幕一直处于电池状态,怎么解决?
2018-01-02 实遇记-Kindle好久没用,屏幕一直处于电池状态,怎么解决? 今天我翻腾出自己的kindle,好久没用了,屏幕一直是一个电池状态,充电头+线充了2个钟头,按电源键木有反应,也是 ...