找回密码
 注册
关于网站域名变更的通知
查看: 435|回复: 1
打印 上一主题 下一主题

ARM多种异常的处理

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-4-8 14:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
ARM中的流水线分为:取值,译码,执行,仿存,回写这五步,SWI(软中断)和UND中断都出现在译码阶段,而其他5种中断都发生在执行阶段。SWI和UND异常两种处理方法步骤都差不多,但是如果是异常出现在执行阶段要怎么样处理呢?
& ?8 c. }! V$ D, A( y7 P
int main()
10 {
11     //发生异常时会进入异常模式跳转到0000 0004地址处理异常事件   
12     unsigned long source_addr=data_abort_init();
13     //异常事件处理函数
14     printf("swi_souce addr is %xn",source_addr);
15     //将异常处理地址的值放到0x60000004
16     mEMCopy(0x60000010,source_addr,0x1000);
17     
18     enable_mmu();
19     //内存映射将0x00000004映射到0x6000000004   
20     __asm__ __volatile__(
21         "mov r0, #1n"
22         "ldr r1, [r0]n"
23      );
24     printf("welcome back! n");
25
26
27 }
1 x9 N9 f" J' W- t" E2 o  T( G% F, Y
如果代码中的汇编语言执行的时候将会发生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 %xn",source_addr);
15     //将异常处理地址的值放到0x600000010
16     memcopy(0x60000010,source_addr,0x1000);
17
18     enable_mmu();
19     //内存映射将0x00000004映射到0x6000000004   
20     __asm__ __volatile__(
21         "mov r0, #1n"
22         "ldr r1, [r0]n"
23      );
24     printf("welcome back! n");
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
33         dest=source;
34 }
35
36 unsigned long  data_abort_init()
37 {
38     unsigned long source;
39     __asm__ __volatile__(
40
41          "ldr %0, =voliate_startn"
42          : "=r" (source)
43      );
44
45
46     return source;
47
48 }
49
50 __asm__(
51
52 "voliate_start:n"
53     //跳转要分三部:
54     //1:将PC保存到新模式下的lr中;
55     //2:将CPSR保存在SPSR中
56     //3:初始化SP
57     //前两步由硬件完成,而第三部需要手动完成
58      "sub lr, lr, #4n"
59      "mov sp, #0x66000000n"//初始化SP
60      "stmfd sp!, {r0-r12, lr}n"//初始化sp,入栈保护寄存器
61     //打印一句话
62      "ldr r0, =data_stringn"
63      "ldr r2, shown"
64      "blx r2n"
65     //跳回来分两部
66     //1:将CPSR保存在SPSR中
67     //2:将PC保存到新模式下的lr中;
68      "mov sp, #0x66000000n"//
69      "ldmea sp, {r0-r12, pc}^n"//
70
71     "show:n"
72      ".word 0xc3e114d8n"
73
74      "data_string:n"
75      ".asciz "hello DATA_ABORT!\n" 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, #3n"
121         "MCR p15, 0, r0, c3, c0, 0n"//manager
122         "MCR p15, 0, %0, c2, c0, 0n"//addr  
123         "MCR p15, 0, %1, c1, c0, 0n"// enable mmu
124         :
125         : "r" (addr), "r" (mmu)
126         : "r0"
127     );
128     printf("MMU is enable!n");
129 }
观察处理模块中58行有一句   "sub lr, lr, #4n"特别要注意这句的重要性,是因为当程序执行发生错误的时候,调用PC-->LR   CPSR-->SPSR   LR--->PC   SPSR--->CPSR。而回来的时候PC却跑到了下一条指令去了。
如果很难理解的话,不妨先记得除了UND和SWI模式,其他的异常模式都需要在处理前将PC的指令前移动一位好了。
4 C1 T/ H& @' ]
接下来是处理多种异常了,因为在实际中,只出现一种异常的情况很少,一般都是几种异常同时出现,假如是出现的是UND和DATAABORT异常,寄存器先会到04地址去处理UND,但是问题来了,假如处理处理UND异常的指令很长(因为一般不止6个字节),这时候又遇到了ABORT异常当到10地址取处理ABORT异常的时候,取到的却不是想要的值。

  q3 Q# X1 h/ S1 G3 U5 S% ~
为了解决这个问题,在处理的时候我们对应构建一张异常向量表,当到对应地址去寻找解决异常的时候,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 %xn",source_addr);
15     //将异常处理地址的值放到0x60000004
16     memcopy(0x60000000,source_addr,0x1000);
17
18     enable_mmu();
19     //内存映射将0x00000004映射到0x6000000004   
20     __asm__ __volatile__(
21         ".word 0x77777777n"
22         "mov r0, #1n"
23         "ldr r1, [r0]n"
24      );
25     printf("welcome back! n");
26

' O6 G1 z$ t: C. c2 H8 X
  • TA的每日心情
    开心
    2023-1-3 15:10
  • 签到天数: 2 天

    [LV.1]初来乍到

    2#
    发表于 2021-4-8 15:39 | 只看该作者
    取值,译码,执行,仿存,回写
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-6-25 04:55 , Processed in 0.109375 second(s), 23 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表