IMX6Solo启动流程-Linux 内核启动 三
2015-09-21 10:32
591 查看
写在前头
*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!*.目的:整理一下RIotBoard开发板的启动流程,对自己的所学做一个整理总结,本系列内核代码基于linux-3.0.35-imx。
*.备注:整个系列只是对我所学进行总结,记录我认为是关键的点,另我能力有限,难免出现疏漏错误,如果读者有发现请多指正,以免我误导他人!
解压时会不会出现覆盖
在RIotBoard板上,内核被Uboot加载到的地址为0x10800000,而内核被解压的地址也是0x10800000,所以根据上篇的分析,目前内存上面的分布为:我们可以看出,解压的时候会导致解压后的数据覆盖掉待解压的数据,所以解压之前我们先要处理一下,防止覆盖情况的发生。
接着上篇文章分析的代码位置往下看
[code]/* * Check to see if we will overwrite ourselves. * r4 = final kernel address * r9 = size of decompressed image * r10 = end of this image, including bss/stack/malloc space if non XIP * We basically want: * r4 - 16k page directory >= r10 -> OK * r4 + image length <= current position (pc) -> OK */ add r10, r10, #16384 cmp r4, r10 bhs wont_overwrite add r10, r4, r9 ARM( cmp r10, pc ) THUMB( mov lr, pc ) THUMB( cmp r10, lr ) bls wont_overwrite
寄存器r4保存的是内核解压地址,r9保存的是解压之后的内核长度,r10保存的是镜像结束地址(镜像的内存分布可以参考vmlinux.lds,在压缩内核数据后面还有bss段以及堆栈等数据)
我们要求:
r4 - 16k page directory >= r10 -> OK
即整个镜像数据在内核解压地址-16K的地方之下。
或者:
r4 + image length <= current position (pc) -> OK
解压之后不会覆盖当前PC位置,由于待解压的数据都在PC之上,所以更不会覆盖掉待解压的数据。
了解这两个要求,上面那段汇编就容易理解了,分别判断上面两个要求,如果满足就跳转到wont_overwrite,跳过重定位镜像,如果不满足就继续执行。此时我们是不满足的,所以需要移动镜像位置。
移动镜像
如果无法满足上述的任一条件,需要将镜像重新移动到高位去,避免解压内核时出现覆盖现象。[code]/* * Relocate ourselves past the end of the decompressed kernel. * r6 = _edata * r10 = end of the decompressed kernel * Because we always copy ahead, we need to do it from the end and go * backward in case the source and destination overlap. */ /* * Bump to the next 256-byte boundary with the size of * the relocation code added. This avoids overwriting * ourself when the offset is small. */ add r10, r10, #((reloc_code_end - restart + 256) & ~255) bic r10, r10, #255;255字节对齐 /* Get start of code we want to copy and align it down. */ adr r5, restart ;从restart开始拷贝 bic r5, r5, #31 ;32位对齐 sub r9, r6, r5 @ size to copy;拷贝restart到__edata间的这段代码 add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes;32位对齐 add r6, r9, r5 ;r6保存待拷贝数据的最顶端 add r9, r9, r10 ;r9保存目的区域的最顶端 ;拷贝数据 1: ldmdb r6!, {r0 - r3, r10 - r12, lr} cmp r6, r5 stmdb r9!, {r0 - r3, r10 - r12, lr} bhi 1b /* Preserve offset to relocated code. */ sub r6, r9, r6 ;计算原先restart和拷贝后的restart之间的偏移量 #ifndef CONFIG_ZBOOT_ROM /* cache_clean_flush may use the stack, so relocate it */ add sp, sp, r6 #endif bl cache_clean_flush ;r6保存的是原先restart和拷贝后的restart之间的偏移量,接下来是计算拷贝后的restart地址并且跳转到restart adr r0, BSYM(restart) add r0, r0, r6 mov pc, r0
拷贝后的内存分布为:
计算出拷贝数据长度与拷贝源、目的地址后,将镜像拷贝到原镜像的上面,然后计算出拷贝后的restart入口地址,并跳转到该处,重新执行加载LC0表,重新分配堆,计算待解压内核长度、判断是否重叠等操作,此时判断是不会重叠的,所以跳过移动镜像的操作,进行下面的指令。
总结
解压缩之后内核数据长度变大以及当前PC位置跟内核解压位置的关系,解压内核有可能会覆盖掉执行镜像,所以在解压之前先要判断一下是否出现覆盖现象。参考
暂无相关文章推荐
- Linux下的CGI和BOA使用期间遇到的问题汇总
- Dart SDK在Linux上的下载及配置
- linux sar 命令详解
- Linux解压
- 9月19日linux系统开机自检硬盘数据故障
- Linux系统函数execve说明(03)---execve函数本质分析
- Linux笔记
- ARM GCC浮点相关总结
- Linux 系统是否适合于您?
- Linux电源管理(10)_autosleep
- Linux电源管理(9)_wakelocks
- linux 学习之路(学linux必看)
- Linux电源管理(8)_Wakeup count功能
- Linux电源管理(7)_Wakeup events framework
- Linux系统函数execve说明(02)---实现两个程序之间的调用
- Linux学习记录(11)LVM的基本概念和操作
- Linux下的一些I/O统计工具
- linux ssh 使用深度解析(key登录详解)
- svn: E200033: database is locked解决办法
- Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码