uboot代码重定位

(mips)

进入函数board_init_f后,首先做一系列初始化:
                timer_init    时钟初始化
                env_init    环境变量初始化(取得环境变量存放的地址)
                init_baudrate    串口速率
                serial_init        串口初始化
                console_init_f    配置控制台
                display_banner    显示u-boot启动信息,版本号等
                checkboard        执行board相关的操作。
                init_func_ram    初始化内存,配置ddr controller
这一系列工作完成后,串口和内存都已经可以用了。然后,就要把内存进行划分,
在内存的最后一部分,留出u-boot代码大小的空间,准备把u-boot代码从flash搬移到这里
然后,是堆的空间,malloc的内存就来自于这里。紧接着放两个全局数据结构bd_info global_data和环境变量boot_params。最后,是栈的空间。
准备进行relocate code。
relocate code的意思是这样的。通常u-boot的执行代码肯定是在flash上(当调试的时候也可以放在ram上)。当启动起来以后,要把它从flash上搬移到ram里运行。这个工作就叫做relocate code。
但是,问题在于,flash上的地址和ram上的地址是不同的。当我们把代码从flash上搬移到ram上以后,当执行函数跳转时,代码里的函数地址还是flash上的地址,所以一跳就跳回去了。
这怎么办呢?
在u-boot里面用的是PIC(position-independent code)的方式解决这个问题。
简单介绍一下其原理。当你用PIC方式时,在用gcc编译时需加上 -fpic的选项。编译器会为你的可执行代码建立一个GOT(global offset table)的段。一个地址在GOT表中有一项,里面存放地址的信息,而在使用这个地址时,只要根据这个地址的编号(也可以叫做偏移量offset)找到表中相应的项目,就可以取得那个地址了。
而如果位置发生变化,只要对GOT表中的地址进行修改就可以了。
我们可以通过反汇编,看一个简单的函数调用例子:
lw    t9,1088(gp)
jalr    t9
这里,gp存放的就是GOT表的起始地址,而1088就是要调用函数的offset,也就是说GOT表的那个位置存放着它的地址。lw    t9,1088(gp) 把函数地址放入t9, 然后调用就可以了。
知道了PIC的原理,解释u-boot relocate code的方法就简单了。
简单的说就把u-boot的执行代码直接从flash里copy到ram的相应区域。
然后,把GOT表中的地址都加上一个偏移量,这个偏移量就是flash里的地址与ram里的地址的差。
还有其他一些工作比如:设置新的栈指针,从flash代码里跳转到ram代码里 等等。
之后,就进入board.c的board_init_r函数,在这个函数里初始化 malloc,flash,pci 以及外设(比如,网口),最后进入命令行或者直接启动Linux kernel。
这样,u-boot的启动工作就完成了。

 

 

 

(mpc83xx)

.globl      relocate_code

relocate_code:             

       r4<= CFG_MONITOR_BASE=0xFE000000,源代码地址,text_base     

       r5<=GOT(__init_end) –r4 , GOT获得_init_end,源代码结束地址,定义在u-boot.lds,故差是u-boot代码长度

       r6<=CFG_CACHELINE_SIZE             /* Cache Line Size,每次搬运32bit*/

       //更新GOT pointer: New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE)+Destination Address

       r14<= r14+r10-r4

r0<=(r5+3)/4,每次搬运32bit,4个字节,r0为将代码copyram的次数

mtctr      r0  //将搬运次数,存放至计数器

r0=0,则不需搬运代码,否则需要进行代码搬运

       la     r8,-4(r4)  //r8<=r4-4

       la     r7,-4(r3)

1:     lwzu       r0,4(r8)

       stwu       r0,4(r7)//代码搬运

       bdnz       1b

  然后在进行第二次搬运,并比较,如果发现不同,则表示搬运出错,退出

      (注:当目的地址>源地址,则逆序搬运代码,而且不需要进行二次搬运和比较。不知道为什么这么做)

 //Flush the cache

       mr   r4,r3

5:     dcbst      0,r4 //有效地址EA=r4+0,EA所在的cache行与内存同步

       add  r4,r4,r6

       cmplw    r4,r5

       blt    5b

       sync                     /* Wait for all dcbst to complete on bus */

       mr   r4,r3

6:     icbi  0,r4   //有效地址EA=r4+0,EA所在的指令cache行无效

       add  r4,r4,r6

       cmplw    r4,r5

       blt    6b

7:     sync                     /* Wait for all icbi to complete on bus   */

       isync

 

/*此时并不返回,而是跳转到board的第二部分的初始化,即in_ramstart.S,此后代码在RAM中运行*/

       addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET //r10为目的地址

       mtlr r0

       blr

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值