微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式 arm平台kernel启动第一阶段汇编head.s分析

嵌入式 arm平台kernel启动第一阶段汇编head.s分析

时间:11-09 来源:互联网 点击:

解压缩内核程序所使用,也是传递给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解压缩阶段已经执行完。

第二阶段的在另外一篇中分析。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top