第三十七天:Tiny4412驱动开发之二级跳转

  ARM五级流水线:取值,译码,执行,访存,回写。未定义指令异常和SWI软中断发生在译码阶段,其它异常发生在执行阶段。

  第三十七天:Tiny4412驱动开发之二级跳转_第1张图片

  现在假设有五条指令,三指令正在执行的时候,四指令在译码过程中发生未定义指令异常,跳转到异常处理程序回来后,因为 PC指向五指令,所以继续执行五指令的内容。

  但是,如果程序在三指令执行期间发生错误,处理回来后到达五指令,把四指令跳过了。解决方式是在处理的把PC的值减去四,具体的代码会在后面的中断代码中体现。

  前文的最后提到如果三个异常同时发生,三个异常处理程序员都要放到指定的地址中处理。这必定会出现重叠。如下图:

   第三十七天:Tiny4412驱动开发之二级跳转_第2张图片

       如果我把swi处理函数放在0x4地址,data abort处理函数放在0x10地址。data abort的处理异常函数就会把swi处理函数.处理方式就是在0x00000000地址上建立异常向量表,下面是实现的代码片段:

   第三十七天:Tiny4412驱动开发之二级跳转_第3张图片

  比如现在要模拟发生未定义指令异常,现在整个流程是:第一步开启MMU,第二步将异常向量表放在0地址。第三步模拟发生未定义异常,跳到0x4地址执行。因为0x4地址也是个跳转指令,就到undef处执行。由于编写大部分程序使用C语言比较方便,在实际处理中,还要进行一次跳转。第四步就是在undef中跳转到C函数,执行函数。第五步。执行完成后回来。回到主函数PC处继续执行。

  下面是具体的代码:同时发生两个异常:

  1 int (*printf)(char *, ...) = 0xc3e114d8;
  2 
  3 void init_ttb(unsigned long *ttb);
  4 void enable_mmu(void);
  5 void memcpy(unsigned char *dest, unsigned char *source, int len);
  6 void do_ex();
  7 
  8 int main()
  9 {
 10     enable_mmu();
 11 
 12     *(unsigned long *)0x67000000 = do_ex;
 13     unsigned long source = 0;
 14     __asm__ __volatile__(
 15         "ldr %0, =vector_start\n"
 16         : "=r" (source)
 17     );
 18     memcpy(0, source, 0x1000);
 19     
 20     __asm__ __volatile__(
 21         "mov r0, #3\n"
 22         "ldr r1, [r0]\n"
 23         ".word 0x77777777\n"
 24     );
 25     printf("welcome back\n");
 26 }
 27 
 28 void do_ex()
 29 {
 30     unsigned long cpsr = 0;
 31     
 32     __asm__ __volatile__(
 33         "mrs %0, cpsr\n"
 34         : "=r" (cpsr)
 35     );
 36     printf("cpsr is %x\n", cpsr & 0x1f);
 37 }
 38 
 39 __asm__(
 40 "vector_start:\n"
 41 "    b reset\n"
 42 "    b undef\n"
 43 "    b swi\n"
 44 "    b pre_abt\n"
 45 "    b data_abt\n"
 46 "    .word 0x0\n"
 47 "    b irq \n"
 48 "    b fiq\n"
 49 "\n"
 50 "reset:\n"
 51 "undef:\n"
 52 "    mov sp, #0x66000000\n"
 53 "    stmfd sp!, {r0-r12, lr}\n"
 54 "    \n"
 55 "    mov r0, #0x67000000\n"
 56 "    ldr r1, [r0]\n"
 57 "    blx r1\n"
 58 "    \n"
 59 "    mov sp, #0x66000000\n"
 60 "    ldmea sp, {r0-r12, pc}^\n"
 61 "swi:\n"
 62 "    mov sp, #0x66000000\n"
 63 "    stmfd sp!, {r0-r12, lr}\n"
 64 "    \n"
 65 "    mov r0, #0x67000000\n"
 66 "    ldr r1, [r0]\n"
 67 "    blx r1\n"
 68 "    \n"
 69 "    mov sp, #0x66000000\n"
 70 "    ldmea sp, {r0-r12, pc}^\n"
 71 "\n"
 72 "pre_abt:\n"
 73 "data_abt:\n"
 74 "    mov sp, #0x66000000\n"
 75 "    sub lr, lr, #4\n"
 76 "    stmfd sp!, {r0-r12, lr}\n"
 77 "    \n"
 78 "    mov r0, #0x67000000\n"
 79 "    ldr r1, [r0]\n"
 80 "    blx r1\n"
 81 "    \n"
 82 "    mov sp, #0x66000000\n"
 83 "    ldmea sp, {r0-r12, pc}^\n"
 84 "irq:\n"
 85 "    mov sp, #0x66000000\n"
 86 "    sub lr, lr, #4\n"
 87 "    stmfd sp!, {r0-r12, lr}\n"
 88 "    \n"
 89 "    mov r0, #0x67000000\n"
 90 "    ldr r1, [r0]\n"
 91 "    blx r1\n"
 92 "    \n"
 93 "    mov sp, #0x66000000\n"
 94 "    ldmea sp, {r0-r12, pc}^\n"
 95 "fiq:\n"
 96 
 97 );
 98 
 99 void init_ttb(unsigned long *ttb)
100 {
101     unsigned long va = 0;
102     unsigned long pa = 0;
103     
104     for(va=0x00000000; va<0x10000000; va+=0x100000){
105         pa = va + 0x60000000;
106         ttb[va >> 20] = pa | 2;
107     }
108     
109     //10000000~14000000  -> 10000000~14000000
110     for(va=0x10000000; va<0x14000000; va+=0x100000){
111         pa = va;
112         ttb[va >> 20] = pa | 2;
113     }
114 
115     //40000000~80000000  -> 40000000~80000000
116     for(va=0x40000000; va<0x80000000; va+=0x100000){
117         pa = va;
118         ttb[va >> 20] = pa | 2;
119     }
120 
121     //30000000~40000000  -> 50000000~60000000
122     for(va=0x30000000; va<0x40000000; va+=0x100000){
123         pa = va + 0x20000000;
124         ttb[va >> 20] = pa | 2;
125     }
126 }
127 
128 void enable_mmu(void)
129 {
130     unsigned long ttb = 0x70000000;
131     init_ttb(ttb);
132     unsigned long mmu = 0;
133     mmu = 1 | (1 << 3) | (1 << 8);
134     __asm__ __volatile__(
135         "mov r0, #3\n"
136         "mcr p15, 0, r0, c3, c0, 0\n" 
137         "mcr p15, 0, %0, c2, c0, 0\n" 
138         "mcr p15, 0, %1, c1, c0, 0\n" 
139         :
140         : "r" (ttb), "r" (mmu)
141     );
142 }
143 
144 void memcpy(unsigned char *dest, unsigned char *source, int len)
145 {
146     int i = 0;
147     for(i=0; i)
148         dest[i] = source[i];
149 }

    运行截图:

第三十七天:Tiny4412驱动开发之二级跳转_第4张图片    

     这里要对cpsr(CPU状态寄存器)介绍下,直接看arm手册中的描述:

 第三十七天:Tiny4412驱动开发之二级跳转_第5张图片

    现在异常发生都到去0x67000000地址中执行。而0x6700000中存放的是do_ex()函数。do_ex()函数的功能是读取cpsr中的后4位,并且打印出来。从上图可以知道,后四位表示的是处于的模式。

  17用二进制表示为10111  1b用二进制表示为11011  查阅三十六天所写的模式跳转第一张表格,10111对应Abor模式,11011对应Undefine模式。

说明代码正确。

  以后编写代码异常处理代码,就直接do_ex()函数中编写。其它的开启MMU,二级跳转。代码都不变!

 

 

            

你可能感兴趣的:(Linux)