• 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
    ", source);
     11 
     12     memcpy(0x60000004, source, 0x1000);    
     13     enable_mmu();
     14 
     15     __asm__ __volatile__ (
     16         ".word 0xffffffff
    "
     17     );
     18 
     19     printf("welcom back
    ");    
     20 }
     21 
     22 unsigned long swi_init()
     23 {
     24     unsigned long addr;
     25     __asm__ __volatile__ (
     26         "ldr %0, =start 
    "
     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
    "
     51         "MCR p15, 0, r0, c3, c0, 0
    "//设置为管理员
     52         "MCR p15, 0, %0, c2, c0, 0
    "//设置表的地址
     53         "MCR p15, 0, %1, c1, c0, 0
    "//开启mmu
     54         :    
     55         :    "r" (addr), "r" (mmu)
     56         :
     57     );
     58 
     59 }
     60 
     61 __asm__ (
     62     
     63     "start: 
    "
     64     "mov sp, #0x47000000
    "
     65     "stmdb sp!, {r0-r12, lr}
    "
     66 
     67     "ldr r3, data
    "
     68     "ldr r0, =str_und
    "
     69     "blx r3
    "
     70     
     71     /*跳回去代码*/
     72     "mov sp, #0x47000000
    "
     73     "ldmdb sp, {r0-r12, pc}^
    "//
     74 
     75     "data:
    "
     76     ".word 0xc3e114d8
    "
     77 
     78     "str_und:
    "
     79     ".asciz "this is undefined\n"
    "
     80     ".align 2
    "
     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
    "    
     14         "mov r3, #3
    "
     15         "ldr r0, [r3]
    "
     16     );
     17     
     18     printf("welcom back
    ");
     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
    "
     41         "MCR p15, 0, r0, c3, c0, 0
    "//set manage
     42         "MCR p15, 0, %0, c2, c0, 0
    "//set ttb
     43         "MCR p15, 0, %1, c1, c0, 0
    "//enable mmu
     44         :    
     45         :    "r" (addr), "r" (mmu)
     46         :
     47     );
     48 
     49 }
     50 
     51 __asm__(
     52 
     53 "vector: 
    "
     54 "    b reset
    "
     55 "    b und
    "
     56 "    b swi
    "
     57 "    b pre_abt
    "
     58 "    b data_abt
    "
     59 "    .word 0x0
    "
     60 "    b irq
    "
     61 "    b fiq
    "
     62 
     63 "reset:
    "
     64 
     65 "und:
    "
     66     /*模式跳转进来分三步:
     67      *(1)将pc存到lr,pc->lr
     68     *(2)将cpsr存到spsr
     69     *(3)初始化sp
     70     *前两部系统硬件帮我们完成,第三步需要我们手动配置*/
     71 "    mov sp, #0x47000000
    "
     72 "    stmdb sp!, {r0-r12, lr}
    "
     73 
     74 "    ldr r3, show
    "
     75 "    ldr r0, =str_und
    "
     76 "    blx r3
    "
     77 
     78     /*回去的时候逆回去就ok*,^表示同时还回去*/
     79 "    mov sp, #0x47000000
    "
     80 "    ldmdb sp, {r0-r12, pc}^    
    "
     81 
     82 "swi:
    "
     83 
     84 "    mov sp, #0x47000000
    "
     85 "    stmdb sp!, {r0-r12, lr}
    "
     86 
     87 "    ldr r3, show
    "
     88 "    ldr r0, =str_swi
    "
     89 "    blx r3
    "
     90 
     91 "    mov sp, #0x47000000
    "
     92 "    ldmdb sp, {r0-r12, pc}^    
    "
     93 "pre_abt:
    "
     94 
     95 "data_abt:
    "
     96 
     97 "    mov sp, #0x47000000
    "
     98 "    sub lr, lr, #4
    "//这句需要好好理解
     99 "    stmdb sp!, {r0-r12, lr}
    "
    100 
    101 "    ldr r3, show
    "
    102 "    ldr r0, =str_data
    "
    103 "    blx r3
    "
    104 
    105 "    mov sp, #0x47000000
    "
    106 "    ldmdb sp, {r0-r12, pc}^    
    "
    107 
    108 "irq:
    "
    109 
    110 "fiq:
    "
    111 
    112 "show:
    "
    113 "    .word 0xc3e114d8
    "
    114 
    115 "str_data:
    "
    116 "    .asciz "this is data abort\n"
    "
    117 "    .align 2
    "
    118 
    119 "str_swi:
    "
    120 "    .asciz "this is swi \n"
    "
    121 "    .align 2
    "
    122 
    123 "str_und:
    "
    124 "    .asciz "this is undefined \n"
    "
    125 "    .align 2
    "
    126 
    127     ".global vector_start
    "
    128 "vector_start: 
    "
    129     ".word vector 
     "
    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 }

    下面是运行结果:

  • 相关阅读:
    C++ Primer中的一个sort算法源码
    字符串反转操作,网易的一道面试题
    字符编码之UCS2与Utf8
    我的Vim配置
    使用PreviousPage来获取前一页页面的元素
    ToString()用法大全
    MSSQL怎样使自动增加的id列数据归零
    确定要离开当前页面吗
    js 获取url参数
    C#判断程序是否以管理员身份运行,否则以管理员身份重新打开 转载
  • 原文地址:https://www.cnblogs.com/wenqiang/p/4775515.html
Copyright © 2020-2023  润新知