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

  • 相关阅读:
    C#实现按键精灵的'找图' '找色' '找字'的功能
    Amazon SES SPF和DKIM设置教程
    你应该知道的最好Webmail邮件客户端,
    8款世界级Webmail工具推荐
    AWS邮件通知服务:实时监控邮件状态
    XenServer:使用XenCenter开设VPS(多图完整版)
    Thinkpad机器BIOS下清除安全芯片和指纹数据的方法
    在ASP.NET Web Application中通过SOAP协议调用Bing搜索服务
    怎么申请 bing api key
    linux挂载硬盘失败,报错!
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4505489.html
Copyright © 2020-2023  润新知