首页 > 代码库 > 第三十七天:Tiny4412驱动开发之二级跳转

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

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

  

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

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

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

   

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

   

  比如现在要模拟发生未定义指令异常,现在整个流程是:第一步开启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~14000000110     for(va=0x10000000; va<0x14000000; va+=0x100000){111         pa = va;112         ttb[va >> 20] = pa | 2;113     }114 115     //40000000~80000000  -> 40000000~80000000116     for(va=0x40000000; va<0x80000000; va+=0x100000){117         pa = va;118         ttb[va >> 20] = pa | 2;119     }120 121     //30000000~40000000  -> 50000000~60000000122     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<len; i++)148         dest[i] = source[i];149 }

    运行截图:

    

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

 

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

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

说明代码正确。

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

 

 

            

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