您的位置:首页 > 运维架构 > Linux

arm linux 启动代码分析(三)

2015-08-01 20:33 633 查看
下面是接着第二节往下的:

@ 对下面这些地址的理解其实还是很麻烦,但有篇文档写得很清楚《About TEXTADDR, ZTEXTADDR,

@ PAGE_OFFSET etc...》。下面程序的意义就是保证解压地址和当前程序的地址不重叠。上面分配了64KB的空间来做解压时的数据缓存。

/*

检查是否会覆盖内核映像本身

* r4 = 最后我们的Image内核执行的最终实地址

* r5 = 本映像zImage的起始地址

* r2 = 分配空间的结束地址(并且处于本映像的前面)

* 基本要求:r4 >= r2 或者 r4 + 映像长度 <= r5

在实际的调试中我们的SEP4020的各个寄存器:

r0 = 0;

r1 = 0x30180358;

r2 = 0x30190358;

r3 = 0x30004000;

r4 = 0x30008000;

r5 = 0x30008000;

r6 = 0x41807202;

r7 = 0x000000c2

*/

cmp r4,
r2

bhs wont_overwrite
/*如果大于或等于的话*/

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

cmp
r0,
r5

bls
wont_overwrite
/*如果r4
+ 映像长度 <= r5 的话*/

@ 如果空间不够了,只好解压到缓冲区地址后面。调用decompress_kernel进行解压缩,这段代码是用c实现的,和架构无关。

mov r5,
r2 @
decompress after malloc space

mov r0,
r5 /*解压程序从分配空间后面存放
*/

mov r3,
r7

bl decompress_kernel

/******************************进入decompress_kernel***************************************************/

@ decompress_kernel共有4个参数,解压的内核地址、缓存区首地址、缓存区尾地址、和芯片ID,返回解压缩代码的长度。注意r5会在其中改变的

ulg

decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,

int
arch_id)

{

output_data=
(uch *)output_start;/*
Points to kernel start */

free_mem_ptr=
free_mem_ptr_p;

free_mem_ptr_end=
free_mem_ptr_end_p;

__machine_arch_type=
arch_id;

arch_decomp_setup();
/*在sep4020中什么都没作*/

makecrc();/*镜像校验*/

putstr("Uncompressing
Linux...");

gunzip();/*通过free_mem_ptr来解压缩*/

putstr("
done, booting the kernel.\n");

return
output_ptr;/*返回镜像的大小*/

}

/******************************从decompress_kernel函数返回*************************************************/

add r0,
r0, #127

bic r0,
r0, #127 @
align the kernel length对齐内核长度

/*

* r0 = 解压后内核长度 0x002ec480

* r1-r3 = 未使用

* r4 = 真正内核执行地址 0x30008000

* r5 = 临时解压内核Image的起始地址 0x3019149c

* r6 = 处理器ID 0x41807202

* r7 = 体系结构ID 0x000000c2

* r8 = 参数列表0x30000100

* r9-r14 = 未使用

*/

@ 完成了解压缩之后,由于空间不够,内核也没有解压到正确的地址,最后必须通过代码搬移来搬到指定的地址0x30008000。搬运过程中有

@ 可能会覆盖掉现在运行的这段代码,所以必须将有可能会执行到的代码搬运到安全的地方,

@ 这里帮运到的地址是解压缩了的代码的后面r5+r0=0x3047d91c的位置。

add r1,
r5, r0 @
end of decompressed kernel

adr r2,
reloc_start

ldr r3,
LC1

@ LC1:.wordreloc_end
- reloc_start 表示reloc_start段代码的大小

add r3,
r2, r3

1:

ldmia r2!,
{r9 - r14} @
copy relocation code

stmia r1!,
{r9 - r14}

ldmia r2!,
{r9 - r14}

stmia r1!,
{r9 - r14}

cmp r2,
r3

blo 1b

bl cache_clean_flush

add pc,
r5, r0 @ call relocation code

@ 在此处会调用重定位代码reloc_start来将Image 的代码从缓冲区r5帮运到最终的目的地r4:0x30008000处

/*

* All code following this line is relocatable. It is relocated by

* the above code to the end of the decompressed kernel image and

* executed there. During this time, we have no stacks.

*

* r0 = decompressed kernel length 0x002ec480

* r1-r3 = unused

* r4 = kernel execution address0x30008000

* r5 = decompressed kernel start0x3019149c

* r6 = processor ID0x41807202

* r7 = architecture ID0x000000c2

* r8 = atags pointer0x30000100

* r9-r14 = corrupted

*/

.align 5

reloc_start: add r9, r5, r0

sub
r9, r9, #128 @ do not copy the stack

debug_reloc_start

mov
r1, r4

1:

.rept4

ldmia r5!,
{r0, r2, r3, r10 - r14} @
relocate kernel

stmia r1!,
{r0, r2, r3, r10 - r14} /*重新帮运内核Image的过程*/

.endr

cmp r5,
r9

blo 1b

debug_reloc_end

call_kernel: bl cache_clean_flush

bl cache_off

mov r0,
#0 @
must be zero

mov r1,
r7 @
restore architecture number

mov r2,
r8 @
restore atags pointer

@ 这个地方就是最终我们从zImage跳转到Image的伟大一跳了,跳之前准备好r0,r1,r2

mov pc,
r4 @
call kernel
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: