异常处理

来源:互联网 发布:matlab2016b是什么软件 编辑:程序博客网 时间:2024/05/22 16:53

参考链接:http://blog.csdn.net/mcgrady_tracy/article/details/7820311

http://blog.csdn.net/feixiaku/article/details/8363850

ARM支持7种类型的异常,它们是:

复位异常

未定义指令异常

软中断指令异常

预取指令异常

数据中止访问异常

中断异常

快速中断异常

 

ARM异常中断种类及优先级:
            优先级                 异常中断名称
                高                   复位(reset)
                ||                    数据访问中止(data abort)
                ||                    快速中断请求(FIQ)
                ||                    外部中断请求(IRQ)                    
               /||/                  指令预取中止(prefetch abort)
                //                    软中断(SWI)
                低                   未定义指令(undefined instruction)

ARM异常向量表


当异常发生时,ARM将做如下事情

(1)将异常发生处下条指令地址保存到相应工作模式下LR寄存器中

(2)CPSR寄存器值复制到相应异常模式下的SPSR寄存器中

(3)切换ARM工作模式

(4)如果异常模式是复位模式或者是快速中断模式,禁止所有快速中断(CPSR[6]=1)

(5)禁止中断CPSR[7]= 1

(6)设置PC寄存器值为相应异常向量地址

我们看ARM异常向量表中,异常向量地址空间大小为4个字节,也就是说这段空间刚好能存放一条ARM指令,所以我们可以在异常这段地址空间中存放一条跳转指令,跳转到我们的异常处理程序中,u-boot中启动代码就是这样做的:

_start: b       start_code

复位异常时,跳转到start_code标号处。


异常处理代码:
.globl _start
_start:

 /* 0 地址 */
 b reset                 /* 复位时,cpu跳到0地址 */
 ldr pc, =undefined_instruction  /* cpu遇到不能识别的指令时 */
 ldr pc, _vector_swi             /* 当执行swi指令时, 进入swi模 式 */
 b halt     @ldr pc, _prefetch_abort /* 预取中止异常 */
 b halt     @ldr pc, _data_abort     /* 数据访问异常 */
 b halt     @ldr pc, _not_used       /* 没用到 */
 ldr pc, _irq            /* 0x18 中断异常 */
 b halt     @ldr pc, _fiq            /* 快中断异常 */

_irq :
 .word vector_irq

_vector_swi:
 .word vector_swi
  
vector_swi:
 /* 1. 保存现场 */
 ldr sp, =0x56000000
 stmdb sp!, {r0-r12, lr}  /* lr就是swi的下一条指令地址 */

 /* 2. 处理异常 */
 mrs r0, cpsr
 ldr r1, =swi_str
 bl print_cpsr

 /* 3. 恢复现场 */
 ldmia sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */
 
swi_str:
 .word 0x00697773  /* swi */
 
undefined_instruction:
 /* 1. 保存现场 */
 ldr sp, =0x55000000
 stmdb sp!, {r0-r12, lr}

 /* 2. 处理异常 */
 mrs r0, cpsr
 ldr r1, =und_str
 bl print_cpsr

 /* 3. 恢复现场 */
 ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */

und_str:
 .word 0x00646e75  /* und */

usr_str:
 .word 0x00727375  /* usr */
vector_irq:
 /* 1. 保存现场 */
 ldr sp, =0x54000000
 sub lr, lr, #4
 stmdb sp!, {r0-r12, lr}  /* lr就是swi的下一条指令地址 */

 /* 2. 处理异常 */
 /* 2.1 分辨是哪个中断 */
 /* 2.2 调用它的处理函数 */
 
 /* 3. 恢复现场 */
 ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */

reset:
/* 硬件相关的设置 */
    /* Peri port setup */
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)   
/* 关看门狗 */
/* 往WTCON(0x7E004000)写0 */
 ldr r0, =0x7E004000
 mov r1, #0
 str r1, [r0]
 /* 设置栈 */
 ldr sp, =8*1024

 /* 设置时钟 */
 bl clock_init
 bl ddr_init
 bl init_uart

/* 把程序的代码段、数据段复制到它的链接地址去 */ 
 adr r0, _start   /* 获得_start指令当前所在的地址 : 0*/
 ldr r1, =_start  /* _start的链接地址 0x51000000 */
 ldr r2, =bss_start      /* bss段的起始链接地址 */
 sub r2, r2, r1
 cmp r0,r1
 beq clean_bss
 bl copy2ddr
 cmp r0, #0
 bne halt
 /* 清BSS */
/* 把BSS段对应的内存清零 */
clean_bss:
 ldr r0, =bss_start
 ldr r1, =bss_end
 mov r3, #0
 cmp r0, r1
 ldreq pc, =on_ddr
clean_loop:
 str r3, [r0], #4
 cmp r0, r1 
 bne clean_loop  
 ldr pc, =on_ddr

on_ddr: 

 mrs r0, cpsr
 bic r0,r0,#0x1f
 orr r0,r0,#0x10
 msr cpsr,r0      /* 进入user mode */

ldr sp, =0x57000000

 ldr r1, =usr_str
 bl print_cpsr 
 swi 0    /*
           * cpu进入svc模式
           * 把之前的cpsr保存到spsr_svc
           * 切换到r13_svc, r14_svc
           * 把swi的下一条指令存到r14(lr)_svc
           * 跳到地址8
           */
 bl hello
undef:
 .word 0xff000000 /*
             * cpu进入Undefined模式
             * 把之前的cpsr保存到spsr_und
             * 切换到r13_und, r14_und
             * 把下一条指令存到r14(lr)_und
             * 跳到地址4
             */
 swi_ret:
 bl main

halt:
 b halt 


 

原创粉丝点击