Linux驱动之异常处理体系结构简析

发布者:beta13最新更新时间:2024-08-20 来源: cnblogs关键字:Linux驱动  异常处理  体系结构 手机看文章 扫描二维码
随时随地手机看文章

异常的概念在单片机中也接触过,它的意思是让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 PC) and spsr_

    @ (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


关键字:Linux驱动  异常处理  体系结构 引用地址:Linux驱动之异常处理体系结构简析

上一篇:Linux驱动之中断处理体系结构简析
下一篇:Linux驱动之按键驱动编写(查询方式)

推荐阅读最新更新时间:2026-03-25 10:50

ARM体系结构--第九章--异常中断处理
注:本文资料全部来源于网络或书籍,同时加上个人理解。若有侵权,告知即删。若有错误,留言商讨。 1、中断向量表 中断向量表中指定了异常中断及其处理程序的对应关系,通常存储在存储地址的低端。ARM异常中断向量表的大小为32个字节,每个异常占用4个字节的空间。通常在这个4个字节的地址空间存放一个跳转指令,跳转到相应的异常服务程序。 2、ARM体系的异常中断 异常中断的响应过程: 保存当前处理器状态、即将cpsr保存到相应的异常模式下spsr_xxx中 设置当前cpsr的相应位,包括:mode修改、T、禁止IRQ中断(I)、FQR模式下,禁止FIQ(F位) 将寄存器r14_xxx设置为返回地址,保存pc的值 将PC设置为
[单片机]
ARM<font color='red'>体系结构</font>--第九章--<font color='red'>异常</font>中断<font color='red'>处理</font>
arm 硬件和软件对异常处理
对IA32(X86)而言,当发现异常时,CPU硬件做了很多事情,比如切换 SP,CR3,CS等等(读取TSS),而对于ARM来说,处理的流程如下 CPU 硬件: 1 : 将发生异常的下一条指令保存至 LR_xxx 2 : 备份当前 CPSR 到该模式的 SPSR_xxx 3 : 重置修改 CPSR,强制进入 相应的模式,强制进入ARM模式,关闭 FIQ/IRQ 响应 4 : 修改PC = (reset = 0/0xFFFF0000,undef = 4/0xFFFF0004...... ) OS(软件) 1 : 切换 sp 2 : 保存上下文 {r0-r12,sp} 3 : 执行处理函数 4 : 执行函数返回
[单片机]
ARM异常---一个Uart中断的触发处理过程
首先给出一些定义: //2440addr.inc INTOFFSET EQU 0x4a000014 ;Interruot request source offset //option.inc _ISR_STARTADDRESS EQU 0x33ffff00 //2440init.s MACRO $HandlerLabel HANDLER $HandleLabel $HandlerLabel sub sp,sp,#4 ;decrement sp(to store jump address) stmfd sp!,{r0} ;PUSH the work regi
[单片机]
ARM寄存器分析以及异常处理方法
ARM 有7个基本工作模式 User : 非特权模式,大部分任务执行在这种模式 FIQ : 当一个高优先级(fast) 中断产生时将会进入这种模式 IRQ : 当一个低优先级(normal) 中断产生时将会进入这种模式 Supervisor :当复位或软中断指令执行时将会进入这种模式 Abort : 当存取异常时将会进入这种模式 Undef : 当执行未定义指令时会进入这种模式 System : 使用和User模式相同寄存器集的特权模式 注意:除User(用户模式)是Normal(普通模式)外,其他6种都是Privilege(特权模式)。 Privilege中除Sys模式外,其余5种为异常模式。 各种模式的切换,可以是程序员通过代
[单片机]
ARM寄存器分析以及<font color='red'>异常</font><font color='red'>处理</font>方法
嵌入式ARM系统异常和中断处理知识总结
关于异常处理,分为三部分: 1. ARM异常和模式:core处理异常时的操作,几种模式介绍。 2. Vector table: 3. 异常优先级 4. lr偏移:几种异常如何返回 异常和中断处理简介 在嵌入式系统中异常处理是核心之一。高效的处理能够极大的提升系统的性能。 ARM处理器一共有7种可以暂停指令的执行序列的异常。 主要分为三个部分: 点击这里 1小时彻底掌握中断 创客学院带你搞定异常和中断处理 1. Exception handling 2. Interrupts 3. Interrupt handling schemes 今天我们主要介绍第一部分 Exception Handling 1.ARM Pro
[单片机]
继电保护测试仪器的异常现象及处理
1.电流某相插孔间报警灯亮,并有报警声:此相电流开路或负载超过实际输出范围,检查接线及负荷后再试。 2.功放一投或一输出电压立即跳开功放,电源指示灯闪烁红光并有报警声:弹开功放按钮,检查电压回路有否短路或严重过载。 3.测试过程中,跳开功放电源:首先软件停止操作输出,然后弹起功放按钮,自保护信号应复归,电源指示灯发 绿光并停止报警声。再按下功放按钮,再继续试验。若弹起面板功放按钮后,不能复归自保护信号,或再次按下按钮后,自保护再次动作,应考虑是否大电流长时间输出。
[测试测量]
ARM的37个寄存器和异常处理机制详解
1.ARM的37个寄存器 ARM的37个寄存器中,30个寄存器是“通用”,1个固定用作PC(程序控制寄存器),一个固定用作CPSR(程序状态寄存器),5个固定用作5种异常模式下的SPSR(程序状态保存寄存器),特别注意user模式和sys模式共用寄存器集。上面的37个寄存器不是同时可见的,只有在特定模式下才能访问某些寄存器。例如sp和lr寄存器各有6个,但是只有在相应模式下才能访问相应的寄存器,在user模式下访问的是user的sp和lr,FIQ模式下访问的是FIQ的sp和lr,这叫做影子寄存器。模式切换时寄存器会自动切换,其中用r13作sp,用r14作lr并不是一定的,用其他的寄存器作sp和lr也是可以的,只是大家约定俗成的
[单片机]
ARM的37个寄存器和<font color='red'>异常</font><font color='red'>处理</font>机制详解
ARM基础学习-异常中断处理
中断类型 当异常中断发生的时候,系统执行完当前指令后,将跳转到相应的异常中断处理程序,当处理程序执行完毕后,程序返回到发生中断的指令的下一条指令处执行;在进入异常中断处理程序时,要保存被中断的执行现场,在异常中断处理程序退出时,要恢复被中断的程序的执行现场; 异常中断类型: 1.复位异常发生后,进入到管理模式(svc) 下。 2.软中断发生后, 进入到 管理模式(svc) 下。 3.未定义指令异常发生后, 进入到 未定义指令中止模式(und)下。 4.指令预取中止异常发生后, 进入到 数据访问中止模式(abt)下; 5.数据访问中止异常发生后, 进入到 数据访问中止模式(abt) 下: 6.外部中断发生后, 进入到 外部中
[单片机]
ARM基础学习-<font color='red'>异常</font>中断<font color='red'>处理</font>
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved