在ARM中的流水线分为:取值,译码,执行,仿存,回写。这五步详细如下:
而主要发生异常情况主要集中在译码以及执行阶段。此次的SWI(软中断)和上次的UND中断都出现在译码阶段,而其他5种中断都发生在执行阶段。
在异常向量表中可以看见对应异常的模式以及SWI异常的描述如图,详细参考ARM架构手册第54以及58页
如下代码,当发生SWI中断异常
1 2 3 4 5 6 7 8 9 10 11 | 2 int (*printf)(char *, ...) = 0xc3e114d8; 3 4 int main() 5 { 6 __asm__ __volatile__( 7 "swi #88n" 8 ); 9 10 printf("welcome backn"); 11 } 12 |
此时,对应地异常向量表。ARM就会到0x00000008这个地址去取指令来处理软异常,和处理UND异常一样,实现跳转模式,处理异常(在这里,我们打印“hello swi”).然后再跳转回来。我们把这处理的指令存到SOURCE地址中,由MEMCOPY函数拷贝到0X60000008地址。然后触发异常,最后打印一句话,如果能打印“welcome back”则代表测试成功。
1
2 int (*printf)(char *, ...) = 0xc3e114d8;
3
4 void init_ttb(unsigned long *addr);
5 void enable_mmu(void);
6 unsigned long swi_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=swi_init();
13 //异常事件处理函数
14 printf("swi_souce addr is %xn",source_addr);
15 //将异常处理地址的值放到0x60000004
16 memcopy(0x60000008,source_addr,0x100);
17
18 enable_mmu();
19 //内存映射将0x00000004映射到0x6000000004
20 __asm__ __volatile__(
21 "swi #88n"
22 );
23 printf("welcome back! n");
24
25
26 }
27
28 void memcopy(unsigned long* dest,unsigned long* source,int len)
29 {
30 int i=0;;
31 for(i=0;i
32 dest[i]=source[i];
33 }
34
35 unsigned long swi_init()
36 {
37 unsigned long source;
38 __asm__ __volatile__(
39 "ldr %0, =swi_startn"
40 : "=r" (source)
41 );
42
43
44 return source;
45
46 }
47 __asm__(
48 "swi_start:n"
49
50
51 //跳转要分三部:
52 //1:将PC保存到新模式下的lr中;
53 //2:将CPSR保存在SPSR中
54 //3:初始化SP
55 //前两步由硬件完成,而第三部需要手动完成
56 "mov sp, #0x66000000n"//初始化SP
57 "stmfd sp!, {r0-r12, lr}n"//初始化sp,入栈保护寄存器
58
59 //打印一句话
60 "ldr r0, =stringn"
61 "ldr r2, shown"
62 "blx r2n"
63
64 //跳回来分两部
65 //1:将CPSR保存在SPSR中
66 //2:将PC保存到新模式下的lr中;
67 "mov sp, #0x66000000n"//
68 "ldmea sp, {r0-r12, pc}^n"//
69
70
71 "loop:n"
72 "b loopn"
73
74
75 "show:n"
76 ".word 0xc3e114d8n"
77
78 "string:n"
79 ".asciz "hello SWI\n" n"
80 ".align 2n"
81 );
82
83 void init_ttb(unsigned long *addr)
84 {
85 unsigned long va = 0;//定义虚拟地址
86 unsigned long pa = 0;//定义物理地址
87
88 //40000000-------80000000 ==== 40000000------80000000
89 for(va=0x40000000; va<=0x80000000; va+=0x100000){
90 pa = va;
91 addr[va >> 20] = pa | 2;
92 //|2的目的是将0-2位置为10此时将是小页模式4K
93 }
94
95 //00000000-------10000000 ==== 60000000------70000000
96 for(va=0x00000000; va<=0x10000000; va+=0x100000){
97 pa = va+0x60000000;
98 addr[va >> 20] = pa | 2;
99 }
100
101 //10000000-------14000000 ==== 10000000------14000000
102 for(va=0x10000000; va<=0x14000000; va+=0x100000){
103 pa = va;
104 addr[va >> 20] = pa | 2;
105 }
106
107 //30000000-------40000000 ==== 50000000------60000000
108 for(va=0x30000000; va<0x40000000; va+=0x100000){
109 pa = va + 0x20000000;
110 addr[va >> 20] = pa | 2;
111 }
112 }
113
114 void enable_mmu(void)
115
116 {
117 unsigned long addr = 0x70000000;
118 init_ttb(addr);
119 //step:初始化页表
120
121 unsigned long mmu = 1 | (1 << 1) | (1 << 8);
122 //将MMU的第0,1,8位置1
123 __asm__ __volatile__(
124 "mov r0, #3n"
125 "MCR p15, 0, r0, c3, c0, 0n"//manager
126 "MCR p15, 0, %0, c2, c0, 0n"//addr
127 "MCR p15, 0, %1, c1, c0, 0n"// enable mmu
128 :
129 : "r" (addr), "r" (mmu)
130 : "r0"
131 );
132 printf("MMU is enable!n");
133 }
vim Makefile:
1
2 all:
3 arm-none-linux-gnueabi-gcc -c mmu.c -o mmu.o
4 arm-none-linux-gnueabi-ld -Ttext=0x41000000 mmu.o -o mmu
5 arm-none-linux-gnueabi-objcopy -Ielf32-littlearm -Obinary mmu mmu.bin
6
make
在minicom中dnw 41000000,
在终端中下载dnw 到板子,go 41000000
可以思考一下:怎么将SWI立即数打印出来?
关键字:ARM4412 SWI中断 流水线『本文转载自网络,版权归原作者所有,如有侵权请联系删除』