|
最近在移植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
|