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. 小程序实践(二):swiper组件实现轮播图效果

    swiper组件类似于Android中的ViewPager,实现类似轮播图的效果,相对于Android的Viewpager,swiper实现起来更加方便,快捷. 效果图: 首先看下swiper支持的属 ...

  2. 章节二、2-String 引用数据类型-字符串类

    一.创建String(字符串对象)的两种方式 1.String str1 = "nihao"("nihao"值存储在常量值中) 2.String str2 = ...

  3. python安装pbkdf2 遇到错误TypeError: __call__() takes exactly 2 arguments (1 given)

    python安装模块时遇到如下错误, import packaging.requirements File "/usr/lib/python2.7/site-packages/packagi ...

  4. java----java垃圾回收算法

    1.引用计数法(Reference Counting Collector) 1.1算法分析 引用计数是垃圾收集器中的早期策略.在这种方法中,堆中每个对象实例都有一个引用计数.当一个对象被创建时,且将该 ...

  5. java任意n以内连续的和等于n

    import java.util.Scanner; /** * Created by Admin on 2017/3/25. */ public class test01 { public stati ...

  6. Java入门(五):控制流程

    在Java中,使用条件语句和循环结构确定控制流程,在本文中,主要包括块作用域.条件语句.循环结构.中断循环这四部分. 一.块作用域 块,也叫复合语句,是指由一对大括号括起来的若干条Java语句.块决定 ...

  7. March 09th, 2018 Week 10th Friday

    All good things must come to an end. 好景无常. Love is when the other person's happiness is more importa ...

  8. 【C编程基础】C编译链接命令gccc

    1.gcc安装 rpm -qa|grep gcc ==>检查gcc是否安装 gcc -v ==>检查gcc版本 yum -y install gcc ==>安装gcc  2.基本语法 ...

  9. 精度 Precision

    柏拉图认为,尽管世间万物是不完美的,但存在一种永恒不变的形式,这个形式是完美的,而生命的意义就是让这个世界尽可能的接近这个完美的形式. 怎么理解这句话,和我们今天讲的精度有什么关系.我们先举一个例子, ...

  10. (转)Geoserver基础配图研究

    https://blog.csdn.net/zbcx_ZGIS/article/details/82216151 1面图层配图 1.1基本框架 这个是geoserver默认的polygon的代码,我们 ...