do_bootm函数及其所调用的函数,根据头部的定位地址(mkimage –a的参数)
将zImage搬移到指定的内存处),根据头部的入口地址(mkimage –e的参数)
获得head.o在内存中的地址,设置r0、r1、r2跳到此处执行。
boot传入r0=0,r1=machine_ID,r2=taglist (r0为0, r1为machine type, r2位参数列表的物理地址)
在次过程中会开启Icache、Dcache,来加速开机过程
程序中有一段称为 LC0的表,其中根据链接脚本确定了got段的起始和结束地址,bss段的起始和结束地址,栈的地址(比链接脚本中的指定的stack大于4),解压的内核存放于物理内存的起始地址。
还有一个LC0标号记录了链接时的LC0标号地址,以及一个链接脚本中程序的链接起始地址_start
如何计算一个程序的在物理内存中运行的起始地址:
1、取运行是LC0的地址(PC加相对地址);设为r0
2、取链接程序的起始地址_start;设为r5
3、区链接是LC0标号的值;设为r1
4、r0-r1+r5即为程序在物理内存中的起始地址
注:一般将链接程序起始地址设为0,故_start=0,实际是unicore也是这么干的
根据r0-r1修正got表的内容(即got表的中每一项+(ro-r1)),同时建立bss段。
判定若将内核解压是否会覆盖掉自身:
1、r5=r0-r1+r5 zImage在物理内存中的起始地址
2、r2=sp+64K
3、r4=解压存放地址
4、r3=sp-r5
5、若r4>r2显然不会覆盖,执行解压
若r4+2r3显然不会覆盖,执行解压
否则挂掉。
在实际应用中出现了这样的问题:
为加速测试音频,没有启动android,而只是挂载了ramdisk,alsa所需的库名、配置文件名(通过objdump、hexdump、strings都可以获得),但是做出的uImage大概4.5M,而image为9M多,现在指定的内核搬移到了40808000,而解压到的地址是400080000,结果40008000+9M>40808000,因此head及misc被冲掉,所以内核不能正常解压,修正的方法是改正kernel/arch/unicore/boot/Makefile下的LOADADDR,使得zImage在内存的地址>40008000+9M,例如师兄修正的41808000
还有个问题,我们可以在将zImage制成uImage时将解压到的地址写入头部,这样boot可以将获取的信息放在合适的位置,感觉这样更好,但是实际上头部没有还有这个信息。