ARM4412中SWI中断。

在ARM中的流水线分为:取值,译码,执行,仿存,回写。这五步详细如下:

而主要发生异常情况主要集中在译码以及执行阶段。此次的SWI(软中断)和上次的UND中断都出现在译码阶段,而其他5种中断都发生在执行阶段。

在异常向量表中可以看见对应异常的模式以及SWI异常的描述如图,详细参考ARM架构手册第54以及58页

如下代码,当发生SWI中断异常

 
  2 int (*printf)(char *, ...) = 0xc3e114d8;
  3 
  4 int main()
  5 {
  6     __asm__ __volatile__(
  7         "swi #88
"
  8     );
  9 
 10     printf("welcome back
");
 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 %x
",source_addr);
 15     //将异常处理地址的值放到0x60000004
 16     memcopy(0x60000008,source_addr,0x100);
 17 
 18     enable_mmu();
 19     //内存映射将0x00000004映射到0x6000000004    
 20     __asm__ __volatile__(
 21         "swi #88
"
 22      );
 23     printf("welcome back! 
");
 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<len;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_start
"
 40          : "=r" (source)
 41      );
 42 
 43 
 44     return source;
 45 
 46 }
 47 __asm__(
 48      "swi_start:
"
 49 
 50 
 51     //跳转要分三部:
 52     //1:将PC保存到新模式下的lr中;
 53     //2:将CPSR保存在SPSR中
 54     //3:初始化SP
 55     //前两步由硬件完成,而第三部需要手动完成
 56      "mov sp, #0x66000000
"//初始化SP
 57      "stmfd sp!, {r0-r12, lr}
"//初始化sp,入栈保护寄存器 
 58 
 59     //打印一句话 
 60      "ldr r0, =string
"
 61      "ldr r2, show
"
 62      "blx r2
"
 63 
 64     //跳回来分两部
 65     //1:将CPSR保存在SPSR中
 66     //2:将PC保存到新模式下的lr中;
 67      "mov sp, #0x66000000
"//
 68      "ldmea sp, {r0-r12, pc}^
"// 
 69 
 70 
 71      "loop:
"
 72      "b loop
"
 73 
 74 
 75      "show:
"
 76      ".word 0xc3e114d8
"
 77 
 78      "string:
"
 79      ".asciz "hello SWI\n" 
"
 80      ".align 2
"
 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, #3
"
125         "MCR p15, 0, r0, c3, c0, 0
"//manager
126         "MCR p15, 0, %0, c2, c0, 0
"//addr  
127         "MCR p15, 0, %1, c1, c0, 0
"// enable mmu
128         :
129         : "r" (addr), "r" (mmu)
130         : "r0"
131     );
132     printf("MMU is enable!
");
133 }
View Code

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立即数打印出来?

原文地址:https://www.cnblogs.com/hongzhunzhun/p/4505489.html