linux系统下驱动中,中断异常的处理过程,与裸机开发中断处理过程非常类似。通过简单的回顾裸机开发中断处理部分,来参考学习linux系统下中断处理流程。

一、ARM裸机开发中断处理过程

以S3C2440的裸机开发启动文件中,有关irq中断部分代码为例进行说明:

.extern     main
.text
.global _start
_start:
b Reset
HandleUndef:
b HandleUndef
HandleSWI:
b HandleSWI
HandlePrefetchAbort:
b HandlePrefetchAbort
HandleDataAbort:
b HandleDataAbort
HandleNotUsed:
b HandleNotUsed
b HandleIRQ
HandleFIQ:
b HandleFIQ Reset:
ldr sp, = @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 msr cpsr_c, #0xd2 @ 进入中断模式
ldr sp, = @ 设置中断模式栈指针 msr cpsr_c, #0xdf @ 进入系统模式
ldr sp, = @ 设置系统模式栈指针 bl init_led @ 初始化LED的GPIO管脚
bl init_irq @ 调用中断初始化函数,在init.c中
msr cpsr_c, #0x5f @ 设置I-bit=,开IRQ中断 ldr lr, =halt_loop @ 设置返回地址
ldr pc, =main @ 调用main函数
halt_loop:
b halt_loop HandleIRQ:
sub lr, lr, # @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp,初始值是上面设置的3072
ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址
ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

当irq中断发生时,一些列的处理流程如下:

1、硬件自动令PC置为irq的中断向量,从而执行跳转指令“b HandleIRQ”。

其实,之前还伴随着保存中断断点地址到lr(还要换算);CPSR的值到SPSR;将CPSR切换到异常模式。

2、保存中断现场

sub lr, lr, #4                  @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器

3、执行中断服务程序

ldr lr, =int_return             @ 设置调用ISR即EINT_Handle函数后的返回地址
ldr pc, =EINT_Handle @ 调用中断服务函数,在interrupt.c中

4、从中断异常工作模式返回

int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr

二、linux系统中断处理流程

具体的代码细节没有分析,主要是为了理清中断处理的整体脉络。

1、ARM异常向量表

arch/arm/kernel/entry-armv.S

    .globl    __vectors_start
__vectors_start:
swi SYS_ERROR0 /* 复位时,执行这条指令 */
b vector_und + stubs_offset /* 未定义异常 */
ldr pc, .LCvswi + stubs_offset /* swi异常 */
b vector_pabt + stubs_offset /* 指令预取异常 */
b vector_dabt + stubs_offset /* 数据访问终止 */
b vector_addrexcptn + stubs_offset /* 没有用 */
b vector_irq + stubs_offset /* irq异常 */
b vector_fiq + stubs_offset /* fiq异常 */ .globl __vectors_end
__vectors_end:

异常向量表,无非还是一些跳转指令。当发生irq中断,执行指令“b vector_irq + stubs_offset”,也就是跳转到vector_irq代码段继续执行。

在linux内核初始化阶段,start_kernel函数(init/main.c)会调用trap_init、init_IRQ两个函数来初始化异常向量相关处理函数。简要说明就是,将异常向量表拷贝到地址0xffff0000处(ARM体系协处理器寄存器c1能设置异常向量的基地址为0xffff0000),再把异常向量表中异常处理的进一步函数代码段拷贝到0xffff0200位置(vector_und、vector_irq等)。

2、异常处理进一步函数----vector_irq

arch/arm/kernel/entry-armv.S

     .globl    __stubs_start
__stubs_start:
vector_stub irq, IRQ_MODE,
.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

从第4行到第19行,记录了(代码链接阶段填入的地址数据)在各个模式下遇到irq中断时,发生异常的处理分支。比如第4行__irq_usr表示用户模式下发生irq中断时,由__irq_usr对应的代码段来处理这种情况。

vector_stub是一个宏,将宏展开内容如下:

vector_irq:
sub lr, lr, #
stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr
str lr, [sp, #] @ save spsr mrs r0, cpsr
eor r0, r0, #(IRQ_MODE ^ SVC_MODE)
msr spsr_cxsf, r0 and lr, lr, #0x0f
mov r0, sp
ldr lr, [pc, lr, lsl #]
movs pc, lr @ branch to handler in SVC mode
.endm

这个宏的目的就是,根据进入irq中断前处理器所处的模式,将紧接着其下边的16个地址池中对应位置的处理向量,取出来赋给PC,完成进一步跳转。这里我们选择让程序跳转到__irq_usr代码段继续执行。

3、异常处理进一步函数----__irq_usr

arch/arm/kernel/entry-armv.S

__irq_usr:
usr_entry @将usr模式下的寄存器、中断返回地址保存到堆栈中 get_thread_info tsk @获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk等于r9 irq_handler @中断处理 mov why, #0
b ret_to_user @中断处理完成,返回中断产生的位置

4、irq_handler

irq_handler是一个宏,将其内容展开如下:

arch/arm/kernel/entry-armv.S

    .macro    irq_handler
get_irqnr_preamble r5, lr
: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
adrne lr, 1b
bne asm_do_IRQ
.endm

由此可见,进入asm_do_IRQ函数开始具体的中断处理。需要指出的是,asm_do_IRQ是中断的C语言总入口函数。asm_do_IRQ函数原型为:

asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

在汇编处理阶段,会为asm_do_IRQ传入两个参数irq(中断号)和regs,中断号对应着发生了什么样的中断事件,于是可以采取什么样的中断服务程序进行处理。

5、get_irqnr_and_base

include/asm-arm/arch-s3c2410/entry-macro.s

    .macro    get_irqnr_and_base, irqnr, irqstat, base, tmp

        mov    \base, #S3C24XX_VA_IRQ

        @@ try the interrupt offset register, since it is there

        ldr    \irqstat, [ \base, #INTPND ]
teq \irqstat, #
beq 1002f
ldr \irqnr, [ \base, #INTOFFSET ]
mov \tmp, #
tst \irqstat, \tmp, lsl \irqnr
bne 1001f @@ the number specified is not a valid irq, so try
@@ and work it out for ourselves mov \irqnr, # @@ start here @@ work out which irq (if any) we got movs \tmp, \irqstat, lsl#
addeq \irqnr, \irqnr, #
moveq \irqstat, \irqstat, lsr#
tst \irqstat, #0xff
addeq \irqnr, \irqnr, #
moveq \irqstat, \irqstat, lsr#
tst \irqstat, #0xf
addeq \irqnr, \irqnr, #
moveq \irqstat, \irqstat, lsr#
tst \irqstat, #0x3
addeq \irqnr, \irqnr, #
moveq \irqstat, \irqstat, lsr#
tst \irqstat, #0x1
addeq \irqnr, \irqnr, # @@ we have the value
:
adds \irqnr, \irqnr, #IRQ_EINT0 @加上中断号的基准数值,得到最终的中断号
:
@@ exit here, Z flag unset if IRQ .endm

linux系统中断号判断过程,是与硬件平台相关的。例如S3C2410的中断号判断过程,是根据INTOFFSET来判断的。但是,需要注意的是,中断号的具体值是有平台相关的代码决定的,和硬件中断挂起寄存器中的中断号是不等的。

#define S3C2410_CPUIRQ_OFFSET     ()
#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET) /* main cpu interrupts */
#define IRQ_EINT0 S3C2410_IRQ() /* */
#define IRQ_EINT1 S3C2410_IRQ() /* 17 */
#define IRQ_EINT2 S3C2410_IRQ() /* 18 */
#define IRQ_EINT3 S3C2410_IRQ() /* 19 */
...............

参考资料:linux-2.6.26内核中ARM中断实现详解(转)

linux驱动之中断处理过程汇编部分的更多相关文章

  1. linux驱动之中断处理过程C程序部分

    当发生中断之后,linux系统在汇编阶段经过一系列跳转,最终跳转到asm_do_IRQ()函数,开始C程序阶段的处理.在汇编阶段,程序已经计算出发生中断的中断号irq,这个关键参数最终传递给asm_d ...

  2. Linux驱动之中断处理体系结构简析

    S3C2440中的中断处理最终是通过IRQ实现的,在Linux驱动之异常处理体系结构简析已经介绍了IRQ异常的处理过程,最终分析到了一个C函数asm_do_IRQ,接下来继续分析asm_do_IRQ, ...

  3. Linux中断 - ARM中断处理过程

    一.前言 本文主要以ARM体系结构下的中断处理为例,讲述整个中断处理过程中的硬件行为和软件动作.具体整个处理过程分成三个步骤来描述: 1.第二章描述了中断处理的准备过程 2.第三章描述了当发生中的时候 ...

  4. linux驱动系列之arm汇编

    在arm平台学习linux时,会遇到arm汇编指令,arm汇编指令与8086汇编指令很多地方都不同,在此记下来以免后面忘了,同时在学习了汇编指令之后分析一些汇编指令编写的代码. 一.相对跳转指令b.b ...

  5. Linux内核system_call中断处理过程

    “平安的祝福 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” men ...

  6. Linux kernel的中断子系统之(六):ARM中断处理过程

    返回目录:<ARM-Linux中断系统>. 总结:二中断处理经过两种模式:IRQ模式和SVC模式,这两种模式都有自己的stack,同时涉及到异常向量表中的中断向量. 三ARM处理器在感知到 ...

  7. 《Linux内核分析》第五周:分析system_call中断处理过程

    实验 分析system_call中断处理过程 使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shiyanlou.com/xref/l ...

  8. Linux内核分析-分析system_call中断处理过程

    姓名:江军 ID:fuchen1994 分析system_call中断处理过程 使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shi ...

  9. Linux驱动实践:中断处理函数如何【发送信号】给应用层?

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

随机推荐

  1. ThreadPoolExecutor 线程池的源码解析

    1.背景介绍 上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newSchedul ...

  2. leetcode-217存在重复元素

    leetcode-217存在重复元素 题意 给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: ...

  3. Java:JavaBean和BeanUtils

    本文内容: 什么是JavaBean JavaBean的使用 BeanUitls 利用DBUtils从数据库中自动加载数据到javabean对象中 首发日期:2018-07-21 什么是JavaBean ...

  4. return ||和return && 区别

    return a && b 如果a是true的话,返回b,否则返回a return a || b 如果a是true的话,返回a,否则返回b

  5. SQL Server -- 回忆笔记(一):初见数据库

    SQL Server知识点回忆篇(一):初见数据库 1.  主键 primary key    唯一标识, 不会重复的值才会用来当做主键使用. 表可以没有主键,但建议每张表都有主键. 2.  数据冗余 ...

  6. Django之--网页展示Hello World!

    上一篇:Django的安装启动完毕后,本文来试下hello world的效果~ 好吧,又开始了喜闻乐见的Hello World环节,本文使用Linux环境演示(Windows太麻烦). [root@p ...

  7. AspNet MVC中使用Hangfire执行定时任务

    Hangfire在Aspnet中执行定时任务: 第一步: NuGet中加入Hangfire包 第二步: 添加Owin的自启动 第三步.Hangfire的后台控制仪表盘默认情况下只能本地访问,外网访问需 ...

  8. c/c++赋值函数(重载=号运算符)

    c/c++赋值函数(重载=号运算符) 首先c++里的各种运算符都是用函数实现的,比如=,就等号函数. 所以当用=给一个对象赋值的时候,实际调用的是=号所对应的=号函数. 分析下面的代码 #includ ...

  9. 用好lua+unity,让性能飞起来——关于《Unity项目常见Lua解决方案性能比较》的一些补充

    <Unity项目常见Lua解决方案性能比较>,这篇文章对比了现在主流几个lua+unity的方案 http://blog.uwa4d.com/archives/lua_perf.html ...

  10. Windows7安装Bitvise开启ssh服务

    Windows7安装Bitvise开启ssh服务 by:铁乐猫 在Liunx和windows10上配置SSH服务是一件很容易的事,毕竟系统己经自带了ssh的服务功能. 不过在windows7上可不容易 ...