LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 4709|回复: 2

ARM-Linux内核研究(arch/arm/boot/compressed/head.S)

[复制链接]
发表于 2005-4-17 19:57:07 | 显示全部楼层 |阅读模式
最近在移植2.6的arm-linux,硬件平台是师兄做的,用的是S3C2410,每天看代码可以学到不少东西,于是顺手都记录下来了,希望与大家一起交流,如果有什么错误帮忙指正啊:)
今天在实验室捣鼓了半天,kernel还是没能起来,收获是:排除了解压缩出现错误的可能,估计很有可能是MMU配置错误导致kernel不能load,以下是我的一些流水帐

在汇编文件中程序的开始段一般用 .section ".start" 或 .type stext标识。这个head.S文件主要产生对vmlinuz解压缩的代码,所以这个文件在链接的时候排在真正kernel的前面,可以用下图来表示:
上图表示了head.S和其他代码在逻辑上的关系,其在vmlinuz中的实际偏移位置可以参考compressed目录下的vmlinux.lds.in文件,该文件定义了各个段在vmlinuz中的偏移位置:
Vmlinux.lds.in文件:
SECTIONS
{
  . = TEXT_START;
  _text = .;


  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.fixup)
    *(.gnu.warning)
    *(.rodata)
    *(.rodata.*)
    *(.glue_7)
    *(.glue_7t)
    *(.piggydata)
    . = ALIGN(4);
  }

  _etext = .;

  _got_start = .;
  .got                  : { *(.got) }
  _got_end = .;
  .got.plt              : { *(.got.plt) }
  .data                 : { *(.data) }
  _edata = .;

  . = BSS_START;
  __bss_start = .;
  .bss                  : { *(.bss) }
  _end = .;

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

  .stab 0               : { *(.stab) }
  .stabstr 0            : { *(.stabstr) }
  .stab.excl 0          : { *(.stab.excl) }
  .stab.exclstr 0       : { *(.stab.exclstr) }
  .stab.index 0         : { *(.stab.index) }
  .stab.indexstr 0      : { *(.stab.indexstr) }
  .comment 0            : { *(.comment) }
  zreladdr = 0x30008000;
}
根据vmlinux.lds.in可以画出准确的vmlinuz结构图,在图中的piggydata就是经过压缩的kernel文件。
Head.S的工作就是把piggydata解压缩后放到合适的内存地址并跳转到kernel的第一条地址。下面对这个解压缩的过程进行分析:

文件的第一个字是 0x016f2818,就是所谓的Magic Number,由Bootloader判断是否vmlinuz文件。之后完成几项设置以及保存数据的任务:
        1)architecture ID保存在r7中
        2)关中断
        3)从LC0中用预定义的数据初始化寄存器r1~r6, ip, sp:
                         .text
                           adr     r0, LC0
                           ldmia   r0, {r1, r2, r3, r4, r5, r6, ip, sp}
                           subs    r0, r0, r1        @ calculate the delta offset
                        …………………..
                        …………………..
                        .type   LC0, #object
                        LC0:     .word   LC0                     @ r1
                                .word   __bss_start             @ r2
                                .word   _end                    @ r3
                                .word   zreladdr                @ r4
                                .word   _start                  @ r5
                                .word   _got_start              @ r6
                                .word   _got_end                @ ip
                                .word   user_stack+4096         @ sp
                        在这段代码中第一条指令把LC0的物理地址加载到r0寄存器,然后用多寄存器加载指令从r0指向的地址取出其余的寄存器值。第三条指令计算出物理地址和编译器链接地址之间的差异delta,这个差值可以用来修正其他段(例如GOT 和 BSS),用于链接地址和物理地址的对齐。
                        zreladdr 根据注释是virt_to_phys(TEXTADDR),一般来说zreladdr = 0x30008000
       
        4)在GOT表中的表项都是链接地址,在实际执行程序的时候必须是物理地址,所以用delta值对链接地址进行修改。
        5)BSS段清零
        6)为解压缩程序分配空间:
                      mov     r1, sp                  @ malloc space above stack
                          add     r2, sp, #0x10000        @ 64k max
                然后根据zreladdr的要求判断解压缩后的kernel image会不会覆盖当前的执行环境(从TEXT的头部到为解压缩程序分配的64k地址空间的尾部。判断的依据是zreladdr是否大于64k地址空间的尾部 或者 zreladdr+4M(估计内核大小不会超过4M)的地址是否小于TEXT的头部地址。一般情况会重叠的。
        7)设定调用decompress_kernel的参数:一般参数从r0开始往高处扩展,最后的返回值存放在r0中。decompress_kernel的四个参数为:
                output_start
                        <---
                                user_stack+16K
                free_mem_ptr_p
                        <---
                                user_stack栈顶
                free_mem_ptr_end_p
                        <---
                                user_stack+16k-1
                int arch_id
                        <---
                                r7
        8)解压完成后kernel image的初始地址在user_stack+16k,kernel image的长度放在r0里面,然后对r0的值进行对齐操作。
        9)对head.S中处于reloc_start和reloc_end之间的代码进行重定位操作,把这些代码搬到kernel image的末尾,在搬移工作结束后跳转到reloc_start开始执行
        10)从reloc_start开始的代码把kernel image搬到zreladdr,即最后开始执行kernel的地址。搬完后跳转到kernel的第一条指令并开始执行。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2007-7-24 16:42:14 | 显示全部楼层
不错,挺有帮助的。我有一个疑问,像__armv4_mpu_cache_off这段代码也属于reloc_start与reloc_end之间吗?  这段代码被reloc_start与reloc_end的代码调用的。
回复 支持 反对

使用道具 举报

发表于 2010-3-11 09:57:10 | 显示全部楼层
硬件平台是师兄做的...可以问一下,是跟原来的开发板不一样嘛?若不一样,您是怎做修改的嘛?麻烦教我一下,我的板子是 s3c2443 LAYt出来的板子,现在卡在解压缩错误...
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表