Arm linxu启动过程分析(二)

***** 解压缩内核 , 分三种情况,下面一一解释:

说明:这一段分析中所提到的 vmlinux 指的是基本内核映像 vmlinux

/* 检查当前地址间的相互关系, 防止解压缩过程中出现地址重叠或者说地址冲突

 *   r4 = final kernel address   // 最终解压后的内核首地址

 *   r5 = start of this image zImage 的运行时首地址,一般为 0x30008000, 当然也可以不同,

 *   r2 = end of malloc space (and therefore this image)

 * We basically want:

 *   r4 >= r2 -> OK

 *   r4 + image length <= r5 -> OK   

decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,

                int arch_id */

第一种情况:

       理论上讲,这种情况下 vmlinux 的起始地址大于 zImage 运行时所需的最大地址( r2 , 那么直接将 zImage 解压到 vmlinux 的目标地址也是没有问题的,但是实际上有点意外,看下面的分析。

              cmp r4, r2

              bhs  wont_overwrite   //r4 大于 r2 不会发生地址冲突

分析:依据链接脚本 arch/arm/boot/compressed/vmlinux.lds 分析

.data       : { *(.data) }

  _edata = .;

  . = ALIGN(4);

  __bss_start = .;

  .bss: { *(.bss) }

  _end = .;

  .stack (NOLOAD): { *(.stack) }

Sp 的装载地址在 zImage 映像上面的 bss 段之上,那么从上面的代码知道 r2=sp+0x10000,

那么我们得出结论:第一种情况不可能发生:因为 r4=0x30008000, 内存的起始地址为 0x30000000,zImage 的大小最小约 1MB, 0x100000 ,所以 r4 一定小于 r2

第二种情况:

       这种情况下 zImage 的起始地址大于 vmlinux 的目标起始地址加上 vmlinux 大小( 4M )的地址,所以将 zImage 直接解压到 vmlinux 的目标地址是没有问题的。

              add  r0, r4, #4096*1024 @ 4MB largest kernel size

              cmp r0, r5          

              bls   wont_overwrite     //r4+zImage size <=r5 不会发生地址冲突

 

 

分析如下:假如 r5>r4+0x400000, 其根本意思就是 u-boot zImage 重定位到 r4+0x400000 (我们这里就是 0x30008000+0x400000=0x30408000 的位置),这一方案是可行的。其内存分布图如下所示:


第三种情况:也是我们最常使用的方式,将作详细解释

       这种情况下vmlinux 的目标位置刚好和zImage 的当前位置重合,所以解决方案就是先将zImage 解压到zImage 的上面,再将其重定位或者说搬移到目标位置。当然这其中就有个问题,vmlinux 的搬移同样会覆盖掉正在运行的重定位及其后面的第一阶段启动代码,所以在搬移vmlinux 到目标位置之前我们需要先将重定位代码段(事实上包含了重定位代码和后面的内核启动第一阶段的代码)搬移到vmlinux 的上面,这样就避免了地址的冲突。

              mov r5, r2                    @ decompress after malloc space

              mov r0, r5           // zImage 解压到 r2 (就是 sp+0x10000 )起始的地址

              mov r3, r7                    //Archtecture ID-->r3

              bl     decompress_kernel 

              add  r0, r0, #127   

              bic   r0, r0, #127           @ align the kernel length

/* r0     = decompressed kernel length

 * r1-r3  = unused

 * r4     = kernel execution address

 * r5     = decompressed kernel start

 * r6     = processor ID

 * r7     = architecture ID

 * r8-r14 = unused    */

 // 将内核重定位代码段搬移到解压后的内核的上面

              add  r1, r5, r0        @ end of decompressed kernel

              adr   r2, reloc_start   //reloc_start 代码段的起始地址

              ldr   r3, LC1      //reloc_start 段代码的大小

              add  r3, r2, r3  

1:            ldmia       r2!, {r8 - r13}              @ copy relocation code

              stmia       r1!, {r8 - r13}

              ldmia       r2!, {r8 - r13}

              stmia       r1!, {r8 - r13}

              cmp r2, r3

              blo   1b

              bl     cache_clean_flush   // cache


              add  pc, r5, r0              @ call relocation code  // 跳转到新的reloc_start 代码位置执行解压后内核的重定位,   将解压后的内核搬移到r4=0x30008000 位置

/* * We're not in danger of overwriting ourselves.  Do this the simple way.

 * r4     = kernel execution address

 * r7     = architecture ID

  解压缩过程中不需要传递压缩映像的起始地址,这些时在编译链接时

  就已经由 arch/arm/boot/compressed/piggy.S 决定好了。 */

第一、二种情况下的解压代调用部分

wont_overwrite:     mov r0, r4    // 设置解压缩目的起始地址,也就是内核入口地址

// arm linux 中这一地址一般为 0x30008000

              mov r3, r7    //architecture ID 解压缩时需要该参数

              bl     decompress_kernel   // 调用解压缩 c 程序

              b     call_kernel 

第三种情况下后面这部分代码的位置已经不是 zImage 最初装载的位置了,而是在搬移重定位代码段时,被搬移到 vmlinux 上面了,否则就会出错,因为 vmlinux 搬移之后将会彻底覆盖 zImage 最初装载的位置。

       debug_reloc_end     //relocate 代码段紧接着就是 call_kernel

call_kernel:     bl     cache_clean_flush   // cache

              bl     cache_off  // cache

              mov r0, #0

              mov r1, r7                    @ restore architecture number

              mov pc, r4                    @ call kernel  跳转到内核启动第二阶段开始执行。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值