免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1353 | 回复: 0
打印 上一主题 下一主题

1.2 uboot分析之start.S详细分析(2) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-14 19:24 |只看该作者 |倒序浏览

4. 地址重映射以及BSS段初始化,拷贝u-boot到RAM中,拷贝中断向量到RAM首地址
remap:
         mov  r0,    pc
         add    r0,     r0,     #0x20000000
         add    r0,     r0,     #0x08
         mov  pc,     r0                                  //到这条结束,其实就是跳到下一条去执行了

         mov  r0,     r0                         //这四个很关键,用来填充流水线
         mov  r0,     r0
         mov  r0,     r0
         mov  r0,     r0
/*关于上面这段代码,我考虑了很久,我是这么认为的:系统启动时,硬件选择从norflash启动,这时的0x2000 0000就是0x0,pc的值都是0x0空间的,下面马上要进行地址重映射了,重映射完了后0x3000 0000就是0x0,而重映射完了之后仍然有代码在norflash中执行,这样就必须人为地将PC指针指向0x2000 0000这个地址段,而不是继续在0x0这个空间执行代码,而0x3000 0000和0x0已经绑定了,在这个地址段里暂时还没有可以执行的代码,因为代码还没有搬运过去。
Shixq说:
在BootLoadr里实现Remap是一个技巧。
  首先假设Remap操作前不对PC进行处理,我们来看一下有什么问题。系统上电后,根据外部跳线,将NorFlash映射为零地址(此时NorFlash拥有两个地址:0x00000000和0x20000000),内核从零地址开始取指令,即开始执行BootLoader里的代码。
  在BootLoader里有一个重要的步骤,就是地址重映射,即将SDRAM(0x30000000)映射到零地址,为将来建立中断向量表做准备。如果不对PC处理,那么一旦执行了地址重映射,零地址开始的一段地址将落在SDRAM上,而不再落在NorFlash上,由于SDRAM开始的一段地址还没有任何内容,这样将导致系统崩溃!
  我们希望执行了Remap操作后,CPU能够继续从NorFlash取指,即继续执行BootLoader里的指令。这样在执行Remap前就必须对PC进行处理。由于Remap后,NorFlash只有0x20000000开始的地址,因此,需要将PC值加上0x20000000。假设执行Remap前PC是0x88,同时这个地址也是0x20000088,我们对PC加0x20000000不会影响系统的运行,而且可以保证Remap后,CPU可以继续从NorFlash取指。
  ldr pc,=0x,就是做了上述处理。至于这个值是多少,我们可以看到在这一条指令下面是mov r0,r0,相当于NOP空指令。只要让PC落在其中任意一*/
    ldr     r4,     =0x11000020               //对这个地址即寄存器写0xb完成地址重映射,这时0x30000000=0x0
     ldr    r5,     =0xb
         str     r5,     [ r4 ]

/*
         init BSS section bss段清零
*/
         ldr r0, = 0
         ldr r1, _bss_start                    //BSS段起始地址
         ldr r2, _bss_end                     //BSS段结束地址
bss_init:
         str r0, [r1]
         add r1,r1,#4
         cmp r1,r2
         blt bss_init

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:                                  /* relocate U-Boot to RAM   拷贝u-boot到RAM中   */
         adr    r0, _start              /* r0 根据现在的PC值计算出的_start地址赋给r0 */
         ldr     r1, _TEXT_BASE                 /* test if we run from flash or RAM 判断是从flash还是从RAM 启动*/
         cmp     r0, r1                  /* don't reloc during debug 在调试的时候不需要拷贝*/
         beq    vector_copy                                //调试的时候全部自动加载到指定的地址了

         ldr     r2, _armboot_start
         ldr     r3, _bss_start
         sub    r2, r3, r2              /* r2             */
         add    r2, r0, r2              /* r2          */

copy_loop:
         ldmia r0!, {r3-r10}               /* copy from source address [r0]    */
         stmia r1!, {r3-r10}               /* copy to   target address [r1]    */
         cmp   r0, r2                   /* until source end addreee [r2]    */
         ble     copy_loop

/*
         now copy to sram the interrupt vector
*/
vector_copy:
         ldr     r0, _TEXT_BASE
         add    r2, r0, #128                                     //拷贝128个字节到0x3000 0000,里面存放着中断向量
         ldr     r1, =0x30000000 /*modified by shixq from 0x0c000000 to 0x30000000*/
/*      add    r1, r1, #0x08 *//*deleted by shixq*/
vector_copy_loop:
         ldmia r0!, {r3-r10}
         stmia r1!, {r3-r10}
         cmp   r0, r2
         ble     vector_copy_loop
#endif         /* CONFIG_SKIP_RELOCATE_UBOOT */

6.使能IRQ中断,进入C代码部分
         /*enable the irq*/
         mrs   R4, cpsr
     bic     R4, R4, #0x80
    msr   cpsr, R4     

         ldr     pc, _start_armboot        
/*这条语句不但跳转到C语言处开始执行,而且是从NORFLASH空间跳转到了SDRAM空间*/
/*该指令是取得标号(_start_armboot)绝对地址并且赋值给pc,而_start_armboot中存储的又是start_armboot的链接时候的绝对地址,它们都是0x3070 0000开始的空间的地址。所以可以利用它实现Flash到RAM的跳转。*/
_start_armboot:   .word  start_armboot

ldr与adr的区别
ldr     r0, _start
        adr     r0, _start
        ldr     r0, =_start
        nop
        mov     pc, lr
_start:
        nop
        
编译的时候设置 RO 0x0c008000
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
0c008000 :
c008000:       e59f000c        ldr     r0, [pc, #12]   ; c008014
c008004:       e28f0008        add     r0, pc, #8      ; 0x8
c008008:       e59f0008        ldr     r0, [pc, #8]    ; c008018
c00800c:       e1a00000        nop                     (mov r0,r0)
c008010:       e1a0f00e        mov     pc, lr

0c008014 :
c008014:       e1a00000        nop                     (mov r0,r0)
c008018:       0c008014        stceq   0, cr8, [r0], -#80

分析:
adr     r0, _start
取得 _start 的地址到 r0,但是请看反编译的结果,它是与位置无关的。其实取得的是相对于当时pc的位置。例如这段代码在 0x0c008000 运行,那么 adr r0, _start 得到 r0 = 0x0c008014;如果在地址 0 运行,就是 0x00000014 了。
ldr     r0, =_start
这个取得标号 _start 的绝对地址。这个绝对地址是在 link 的时候确定的。看上去这只是一个指令,但是它要占用 2 个 32bit 的空间,一条是指令,另一条是 _start 的数据(因为在编译的时候不能确定 _start 的值,而且也不能用 mov 指令来给 r0 赋一个 32bit 的常量,所以需要多出一个空间存放 _start 的真正数据,在这里就是 0x0c008014)。
因此可以看出,这个是绝对的寻址,不管这段代码在什么地方运行,它的结果都是 r0 = 0x0c008014



完毕!!!



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/107770/showart_2121211.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP