zoukankan      html  css  js  c++  java
  • ARM多种异常的处理

    ARM中的流水线分为:取值,译码,执行,仿存,回写这五步,SWI(软中断)和UND中断都出现在译码阶段,而其他5种中断都发生在执行阶段。SWI和UND异常两种处理方法步骤都差不多,但是如果是异常出现在执行阶段要怎么样处理呢?

    int main()
     10 { 
     11     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
     12     unsigned long source_addr=data_abort_init();
     13     //异常事件处理函数
     14     printf("swi_souce addr is %x
    ",source_addr);
     15     //将异常处理地址的值放到0x60000004
     16     memcopy(0x60000010,source_addr,0x1000);
     17     
     18     enable_mmu();
     19     //内存映射将0x00000004映射到0x6000000004    
     20     __asm__ __volatile__( 
     21         "mov r0, #1
    "
     22         "ldr r1, [r0]
    "
     23      );
     24     printf("welcome back! 
    "); 
     25 
     26 
     27 }

    如果代码中的汇编语言执行的时候将会发生DATA Abrot异常,将会到0x0000010地址区执行处理代码其中,处理执行的时候发生异常和处理译码时候的异常都大同小异。但是需要注意的是:

     1 
      2 int (*printf)(char *, ...) = 0xc3e114d8;
      3 
      4 void init_ttb(unsigned long *addr);
      5 void enable_mmu(void);
      6 unsigned long data_abort_init();
      7 void memcopy(unsigned long* dest,unsigned long* source,int len);
      8 
      9 int main()
     10 {
     11     //发生OBORT异常时会进入异常模式跳转到0000 0010地址处理异常事件  
     12     unsigned long source_addr=data_abort_init();
     13     //异常事件处理函数
     14     printf("swi_souce addr is %x
    ",source_addr);
     15     //将异常处理地址的值放到0x600000010
     16     memcopy(0x60000010,source_addr,0x1000);
     17 
     18     enable_mmu();
     19     //内存映射将0x00000004映射到0x6000000004    
     20     __asm__ __volatile__(
     21         "mov r0, #1
    "
     22         "ldr r1, [r0]
    "
     23      );
     24     printf("welcome back! 
    ");
     25 
     26 
     27 }
     28 
     29 void memcopy(unsigned long* dest,unsigned long* source,int len)
     30 {
     31     int i=0;;
     32     for(i=0;i<len;i++)
     33         dest[i]=source[i];
     34 }
     35 
     36 unsigned long  data_abort_init()
     37 {
     38     unsigned long source;
     39     __asm__ __volatile__(
     40 
     41          "ldr %0, =voliate_start
    "
     42          : "=r" (source)
     43      );
     44 
     45 
     46     return source;
     47 
     48 }
     49 
     50 __asm__(
     51 
     52 "voliate_start:
    "
     53     //跳转要分三部:
     54     //1:将PC保存到新模式下的lr中;
     55     //2:将CPSR保存在SPSR中
     56     //3:初始化SP
     57     //前两步由硬件完成,而第三部需要手动完成
     58      "sub lr, lr, #4
    "
     59      "mov sp, #0x66000000
    "//初始化SP
     60      "stmfd sp!, {r0-r12, lr}
    "//初始化sp,入栈保护寄存器 
     61     //打印一句话 
     62      "ldr r0, =data_string
    "
     63      "ldr r2, show
    "
     64      "blx r2
    "
     65     //跳回来分两部
     66     //1:将CPSR保存在SPSR中
     67     //2:将PC保存到新模式下的lr中;
     68      "mov sp, #0x66000000
    "//
     69      "ldmea sp, {r0-r12, pc}^
    "// 
     70 
     71     "show:
    "
     72      ".word 0xc3e114d8
    "
     73 
     74      "data_string:
    "
     75      ".asciz "hello DATA_ABORT!\n" 
    "
     76 
     77         );
     78 
     79 void init_ttb(unsigned long *addr)
     80 {
     81     unsigned long va = 0;//定义虚拟地址
     82     unsigned long pa = 0;//定义物理地址
     83 
     84     //40000000-------80000000   ====  40000000------80000000
     85     for(va=0x40000000; va<=0x80000000; va+=0x100000){
     86         pa = va;
     87         addr[va >> 20] = pa | 2;
     88         //|2的目的是将0-2位置为10此时将是小页模式4K
     89     }
     90 
     91     //00000000-------10000000   ====  60000000------70000000
     92     for(va=0x00000000; va<=0x10000000; va+=0x100000){
     93         pa = va+0x60000000;
    94         addr[va >> 20] = pa | 2;
     95     }
     96 
     97     //10000000-------14000000   ====  10000000------14000000
     98     for(va=0x10000000; va<=0x30000000; va+=0x100000){
     99         pa = va;
    100         addr[va >> 20] = pa | 2;
    101     }
    102 
    103     //30000000-------40000000   ====  50000000------60000000
    104     for(va=0x30000000; va<0x40000000; va+=0x100000){
    105         pa = va + 0x20000000;
    106         addr[va >> 20] = pa | 2;
    107     }
    108 }
    109 
    110 void enable_mmu(void)
    111 
    112 {
    113     unsigned long addr = 0x70000000;
    114     init_ttb(addr);
    115     //step:初始化页表
    116 
    117     unsigned long mmu = 1 | (1 << 1) | (1 << 8);
    118     //将MMU的第0,1,8位置1
    119     __asm__ __volatile__(
    120         "mov r0, #3
    "
    121         "MCR p15, 0, r0, c3, c0, 0
    "//manager
    122         "MCR p15, 0, %0, c2, c0, 0
    "//addr  
    123         "MCR p15, 0, %1, c1, c0, 0
    "// enable mmu
    124         :
    125         : "r" (addr), "r" (mmu)
    126         : "r0"
    127     );
    128     printf("MMU is enable!
    ");
    129 }
    View Code

    观察处理模块中58行有一句   "sub lr, lr, #4 "特别要注意这句的重要性,是因为当程序执行发生错误的时候,调用PC-->LR   CPSR-->SPSR   LR--->PC   SPSR--->CPSR。而回来的时候PC却跑到了下一条指令去了。

    如果很难理解的话,不妨先记得除了UND和SWI模式,其他的异常模式都需要在处理前将PC的指令前移动一位好了。

    接下来是处理多种异常了,因为在实际中,只出现一种异常的情况很少,一般都是几种异常同时出现,假如是出现的是UND和DATAABORT异常,寄存器先会到04地址去处理UND,但是问题来了,假如处理处理UND异常的指令很长(因为一般不止6个字节),这时候又遇到了ABORT异常当到10地址取处理ABORT异常的时候,取到的却不是想要的值。

    为了解决这个问题,在处理的时候我们对应构建一张异常向量表,当到对应地址去寻找解决异常的时候,B到对应的解决方法里去!实现一个二级的跳转,这样,多种异常同时来我也不怕不怕啦!

      1 
      2 int (*printf)(char *, ...) = 0xc3e114d8;
      3 
      4 void init_ttb(unsigned long *addr);
      5 void enable_mmu(void);
      6 unsigned long data_abort_init();
      7 void memcopy(unsigned long* dest,unsigned long* source,int len);
      8 
      9 int main()
     10 {
     11     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
     12     unsigned long source_addr=data_abort_init();
     13     //异常事件处理函数
     14     printf("swi_souce addr is %x
    ",source_addr);
     15     //将异常处理地址的值放到0x60000004
     16     memcopy(0x60000000,source_addr,0x1000);
     17 
     18     enable_mmu();
     19     //内存映射将0x00000004映射到0x6000000004    
     20     __asm__ __volatile__(
     21         ".word 0x77777777
    "
     22         "mov r0, #1
    "
     23         "ldr r1, [r0]
    "
     24      );
     25     printf("welcome back! 
    ");
     26 
     27 
     28 }
     29 
     30 void memcopy(unsigned long* dest,unsigned long* source,int len)
     31 {
     32     int i=0;;
     33     for(i=0;i<len;i++)
     34         dest[i]=source[i];
     35 }
     36 
     37 unsigned long  data_abort_init()
     38 {
     39     unsigned long source;
     40     __asm__ __volatile__(
     41          "ldr %0, =voliate_start
    "
     42          : "=r" (source)
     43      );
     44 
     45 
     46     return source;
     47 
     48 }
     49 
     50 __asm__(
     51 
     52 "voliate_start:
    "
     53     //跳转目录
     54     " b reset
    "
     55     " b undefined
    "
     56     " b swi
    "
     57     " b pre_abt
    "
     58     " b data_abt
    "
     59     " .word 0
    "//占位符号,一个位占4个字节
     60     " b irq
    "
     61     " b fiq
    "
     62 "
    "
     63 
     64     //跳转要分三部:
     65     //1:将PC保存到新模式下的lr中;
     66     //2:将CPSR保存在SPSR中
     67     //3:初始化SP
     68     //前两步由硬件完成,而第三部需要手动完成
     69 "reset:
    "
     70 
     71 "undefined:
    "
     72      "mov sp, #0x66000000
    "//初始化SP
     73      "stmfd sp!, {r0-r12, lr}
    "//初始化sp,入栈保护寄存器 
     74     //打印一句话 
     75      "ldr r0, =und_string
    "
     76      "ldr r2, show
    "
     77      "blx r2
    "
     78     //跳回来分两部
     79     //1:将CPSR保存在SPSR中
     80     //2:将PC保存到新模式下的lr中;
     81      "mov sp, #0x66000000
    "//
     82      "ldmea sp, {r0-r12, pc}^
    "// 
     83 
     84 "swi:
    "
     85 
     86 "pre_abt:
    "
     87 "data_abt:
    "
     88      "sub lr, lr, #4
    "
     89      "mov sp, #0x66000000
    "//初始化SP
     90      "stmfd sp!, {r0-r12, lr}
    "//初始化sp,入栈保护寄存器 
     91     //打印一句话 
     92      "ldr r0, =data_string
    "
     93      "ldr r2, show
    "
    84 "swi:
    "
     85 
     86 "pre_abt:
    "
     87 "data_abt:
    "
     88      "sub lr, lr, #4
    "
     89      "mov sp, #0x66000000
    "//初始化SP
     90      "stmfd sp!, {r0-r12, lr}
    "//初始化sp,入栈保护寄存器 
     91     //打印一句话 
     92      "ldr r0, =data_string
    "
     93      "ldr r2, show
    "
     94      "blx r2
    "
     95     //跳回来分两部
     96     //1:将CPSR保存在SPSR中
     97     //2:将PC保存到新模式下的lr中;
     98      "mov sp, #0x66000000
    "//
     99      "ldmea sp, {r0-r12, pc}^
    "// 
    100 
    101 "irq:
    "
    102 "fiq:
    "
    103     "show:
    "
    104      ".word 0xc3e114d8
    "
    105 
    106     "und_string:
    "
    107      ".asciz "hello UND!\n" 
    "
    108      "data_string:
    "
    109      ".asciz "hello DATA_ABORT!\n" 
    "
    110 
    111         );
    112 
    113 void init_ttb(unsigned long *addr)
    114 {
    115     unsigned long va = 0;//定义虚拟地址
    116     unsigned long pa = 0;//定义物理地址
    117 
    118     //40000000-------80000000   ====  40000000------80000000
    119     for(va=0x40000000; va<=0x80000000; va+=0x100000){
    120         pa = va;
    121         addr[va >> 20] = pa | 2;
    122         //|2的目的是将0-2位置为10此时将是小页模式4K
    123     }
    124 
    125     //00000000-------10000000   ====  60000000------70000000
    126     for(va=0x00000000; va<=0x10000000; va+=0x100000){
    127         pa = va+0x60000000;
    128         addr[va >> 20] = pa | 2;
    129     }
    130 
    131     //10000000-------14000000   ====  10000000------14000000
    132     for(va=0x10000000; va<=0x14000000; va+=0x100000){
    133         pa = va;
    134         addr[va >> 20] = pa | 2;
    135     }
    136 
    137     //30000000-------40000000   ====  50000000------60000000
    138     for(va=0x30000000; va<0x40000000; va+=0x100000){
    139         pa = va + 0x20000000;
    140         addr[va >> 20] = pa | 2;
    141     }
    142 }
    143 
    144 void enable_mmu(void)
    145 
    146 {
    147     unsigned long addr = 0x70000000;
    148     init_ttb(addr);
    149     //step:初始化页表
    150 
    151     unsigned long mmu = 1 | (1 << 1) | (1 << 8);
    152     //将MMU的第0,1,8位置1
    153     __asm__ __volatile__(
    154         "mov r0, #3
    "
    155         "MCR p15, 0, r0, c3, c0, 0
    "//manager
    156         "MCR p15, 0, %0, c2, c0, 0
    "//addr  
    157         "MCR p15, 0, %1, c1, c0, 0
    "// enable mmu
    158         :
    159         : "r" (addr), "r" (mmu)
    160         : "r0"
    161     );
    162     printf("MMU is enable!
    ");
    163 }
    View Code

    测试一下结果:

    总结一下:1.如果处理的是执行中发生的异常,PC回一一条指令:

           "sub lr, lr, #4 "

         2.为了解决处理异常地址错乱,构建一张异常向量表:跳转到指定地点解决:

           //跳转目录
                " b reset "
                  " b undefined "
                 " b swi "
                  " b pre_abt "
                  " b data_abt "
                  " .word 0 "//占位符号,一个位占4个字节
                  " b irq "
                 " b fiq "

          //前两步由硬件完成,而第三部需要手动完成
     69 "reset: "
     70
     71 "undefined: "
     72      "mov sp, #0x66000000 "//初始化SP
     73      "stmfd sp!, {r0-r12, lr} "//初始化sp,入栈保
        护寄存器
     74     //打印一句话
     75      "ldr r0, =und_string "
     76      "ldr r2, show "
     77      "blx r2 "
    ...........................

        





     

  • 相关阅读:
    计划给予心脏公式
    平原绫香 Hirahara Ayaka-Jupiter
    legend---十一、thinkphp事务中if($ans1&&$ans2){}else{}方式和try{}catch{}方式事务操作的区别在哪里
    chrome控制台常用技巧有哪些
    js中console强大之处体现在哪
    Pocket英语语法---五、形式主语是怎么回事
    智课雅思词汇---十二、vent是什么意思
    英语影视台词---八、the shawshank redemption
    Pocket英语语法---四、should的同义词是谁
    m_Orchestrate learning system---二十七、修改时如何快速找到作用位置
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4506180.html
Copyright © 2011-2022 走看看