IMX6Solo启动流程-Linux 内核启动 三

释放双眼,带上耳机,听听看~!

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!
*.目的:整理一下RIotBoard开发板的启动流程,对自己的所学做一个整理总结,本系列内核代码基于linux-3.0.35-imx。
*.备注:整个系列只是对我所学进行总结,记录我认为是关键的点,另我能力有限,难免出现疏漏错误,如果读者有发现请多指正,以免我误导他人!


解压时会不会出现覆盖

在RIotBoard板上,内核被Uboot加载到的地址为0x10800000,而内核被解压的地址也是0x10800000,所以根据上篇的分析,目前内存上面的分布为:
我们可以看出,解压的时候会导致解压后的数据覆盖掉待解压的数据,所以解压之前我们先要处理一下,防止覆盖情况的发生。
接着上篇文章分析的代码位置往下看


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1/*
2 * Check to see if we will overwrite ourselves.
3 *   r4  = final kernel address
4 *   r9  = size of decompressed image
5 *   r10 = end of this image, including  bss/stack/malloc space if non XIP
6 * We basically want:
7 *   r4 - 16k page directory >= r10 -> OK
8 *   r4 + image length <= current position (pc) -> OK
9 */
10        add r10, r10, #16384
11        cmp r4, r10
12        bhs wont_overwrite
13        add r10, r4, r9
14   ARM(     cmp r10, pc     )
15 THUMB(     mov lr, pc      )
16 THUMB(     cmp r10, lr     )
17        bls wont_overwrite
18
19

寄存器r4保存的是内核解压地址,r9保存的是解压之后的内核长度,r10保存的是镜像结束地址(镜像的内存分布可以参考vmlinux.lds,在压缩内核数据后面还有bss段以及堆栈等数据)
我们要求:

r4 – 16k page directory >= r10 -> OK

即整个镜像数据在内核解压地址-16K的地方之下。
或者:

r4 + image length <= current position (pc) -> OK

解压之后不会覆盖当前PC位置,由于待解压的数据都在PC之上,所以更不会覆盖掉待解压的数据。
了解这两个要求,上面那段汇编就容易理解了,分别判断上面两个要求,如果满足就跳转到wont_overwrite,跳过重定位镜像,如果不满足就继续执行。此时我们是不满足的,所以需要移动镜像位置。


移动镜像

如果无法满足上述的任一条件,需要将镜像重新移动到高位去,避免解压内核时出现覆盖现象。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1/*
2 * Relocate ourselves past the end of the decompressed kernel.
3 *   r6  = _edata
4 *   r10 = end of the decompressed kernel
5 * Because we always copy ahead, we need to do it from the end and go
6 * backward in case the source and destination overlap.
7 */
8        /*
9         * Bump to the next 256-byte boundary with the size of
10         * the relocation code added. This avoids overwriting
11         * ourself when the offset is small.
12         */
13        add r10, r10, #((reloc_code_end - restart + 256) &amp; ~255)
14        bic r10, r10, #255;255字节对齐
15
16        /* Get start of code we want to copy and align it down. */
17        adr r5, restart      ;从restart开始拷贝
18        bic r5, r5, #31      ;32位对齐
19
20        sub r9, r6, r5      @ size to copy;拷贝restart到__edata间的这段代码
21        add r9, r9, #31     @ rounded up to a multiple
22        bic r9, r9, #31     @ ... of 32 bytes;32位对齐
23        add r6, r9, r5      ;r6保存待拷贝数据的最顶端
24        add r9, r9, r10     ;r9保存目的区域的最顶端
25
26;拷贝数据
271:      ldmdb   r6!, {r0 - r3, r10 - r12, lr}
28        cmp r6, r5
29        stmdb   r9!, {r0 - r3, r10 - r12, lr}
30        bhi 1b
31
32        /* Preserve offset to relocated code. */
33        sub r6, r9, r6      ;计算原先restart和拷贝后的restart之间的偏移量
34
35#ifndef CONFIG_ZBOOT_ROM
36        /* cache_clean_flush may use the stack, so relocate it */
37        add sp, sp, r6
38#endif
39
40        bl  cache_clean_flush
41;r6保存的是原先restart和拷贝后的restart之间的偏移量,接下来是计算拷贝后的restart地址并且跳转到restart
42        adr r0, BSYM(restart)
43        add r0, r0, r6
44        mov pc, r0
45

拷贝后的内存分布为:
计算出拷贝数据长度与拷贝源、目的地址后,将镜像拷贝到原镜像的上面,然后计算出拷贝后的restart入口地址,并跳转到该处,重新执行加载LC0表,重新分配堆,计算待解压内核长度、判断是否重叠等操作,此时判断是不会重叠的,所以跳过移动镜像的操作,进行下面的指令。


总结

解压缩之后内核数据长度变大以及当前PC位置跟内核解压位置的关系,解压内核有可能会覆盖掉执行镜像,所以在解压之前先要判断一下是否出现覆盖现象。

参考

暂无

给TA打赏
共{{data.count}}人
人已打赏
安全运维

WordPress网站专用docker容器环境带Waf

2020-7-18 20:04:44

安全运维

运维安全-Gitlab管理员权限安全思考

2021-9-19 9:16:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索