嵌入式 arm平台kernel启动第一阶段汇编head.s分析
解压缩内核程序所使用,也是传递给decompress_kernel的第二和第三的参数
movr1,sp@mallocspaceabovestack
addr2,sp,#0x10000@64kmax解压缩的缓冲区
@下面程序的意义就是保证解压地址和当前程序的地址不重叠。上面分配了64KB的空间来做解压时的数据缓存。
/*
*检查是否会覆盖内核映像本身
*r4=最终解压后的内核首地址
*r5=zImage的运行时首地址,一般为0x30008000
*r2=endofmallocspace分配空间的结束地址(并且处于本映像的前面)
*基本要求:r4>=r2或者r4+映像长度<=r5
(1)vmlinux的起始地址大于zImage运行时所需的最大地址(r2),那么直接将zImage解压到vmlinux的目标地址
cmpr4,r2
bhswont_overwrite/*如果r4大于或等于r2的话*/
(2)zImage的起始地址大于vmlinux的目标起始地址加上vmlinux大小(4M)的地址,所以将zImage直接解压到vmlinux的目标地址
addr0,r4,#4096*1024@4MBlargestkernelsize
cmpr0,r5
blswont_overwrite/*如果r4+映像长度<=r5的话*/
@前两种方案通常都不成立,不会跳转到wont_overwrite标号处,会继续走如下分支,其解压后的内存分配示意图如下:
movr5,r2@decompressaftermallocspace
movr0,r5/*解压程序从分配空间后面存放*/
movr3,r7
bldecompress_kernel
/进入decompress_kernel*/
@decompress_kernel共有4个参数,解压的内核地址、缓存区首地址、缓存区尾地址、和芯片ID,返回解压缩代码的长度。
decompress_kernel(ulgoutput_start,ulgfree_mem_ptr_p,ulgfree_mem_ptr_end_p,
intarch_id)
{
output_data=(uch*)output_start;/*Pointstokernelstart*/
free_mem_ptr=free_mem_ptr_p;/*保存缓存区首地址*/
free_mem_ptr_end=free_mem_ptr_end_p;/*保存缓冲区结束地址*/
__machine_arch_type=arch_id;
arch_decomp_setup();
makecrc();/*镜像校验*/
putstr("UncompressingLinux...");
gunzip();/*通过free_mem_ptr来解压缩*/
putstr("done,bootingthekernel.\n");
returnoutput_ptr;/*返回镜像的大小*/
}
/从decompress_kernel函数返回*/
addr0,r0,#127+128
bicr0,r0,#127@alignthekernellength对齐内核长度
/*
*r0=解压后内核长度
*r1-r3=未使用
*r4=真正内核执行地址0x30008000
*r5=临时解压内核Image的起始地址
*r6=处理器ID
*r7=体系结构ID
*r8=参数列表0x30000100
*r9-r14=未使用
*/
@完成了解压缩之后,由于内核没有解压到正确的地址,最后必须通过代码搬移来搬到指定的地址0x30008000。搬运过程中有
@可能会覆盖掉现在运行的重定位代码,所以必须将这段代码搬运到安全的地方,
@这里搬运到的地址是解压缩了的代码的后面r5+r0的位置。
addr1,r5,r0@endofdecompressedkernel解压内核的结束地址
adrr2,reloc_start
ldrr3,LC1@LC1:.wordreloc_end-reloc_start表示reloc_start段代码的大小
addr3,r2,r3
1:ldmiar2!,{r9-r14}@copyrelocationcode
stmiar1!,{r9-r14}
ldmiar2!,{r9-r14}
stmiar1!,{r9-r14}
cmpr2,r3
blo1b
blcache_clean_flush@清cache
ARM(addpc,r5,r0)@callrelocationcode跳转到重定位代码开始执行
@在此处会调用重定位代码reloc_start来将Image的代码从缓冲区r5帮运到最终的目的地r4:0x30008000处
reloc_start:addr9,r5,r0@r9中存放的是临时解压内核的末尾地址
subr9,r9,#128@不拷贝堆栈
movr1,r4@r1中存放的是目的地址0x30008000
1:
.rept4
ldmiar5!,{r0,r2,r3,r10-r14}@relocatekernel
stmiar1!,{r0,r2,r3,r10-r14}/*搬运内核Image的过程*/
.endr
cmpr5,r9
blo1b
movsp,r1/*留出堆栈的位置*/
addsp,sp,#128@relocatethestack
call_kernel:blcache_clean_flush@清除cache
blcache_off@关闭cache
movr0,#0@mustbezero
movr1,r7@restorearchitecturenumber
movr2,r8@restoreatagspointer
@这里就是最终我们从zImage跳转到Image的伟大一跳了,跳之前准备好r0,r1,r2
movpc,r4@callkernel
到此kernel的第一阶段zImage解压缩阶段已经执行完。
第二阶段的在另外一篇中分析。
嵌入式arm平台kernel启 相关文章:
- 嵌入式 arm平台kernel启动第二阶段分析(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)