Tiny4412模式跳转

  ARM体系的CPU有以下7种工作模式:

          1、用户模式(Usr):用于正常执行程序;

          2、快速中断模式(FIQ):用于高速数据传输;

          3、外部中断模式(IRQ):用于通常的中断处理;

          4、管理模式(svc):操作系统使用的保护模式;

          5、数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储以及存储保护;

          6、系统模式(sys):运行具有特权的操作系统任务;

          7、未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件;

  如下图:

 

要进行模式跳转,就需要要有异常事件在触发它进行模式跳转,在ARM中,异常有如下几种:

 

 

  (1)在异常向量表中,需要注意的是未定义指令(undefined),软中断(swi)是发生在译码阶段,其他五种都发生在执行阶段;ARM中的流水线分为:取值,译码,执行,仿存,回写这五步,当一条指令正在执行时,它的下一条指令正在译码,下下一条在取值,pc指向的是正在取值的那条指令,在模式跳转要回去的时候这点需要认真考虑

  (2)通过上图我们可以看出要是发生undefined,它就会自动跳到0x0000004这个地址去执行,那如果我们在这个地址放一段代码,到时候就可以知道有没有发生异常,是不是跳到0x0000004这个;思想就是这样,但是现在有遇到一个新的问题,因为在这个三星公司将0x00000000—0x00010000为iROM,这个地址是只能读,不能改,因此我们就要需开启mmu,把0x00000004映射到其他空闲的地址上去:

下面是代码:

  1 int (*printf)(char *, ...) = 0xc3e114d8;
  2 void enable_mmu();
  3 void memcpy(unsigned long *dest, unsigned long *source, int len);
  4 void init_table(unsigned long *addr);
  5 unsigned long swi_init();
  6 
  7 int main()
  8 {
  9     unsigned long source = swi_init();
 10     printf("source is %x\n", source);
 11 
 12     memcpy(0x60000004, source, 0x1000);    
 13     enable_mmu();
 14 
 15     __asm__ __volatile__ (
 16         ".word 0xffffffff\n"
 17     );
 18 
 19     printf("welcom back\n");    
 20 }
 21 
 22 unsigned long swi_init()
 23 {
 24     unsigned long addr;
 25     __asm__ __volatile__ (
 26         "ldr %0, =start \n"
 27         : "=r" (addr)
 28     );
 29     
 30     return addr;    
 31 }
 32 
 33 void memcpy(unsigned long *dest, unsigned long *source, int len)
 34 {
 35     int i = 0;
 36     for(i = 0; i < len; i++) {
 37         dest[i] = source[i];
 38     }
 39 }
 40 
 41 void enable_mmu()
 42 {
 43     /*构建表*/
 44     unsigned long addr = 0x50000000;
 45     init_table(addr);
 46     /*打开mmu*/
 47     unsigned long mmu = 0;
 48     mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
 49     __asm__ __volatile__ (
 50          "mov r0, #3\n"
 51         "MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
 52         "MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
 53         "MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
 54         :    
 55         :    "r" (addr), "r" (mmu)
 56         :
 57     );
 58 
 59 }
 60 
 61 __asm__ (
 62     
 63     "start: \n"
 64     "mov sp, #0x47000000\n"
 65     "stmdb sp!, {r0-r12, lr}\n"
 66 
 67     "ldr r3, data\n"
 68     "ldr r0, =str_und\n"
 69     "blx r3\n"
 70     
 71     /*跳回去代码*/
 72     "mov sp, #0x47000000\n"
 73     "ldmdb sp, {r0-r12, pc}^\n"//
 74 
 75     "data:\n"
 76     ".word 0xc3e114d8\n"
 77 
 78     "str_und:\n"
 79     ".asciz \"this is undefined\\n\"\n"
 80     ".align 2\n"
 81 );
 82 
 83 void init_table(unsigned long *addr)
 84 {
 85     unsigned long va = 0;
 86     unsigned long phys = 0;
 87 
 88     //0x40000000-0x80000000 -> 0x40000000-0x80000000    
 89     for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
 90         phys = va;
 91         addr[va >> 20] = phys | 2;
 92     }
 93 
 94     //0x10000000-0x14000000 -> 0x10000000-0x140000000    
 95     for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
 96         phys = va;
 97         addr[va >> 20] = phys | 2;
 98     }
 99     //0x10000000-0x14000000 -> 0x10000000-0x140000000    
100     for(va = 0x0; va < 0x10000000; va += 0x100000) {
101         phys = va + 0x60000000;
102         addr[va >> 20] = phys | 2;
103     }
104             
105 }

在开发板运行结果如下:

  总结一下:当一个模式发生跳转是,需要三步:(1)将pc存到lr中,pc->lr;(2)将cpsr存到spsr,cpsr-spsr;(3)初始化sp;第一二步由系统硬件自动完成,第三部需要我们手动完成;

  模式跳回去的时候逆过过来就ok,初始化sp,将lr还给pc,spsr还给cpsr,注意需要同时一起还,73行

  上面代码还有一问题就是,要是几个异常一起发生怎么办,因为我们不能控制它每次执法生一个吧,cpu留给我们处理每个异常的只有4个字节,那么我们就需要进行二级跳转了,下面贴出二级跳转代码:

 

  1 int (*printf)(char *, ...) = 0xc3e114d8;
  2 void enable_mmu();
  3 void init_table(unsigned long *addr);
  4 void memcpy(unsigned char *dest, unsigned char *src, int len);
  5 extern unsigned long  vector_start;
  6 
  7 int main()
  8 {    
  9     memcpy(0x70000000, vector_start, 0x1000);    
 10     enable_mmu();
 11 
 12     __asm__ __volatile__(
 13         ".word 0x77777777\n"    
 14         "mov r3, #3\n"
 15         "ldr r0, [r3]\n"
 16     );
 17     
 18     printf("welcom back\n");
 19 
 20     return 0;
 21 }
 22 
 23 void memcpy(unsigned char *dest, unsigned char *src, int len)
 24 {
 25     int i = 0;
 26     for(i = 0; i < len; i++) {
 27         dest[i] = src[i];
 28     }
 29 }
 30 
 31 void enable_mmu()
 32 {
 33     //step 1: creat ttb
 34     unsigned long addr = 0x50000000;
 35     init_table(addr);
 36     //step 2: enable mmu
 37     unsigned long mmu = 0;
 38     mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
 39     __asm__ __volatile__ (
 40         "mov r0, #3\n"
 41         "MCR p15, 0, r0, c3, c0, 0\n"//set manage
 42         "MCR p15, 0, %0, c2, c0, 0\n"//set ttb
 43         "MCR p15, 0, %1, c1, c0, 0\n"//enable mmu
 44         :    
 45         :    "r" (addr), "r" (mmu)
 46         :
 47     );
 48 
 49 }
 50 
 51 __asm__(
 52 
 53 "vector: \n"
 54 "    b reset\n"
 55 "    b und\n"
 56 "    b swi\n"
 57 "    b pre_abt\n"
 58 "    b data_abt\n"
 59 "    .word 0x0\n"
 60 "    b irq\n"
 61 "    b fiq\n"
 62 
 63 "reset:\n"
 64 
 65 "und:\n"
 66     /*模式跳转进来分三步:
 67      *(1)将pc存到lr,pc->lr
 68     *(2)将cpsr存到spsr
 69     *(3)初始化sp
 70     *前两部系统硬件帮我们完成,第三步需要我们手动配置*/
 71 "    mov sp, #0x47000000\n"
 72 "    stmdb sp!, {r0-r12, lr}\n"
 73 
 74 "    ldr r3, show\n"
 75 "    ldr r0, =str_und\n"
 76 "    blx r3\n"
 77 
 78     /*回去的时候逆回去就ok*,^表示同时还回去*/
 79 "    mov sp, #0x47000000\n"
 80 "    ldmdb sp, {r0-r12, pc}^    \n"
 81 
 82 "swi:\n"
 83 
 84 "    mov sp, #0x47000000\n"
 85 "    stmdb sp!, {r0-r12, lr}\n"
 86 
 87 "    ldr r3, show\n"
 88 "    ldr r0, =str_swi\n"
 89 "    blx r3\n"
 90 
 91 "    mov sp, #0x47000000\n"
 92 "    ldmdb sp, {r0-r12, pc}^    \n"
 93 "pre_abt:\n"
 94 
 95 "data_abt:\n"
 96 
 97 "    mov sp, #0x47000000\n"
 98 "    sub lr, lr, #4\n"//这句需要好好理解
 99 "    stmdb sp!, {r0-r12, lr}\n"
100 
101 "    ldr r3, show\n"
102 "    ldr r0, =str_data\n"
103 "    blx r3\n"
104 
105 "    mov sp, #0x47000000\n"
106 "    ldmdb sp, {r0-r12, pc}^    \n"
107 
108 "irq:\n"
109 
110 "fiq:\n"
111 
112 "show:\n"
113 "    .word 0xc3e114d8\n"
114 
115 "str_data:\n"
116 "    .asciz \"this is data abort\\n\"\n"
117 "    .align 2\n"
118 
119 "str_swi:\n"
120 "    .asciz \"this is swi \\n\"\n"
121 "    .align 2\n"
122 
123 "str_und:\n"
124 "    .asciz \"this is undefined \\n\"\n"
125 "    .align 2\n"
126 
127     ".global vector_start\n"
128 "vector_start: \n"
129     ".word vector \n "
130 
131 );
132 
133 void init_table(unsigned long *addr)
134 {
135     unsigned long va = 0;
136     unsigned long phys = 0;
137 
138     //0x40000000-0x80000000 -> 0x40000000-0x80000000    
139     for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
140         phys = va;
141         addr[va >> 20] = phys | 2;
142     }
143 
144     //0x10000000-0x14000000 -> 0x10000000-0x140000000    
145     for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
146         phys = va;
147         addr[va >> 20] = phys | 2;
148     }
149     //0x10000000-0x14000000 -> 0x10000000-0x140000000    
150     for(va = 0x0; va < 0x10000000; va += 0x100000) {
151         phys = va + 0x70000000;
152         addr[va >> 20] = phys | 2;
153     }
154             
155 }

下面是运行结果:

 

posted @ 2015-09-01 13:56  zhangwju  阅读(1106)  评论(0编辑  收藏  举报