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
@ 对下面这些地址的理解其实还是很麻烦,但有篇文档写得很清楚《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
相关文章推荐
- arm linux 启动代码分析(二)
- Linux应用程序在内存地址布局
- arm linux 启动代码分析(一)
- linux中没有dos2UNIX或者UNIX2dos命令怎么解决办法
- Linux vsftpd移植笔记
- SELinux 的开启和关闭
- SELinux 的开启和关闭
- SELinux 的开启和关闭
- SELinux 的开启和关闭
- 树莓派上使用花生壳实现外网访问
- Linux 共享库
- linux 静态库、共享库
- Linux下挂载,文件传递,操作规范,文件夹显示大小,网页访问,vim退格,端口查看,查看路由信息等
- CentOS6.5 安装配置drbd
- linux初学(二十)之linux软件管理基础之RPM软件包管理
- [Linux内存]页缓存和块缓存
- Linux下安装软件遇见的问题汇总
- linux解决xhost: unable to open display ""
- [C] zintrin.h : 智能引入intrinsic函数。支持VC、GCC,兼容Windows、Linux、Mac OS X
- linux 问题总结