arm linux 启动代码分析(三)

本文详细介绍了如何在有限空间下解压内核,并确保解压后的内核不会覆盖现有程序,同时通过代码搬运将其安全地放置到指定地址。包括检查空间、解压缩、内存对齐、重定位代码等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面是接着第二节往下的:

@ 对下面这些地址的理解其实还是很麻烦,但有篇文档写得很清楚《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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值