基于linux-3.3内核的ARM异常处理之概述

ARM处理器有7种工作模式 :

USR 模式
    正常用户模式,程序正常执行模式

FIQ 模式(Fast Interrupt Request)
处理快速中断,支持高速数据传送或通道处理

IRQ 模式
    处理普通中断
    
SVC 模式(Supervisor)
    操作系统保护模式,处理软件中断swi  reset

ABT 中止(Abort mode){数据、指令}
    处理存储器故障、实现虚拟存储器和存储器保护

UND 未定义(Undefined)
   处理未定义的指令陷阱,支持硬件协处理器的软件仿真

SYS 系统模式(基本上=USR)(System)
   运行特权操作系统任务 

这7种模式,除了用户模式之外的其他6种处理器模式称为特权模式

特权模式下,程序可以访问所有的系统资源,也可以任意地进行处理器模式的切换。

特权模式中,除系统模式外,其他5种模式又称为异常模式。

下面就来讨论一下发生异常时,linux的处理过程

首先引入中断异常向量表。
中断异常向量表就是一张函数表格,里面放置了一组函数,存放在一个固定位置,当发生异常时,处理器被强制从这个位置取出
函数执行。

中断异常向量表在启动之前存在于地址0x00000000,这是uboot的中断异常向量表,
u-boot\arch\arm\cpu\arm920t\start.S 40行
.globl _start
_start: b start_code                      // 0x00
ldr pc, _undefined_instruction          // 0x04     未定义指令异常
ldr pc, _software_interrupt             // 0x08     软件中断异常
ldr pc, _prefetch_abort                 // 0x0c     指令预取中止异常
ldr pc, _data_abort                     // 0x10     数据访问中止异常
ldr pc, _not_used                       // 0x14     保留
ldr pc, _irq                            // 0x18     外部中断请求异常
ldr pc, _fiq                            // 0x1c     快速中断请求异常
所以刚开始中断向量表的地址是0x00~0x1c

0x00地址放的跳转指令就是跳转到执行uboot的引导启动代码

在引导了kernel后,中断异常向量表会存在于地址0xffff0000,追踪代码如下:
start_kernel
    setup_arch(&command_line);
        early_trap_init(); 
            #if defined(CONFIG_CPU_USE_DOMAINS)
                unsigned long vectors = CONFIG_VECTORS_BASE;
            #else
                unsigned long vectors = (unsigned long)vectors_page;
            #endif
            ...
            memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);  //这三条指令就是搬移中断异常向量表指令
            memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
            memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

为什么会被拷到0xffff0000?
从上面的代码看CONFIG_CPU_USE_DOMAINS有没有被设置,我们去内核目录的.config文件查看,它被设置了,所以
vectors = CONFIG_VECTORS_BASE,而在.config文件中CONFIG_VECTORS_BASE=0xffff0000

中断异常向量表被拷贝到0xffff0000地址,中断异常处理函数也拷贝到0xffff0000 + 0x200的地址上去

考察汇编的时候到了,被虐的体无完肤啊,建议看之前恶补一下

在哪里拷贝呢?
从上面的代码看出,异常向量表从__vectors_start拷贝,中断异常处理函数从__stubs_start拷贝,这段代代码在
linux-3.3\arch\arm\kernel\entry-armv.S 1132行
__vectors_start:
  ARM( swi SYS_ERROR0 )
  THUMB( svc #0 )                          // 0x00
  THUMB( nop )                            // 0x02 
    W(b) vector_und + stubs_offset            // 0x04
    W(ldr) pc, .LCvswi + stubs_offset         // 0x08
    W(b) vector_pabt + stubs_offset           // 0x0c 
    W(b) vector_dabt + stubs_offset           // 0x10 
    W(b) vector_addrexcptn + stubs_offset     // 0x14
    W(b) vector_irq + stubs_offset            // 0x18 
    W(b) vector_fiq + stubs_offset            // 0x1c

.globl __vectors_end
__vectors_end:

以上是介绍了异常向量表,当发生异常的时候,处理器会跳转到到这些地方来执行,不同的异常对应不同的入口地址。发生具体的异常会怎么处理,请见下面的博文

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。