zoukankan      html  css  js  c++  java
  • S3C2440的七种模式之——未定义模式(去掉bl print1 bug解决)

    现在做第一个实验,模拟未定义模式。

    未定义模式,是cpu遇到自己不能识别的指令时候做出的异常处理。

    arm指令的机器码一定是按照某种规范要求的,不然你随意写一条指令,cpu不是都可以执行吗?在cpu没有定义该条指令含义的情况下,我们执行了这样未定义的指令,就会进入未定义异常。

    现在我们要模拟一个未定义异常,所以我们只要写出一个cpu无法识别的指令即可。

    在这之前,要明白一个道理,在内存中执行的机器码,只有0,1两个值,不同的指令被分解为不同的0,1信号的机器码。

    所以,我们在运行内存中存放一个32bit的值,这个值又恰恰是上图所不能表示的指令,那么这样,就可以测试未定义异常了。我们采用.word 关键字,.word expression就是在当前位置放一个word型的值,这个值就是expression 。

    .word 接收4字节的数据,放在当前地址。

    现在我们仔细观察上面的那个图,找到一个未定义的机器码,把这个值放在.word的地方,当cpu运行到.word 地址时,发现这个地址的0,1数据即机器码它不能识别,就发生未定义异常。

    所以我们可以使用 .word 0xf3000000来表示一条未定义指令,但大家用的比较多的是.word 0xbadc0de(很形象,表示坏代码)。

     现在更改star.S:

    .text
    .global _start
    
    _start:
        b reset  /* vector 0 : reset */
        ldr pc, und_addr /* vector 4 : und */
    
    und_addr:
        .word do_und
    
    do_und:
        /* 执行到这里之前:
         * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址
         * 2. SPSR_und保存有被中断模式的CPSR
         * 3. CPSR中的M4-M0被设置为11011, 进入到und模式
         * 4. 跳到0x4的地方执行程序 
         */
    
        /* sp_und未设置, 先设置它 */
        ldr sp, =0x34000000
    
        /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */
        /* lr是异常处理完后的返回地址, 也要保存 */
        stmdb sp!, {r0-r12, lr}  
        
        /* 保存现场 */
        /* 处理und异常 */
        mrs r0, cpsr
        ldr r1, =und_string
        bl printException
        
        /* 恢复现场 */
        ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */
        
    und_string:
        .string "undefined instruction exception"
    
    .align 4
    
    reset:
        /* 关闭看门狗 */
        ldr r0, =0x53000000
        ldr r1, =0
        str r1, [r0]
    
        /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
        /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
        ldr r0, =0x4C000000
        ldr r1, =0xFFFFFFFF
        str r1, [r0]
    
        /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
        ldr r0, =0x4C000014
        ldr r1, =0x5
        str r1, [r0]
    
        /* 设置CPU工作于异步模式 */
        mrc p15,0,r0,c1,c0,0
        orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
        mcr p15,0,r0,c1,c0,0
    
        /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
         *  m = MDIV+8 = 92+8=100
         *  p = PDIV+2 = 1+2 = 3
         *  s = SDIV = 1
         *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
         */
        ldr r0, =0x4C000004
        ldr r1, =(92<<12)|(1<<4)|(1<<0)
        str r1, [r0]
    
        /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
         * 然后CPU工作于新的频率FCLK
         */
        
        
    
        /* 设置内存: sp 栈 */
        /* 分辨是nor/nand启动
         * 写0到0地址, 再读出来
         * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
         * 否则就是nor启动
         */
        mov r1, #0
        ldr r0, [r1] /* 读出原来的值备份 */
        str r1, [r1] /* 0->[0] */ 
        ldr r2, [r1] /* r2=[0] */
        cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
        ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
        moveq sp, #4096  /* nand启动 */
        streq r0, [r1]   /* 恢复原来的值 */
    
        bl sdram_init
        //bl sdram_init2     /* 用到有初始值的数组, 不是位置无关码 */
    
        /* 重定位text, rodata, data段整个程序 */
        bl copy2sdram
    
    
    
    
        ldr pc, =sdram
    sdram:
        /* 清除BSS段 */
        bl clean_bss
        
        bl uart0_init
    
        bl print1
        /* 故意加入一条未定义指令 */
    und_code:
        .word 0xdeadc0de  /* 未定义指令 */
        bl print2
    
        //bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
        ldr pc, =main  /* 绝对跳转, 跳到SDRAM */
    
    halt:
        b halt
        

    cpu处理异常的时候,是有专门地址的,这里的未定义und异常,在地址0x4处,当发生未定义异常时,硬件让程序从地址0x4处执行。这里说明一下汇编中定义字符串:

    .string  “XXXX” 表示定义的字符串包含最后的.

    .ascii "XXXX"表示定义的字符串不包含最后的.

    .asciiz "XXXX"表示定义的字符串包含最后的,z代表zero。

    参考:(点击这里)

    .align 4 放在.string 后面是为了使后面的指令四字节对齐,因为字符串的字节数不一定是四字节对齐的。

    进入异常处理前需要保存现场,异常处理之后需要恢复现场。

    现在说明下面代码段:

        ldr pc, und_addr /* vector 4 : und */
    
    und_addr:
        .word do_und

    但是我在想,为什么韦老大说nand启动,怕访问超过4k空间,所以采取上面的操作方式,这样保证肯定无论是否超过4k,程序都可以正常运行。但是,我们的sdram已经重定位完毕了,那样sdram已经是可以访问的了,所以就算超过4k也不会有问题啊?(这个等到后面上文件系统的时候测试,我觉得这里是不存在老师说的那种情况的)。

    Question:

    去掉star.S中的 bl  print1

    发现不会进入未定义异常了?这是为什么?

     经过分析,是puts函数问题,只有调用了puts函数,才会进入未定义异常。原因。。。

    我们上面忽略了一点,就是cond所占用的四个字节条件,

    所以,未定义指令要忽略高4位cond条件码。

    在测试过程中,我能发现是puts函数的问题,可是,puts函数是我们重定义的库函数,这和stm32 printf映射串口有一点像,具体编译器在操作puts的时候做了什么不得而知,但是可以肯定的是puts让cpsr高四位变成了无条件执行,才触发了未定义异常。现在我们把未定义指令的高四位改成1110,后面加上arm不能识别的指令,就可以进入未定义异常模式了。

  • 相关阅读:
    Robberies
    Big Event in HDU
    UVA 562 Dividing coins
    Little Rooks
    Bone Collector
    Piggy-Bank
    0-1背包问题之——饭卡
    Monkey and Banana
    The Triangle
    Burning Midnight Oil
  • 原文地址:https://www.cnblogs.com/yangguang-it/p/8097828.html
Copyright © 2011-2022 走看看