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 %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 }
如果代码中的汇编语言执行的时候将会发生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 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的指令前移动一位好了。 接下来是处理多种异常了,因为在实际中,只出现一种异常的情况很少,一般都是几种异常同时出现,假如是出现的是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 %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 27 28 } 29 30 void memcopy(unsigned long* dest,unsigned long* source,int len) 31 { 32 int i=0;; 33 for(i=0;i 35 } 36 37 unsigned long data_abort_init() 38 { 39 unsigned long source; 40 __asm__ __volatile__( 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 " b resetn" 55 " b undefinedn" 56 " b swin" 57 " b pre_abtn" 58 " b data_abtn" 59 " .word 0n"//占位符号,一个位占4个字节 60 " b irqn" 61 " b fiqn" 62 "n" 63 64 //跳转要分三部: 65 //1:将PC保存到新模式下的lr中; 66 //2:将CPSR保存在SPSR中 67 //3:初始化SP 68 //前两步由硬件完成,而第三部需要手动完成 69 "reset:n" 70
上一篇:qemu+chroot构建arm aarch64虚拟机
下一篇:ARM4412中SWI中断
推荐阅读最新更新时间:2024-11-12 16:57
设计资源 培训 开发板 精华推荐
- LT1120CN8 限流 1A 稳压器的典型应用电路
- FSQ0270RNA绿色模式电源开关典型应用电路
- L78L09AC输出升压电路正电压稳压器的典型应用
- LT3472,一个 1.1MHz、2.7V4.2V 至 15V、25mA 和 8V、35mA 转换器/逆变器
- 多通道步进电机驱动IC —— TB67H452FTG
- 使用 ROHM Semiconductor 的 BD4739 的参考设计
- 具有 I2C 基准的 LTC2655IGN-H12 四通道、12 位轨至轨 DAC 的典型应用
- LTC2162 的典型应用 - 16 位、65Msps 低功耗 ADC
- LTC3867EUF 高效同步降压控制器的典型应用电路
- AR0234CSSM00SUKAH3-GEVB:带有 2MP 单声道 0deg 全局快门 CMOS 图像传感器的 2.3MP 评估板