boot.img基址 base的计算方法
如果您看这个帖子,没有耐心的话,我只能对你说,出现任何问题都是你自己的错,有点耐心继续 看吧,虽然在文章最后有点邪恶,大家原谅一下!我在工具包中给了一个参数,对于我的GT540肯定没有什么问题,但是对于其他手机我不敢保证,所以可能还 需您自己计算,或者使用版区前辈得到的数值!如果您做完之后刷回到手机之后会卡在开机界面,屏幕一闪一闪啊黑屏啊之类的症状层出不穷,普遍有两种可能。
一、boot.img是加过密的。各位手机出产的公司,在做ROM的时候,以他们独自的加密算法,对整个文件进行CRC验算,然后将验算值添加到 boot.img的最末尾。刷机的时候,手机的硬件BIOS就像一名尽职的士兵,对此进行验算,对不上口令的,那么对不起,请君离开,不离开我报警了~~ 呃,报不了警,那反正我不让你进门~~
二、boot.img还有一个重要的参数,基址 base,用于告诉手机从哪个地址开始,是准备给内存盘的入口,哪个地址是给kernel的入口。如果你对不上号,对不起,不能非法入室的。
如果是第一种,那只能望风而逃,罢手了。
各种查阅,终于发现在ROM的boardconfig.h中存在地址偏移的define。虽然本人手机的ROM中不存在这文件,但各android系统这个偏移是通用的,一般没吃错药不会去改。
偏移DEFINE如下:
- #define PHYSICAL_DRAM_BASE 0x00200000<!--IWMS_AD_BEGIN--> //基址,各不相同,我们的目的是为了获得这个基址,但由于没有ROM源代码,这貌似是不可能的。<!--IWMS_AD_END-->#define KERNEL_ADDR (PHYSICAL_DRAM_BASE + 0x00008000)#define RAMDISK_ADDR (PHYSICAL_DRAM_BASE + 0x01000000)#define TAGS_ADDR (PHYSICAL_DRAM_BASE + 0x00000100)#define NEWTAGS_ADDR (PHYSICAL_DRAM_BASE + 0x00004000)
复制代码
还记得WIKI中有这句话吧?For Nexus One : Add --base 0x20000000 to mkbootimg command-line. 翻译一下,如果是nexus one手机,那么需要在mkbootimg命令中加入 --base 0x20000000。。现在是不是很熟了?原来基址写在这里,mkbootimg会自动为你加入偏移量,并写入boot.img。。
好吧,我们现在需要知道,这些值是在哪个位置的。
为什么需要呢?在第上面,我们已经知道了偏移量了,那么如果我们再从官方ROM的boot.img中获取 kernel_addr,再用kernel_addr -偏移量0x00008000,不就可以得出基址了吗?
没辙,需要知道bootimg工具把它们写到哪了,只能查看mkbootimg的源代码(幸好bootimg作为一个典型的LINUX工具,是开源的。若换成WIN,哥就真悲情了)。
各种查找,找到bootimg.c文件,看吧。
header + padding + kernel + padding + ramdisk + padding + ...(padding是补全,还记得上面所说的,一个盒子装10张卡片,11张卡片需要几个盒子的事情吧?第二个盒子由于只放了一张卡片,所以需要9张空白卡片来填充位置,即padding)
4 * 2, magic,固定为"ANDROID!"
4 * 1, kernel长度,小端unsigned类型
4 * 1, kernel地址,应为base + 0x00008000
4 * 1, ramdisk长度,小端unsigned
4 * 1, ramdisk地址,应为base + 0x01000000
4 * 1, second stage长度,小端unsigned,为0
4 * 1, second stage地址,应为base + 0x00f00000
4 * 1, tags地址,应为base + 0x00000100
4 * 1, page大小,小端unsigned, 为2048或者4096
4 * 2, 未使用,固定为0x00
4 * 4, 板子名字,一般为空
4 * 128, 内核命令参数,一大串
4 * 8, id,不知道啥玩意,0x00
给亲爱的16进制帖张图吧,看图说话,下图是N600+官方2.1ROM的16进制图片,如下:
从图中我们可以知道:
41 4E 44 52 4F 49 44 21 就是Magic Number ,内容是固定的ANDROID!。一一对应
kernel_size就是0x00237470。注意,小端读法。是Byte内,顺读,整个类型中,逆读。故70 74 23 00 的确切数字是0x 00 23 74 70
kernel_addr即0x 03008000。这时有人就问了,那用这个减去上面获取的kernel偏移,0x00008000,那么base是不是0x030000000?好了,我知道了,我就用--base 0x03000000来打包。那么,恭喜你,在N600上,这样写依然是不能启动的,为什么,请继续看。
ramdisk_size是:B9 66 03 00 -->0x 00 03 66 B9。
ramdisk_addr即00 00 A0 03 -->0x 03 A0 00 00。减去偏移0x01000000,base=0x02a00000
second_stage size:00000000
second_stage addr:00 00 90 03-->0x 03 90 00 00.减去偏移0x00f00000,base=0x02a00000
tags_addr:00 01 a0 02-->0x 02a00100.减去偏移0x00000100,base=0x02a00000
page_size:00 80 -->0x0800.这是页长。记得我前面说过的页长一般都为1K(1024)的整数倍吧?此处页长是0x0800,转为十进制,则是2048
好吧,我们来看下base吧,嗯,kernel的base是0x03000000,ramdisk和second_stage及tags_addr的基址都一样啊,是...是0x02a000000。。我了个去~~4个base竟然有不一样的~是的,我当时就是这么骂的。
我就想,还好本人闲着无事算了4个base,如果有只算第1个,然后用0x03000000来打包的,基本就是悲剧的结果,可能还摸不着头脑,以为这个boot.img是CRC校验的,而非基址弄错。
好吧,以少数服从多数的原则,我们在打包的时候,把基址填为0x02a00000。然后把第一个地址kernel_addr,手动修正。
那么,正确的命令如下:
- bootimg ramdisk |gzip >ramdisk-new.gzmkbootimg --kernel boot.img-kernel --ramdisk ramdisk-new.gz --base 0x02a00000 -o boot.img
复制代码
然后用ghex2打开boot.img,忽略前面的4*2Byte,41 4E 44 52 4F 49 44 21,这是magic number,固定不变的。
再跳过4*1Byte,在我这是70 74 23 00。这是kernel_size,程序生成,不需要手动改。
其后的4*1Byte才是kernel_addr,现在是00 80 A0 02,修改成 00 80 00 03。保存之。
好了,将它放到刷机包目录中,打开刷机工具,刷之。快乐的启动吧。