XX教你玩 MiniPC (四) Mk908 bootloader行为分析

经历了沉寂郁闷的一天,终于一定程度上搞清楚了flashboot的启动行为。以下就说下自己做过的一些尝试吧,希望大家能从中吸取经验教训,少走弯路。

说到要分析一个软件的行为,我们通常都会从两个方面去考虑,这有点类似于做测试,白盒测试和黑盒测试。

要进行白盒测试,对应的就需要反编译flashboot,从它的代码中看到启动的过程。从上一篇的总结中,可以知道:flashboot在启动时经过了两次代码拷贝过程,在拷贝完毕后,转到地址0,继续执行。第一次拷贝时,把代码从0x60000310的位置拷贝到了0地址,大小为0x530;第二次拷贝时,把代码从0x60000840的位置拷贝到0x60080000的位置,大小为(0x6009b65c - 0x60080000)。通过分析,第一次拷贝的代码中包含了中断向量表,以及最基本的MMU,栈指针(SP)的初始化等操作,然后转到后面的0x60080000位置的代码中运行。

我们的反汇编操作也就是围绕着这两部分代码来进行的。

第一步,取出代码部分。第一次拷贝的位置位于0x60000310 ~ 0x60000840之间,它的目的地址是0。这里声明一下,linux下的指令一些是需要root账户权限的,如果你执行不通过,请su 到root账户,或者使用 sudo来操作,这在以后的篇幅中不再说明了。

# dd if=FlashBoot.bin of=FBPart1.bin bs=1 count=`echo "ibase=16;840-310"|bc` skip=`echo "ibase=16;310"|bc`

这样就得到第一部分的文件,类似的,取出第二部分代码部分。

# dd if=FlashBoot.bin of=FBPart2.bin bs=1 count=`echo "ibase=16;9B65C-80000"|bc`  skip=`echo "ibase=16;840"|bc`

注意了,bc 计算器只认识大写的16进制字母。

第二步,反汇编。反汇编的指令还是使用上一篇提到的objdump,但是这里又有一些不同,因为代码存放和运行的地址不同。FBPart1.bin运行于0地址,FBPart2.bin运行于0x60080000,所以为了理解方便,在反汇编时,使用参数--adjust-vma使其base地址发生偏移,便于查看。

# arm-linux-gnueabi-objdump  -b binary -marmv5 --adjust-vma=0x0 -D FBPart1.bin > FBPart1.asm

# arm-linux-gnueabi-objdump  -b binary -marmv5 --adjust-vma=0x60080000 -D FBPart2.bin > FBPart2.asm

第三步,利用汇编文件,形成C语言文件。现在就得到了两个汇编文件,这时的工作就是利用arm汇编指令以及CPU的寄存器地址,实现C语言。这个工作是非常繁琐的,需要掌握arm机器码的编码方式,arm gcc的链接过程,CPU的memory Map等等,所以还是在有时间的时候去做吧。

因为白盒反汇编的过程很漫长,所以只能通过黑盒的方式来从外围验证flashboot的功能。

从外设的角度讲,flashboot将围绕着 DDR,NAND flash,IDB flash,USB OTG,UART这个几个方面来操作。

从功能的角度讲,flashboot判断reset按键的状态,进而进入loader状态,或者直接启动kernel。在loader状态,负责 处理USB OTG的指令,包括烧写和读取等等。它还应该负责启动kernel失败后的处理。

那么以下,就通过实际的测试来验证我们预想的功能。

第一步,准备工具和原料。linux下,最好自己编译,否则出现一些问题,自己都不清楚。

工具:rkflashtool  下载地址:http://sourceforge.jp/projects/sfnet_rkflashtool/

参考文章:http://forum.xda-developers.com/showthread.php?t=1286305

原料:update_mk908_202j2203_overseas.img  注意是202j的,否则里面的内核在启动时,会发生错误。

下载地址:http://pan.baidu.com/s/1nFKAB

第二步,解包和烧写。当然可以先在windows用量产工具把升级包一次全部写入,这样我们就可以用减法的方法来验证预想。

进入loader模式的方法: 在进行试验前,先把MK908的调试串口接入主机,如果是USB转串口的线,则一般会在/dev/下产生

ttyUSBx的设备节点,如果是普通的串口,则使用ttySx就可以了。然后启动minicom或者其他串口软件。minicom第一次使用时,可以使用sudo minicom -s 来进行设置,设置方法就不多说了。

方法1.断电,用曲别针插入指示灯对面的小孔,按住reset键,USBcable 插入OTG接口,注意不是power接口。

方法2. 如果已经进入android系统了,那么在minicom中就有shell环境了。在shell中输入:

# su切换到root

# reboot  重启,在重启前,按住reset键,重启后就进入loader模式了。

验证进入loader模式的方法:

1. 在minicom中会有显示

2. 使用 lsusb 命令,会发现多了一个无名的设备,ivendr:iproduct == 2207:310B

以下实验都在loader模式下进行。

实验一:删除kernel分区,再启动。关于分区地址我们可以从解包后的parameter文件中cmdline中获得。

CMDLINE:console=ttyFIQ0 androidboot.console=ttyFIQ0 init=/init initrd=0x62000000,0x00800000 mtdparts=rk29xxnand:0x00002000@0x00002000(misc),0x00006000@0x00004000(kernel),0x00008000@0x0000A000(boot),0x00010000@0x00012000(recovery),0x00020000@0x00022000(backup),0x00040000@0x00042000(cache),0x00400000@0x00082000(userdata),0x00002000@0x00482000(kpanic),0x00100000@0x00484000(system),-@0x00584000(user)

# rkflashtool e 0x4000 0x6000  擦除

# rkflashtool  b重启

现象:系统可以正常启动

结论:kernel分区错误不影响系统启动。flashboot在启动时,可以检测到kernel分区的错误,进而跳过kernel分区,启动boot分区。

实验二:增加kernel分区内容。从网上下载了做好了的kernel image。http://www.zhetenger.com/node/56 这篇文章中的“MK908直接启动ubuntu系统内核”。使用winhex工具,能看到这个内核是经过rkcrc附加了校验信息的内核镜像。

# rkflashtool w 0x4000 0x6000 < kernel.img

# rkflashtool  b重启

现象系统启动到android

结论:即使kernel分区被写入了正确的内核镜像,flashboot也不会理会kernel。这说明kernel分区在这里只是一个摆设,没有实际作用。

实验三:删除boot分区。

# rkflashtool e 0xa000 0x8000  擦除

# rkflashtool  b 重启

现象:系统无法启动,重启到recovery模式,recovery模式下,修复了boot分区

结论:boot分区的缺失会使android无法启动,但flashboot会在boot分区启动失败时进入recovery模式,利用recovery模式修复系统。

实验四:删除boot分区,删除recovery分区

# rkflashtool e 0xa000 0x8000  擦除

# rkflashtool e 0x12000 0x10000  擦除

# rkflashtool  b 重启

现象:android系统无法启动,recovery模式无法进入,使用backup分区进行修复

结论:当recovery分区也缺失时,flashboot会利用backup分区的内容,对boot分区,misc分区,recovery分区进行修复。

实验五:删除boot,recovery,backup分区

# rkflashtool e 0xa000 0x8000  擦除

# rkflashtool e 0x12000 0x10000  擦除

#rkflashtool e 0x22000 0x20000  擦除

# rkflashtool  b 重启

现象:系统无法启动,flashboot停留在loader模式

结论:当所有以上的分区都缺失后 flashboot无能为力了,停在了loader模式下

通过以上实验,可以知道实际启动的内核在boot分区下。

在linux kernel启动过程中,bootloader给kernel传递的参数非常重要,很多参数都存在于parameter文件中,所以需要测试一下parameter参数对kernel启动的影响。注意:parameter文件修改后,需要使用rkcrc 进行Magic和校验的添加,否则flashboot无法检索到parameter。

下面是更细节的测试。

实验六:修改parameter参数,分析对启动的影响

a. 修改MACHINE_ID 字段为 008

启动正常

b.修改MAGIC 字段为0x5041524C

启动正常

c.修改ATAG字段

启动正常

d.修改CHECK_MASK字段

启动正常

e.修改KERNEL_IMG字段

启动正常

f.修改MACHINE字段

启动失败

g.修改CMDLINE

在启动的log中,能够发现内核的cmdline也发生改变

通过以上的实验,可以知道,parameter文件中的一些参数在启动android时是不起作用的,可能是在直接启动kernel时(目前的这个flashboot不支持)使用的。真正启动时使用的是MACHINE字段和CMDLINE字段。

MACHINE字段为bootloader启动kernel时传递的第二个参数,必须与内核中的machine id相同,否则无法启动内核。这一点可以参考uboot对linux 内核的启动。kernel端的machine id存放于 arch/arm/tools/mach-types文件中。

CMDLINE字段将以param中atag的形式传递给内核,即上图的第三个参数。实际上,这个参数是个内存地址,对应于parameter文件中的ATAG字段。内核在启动时,从该地址取得bootloader传递过来的参数,其中就包括了cmdline。这部分代码位于arch/arm/kernel/setup.c 中的setup_arch 函数。

通过以上的实验,我们大致验证了开始时的预想。

新增的结论:

使用当前的flashboot无法实现从kernel分区的直接启动

当前的flashboot优先启动boot分区,并在boot分区失效情况下,通过其他方式实现修复

当前flashboot 条件下,只有parameter文件中的MACHINE和CMDLINE字段影响内核启动

最终的结论:

当前flashboot 条件下,要想实现启动定制的内核,只能依赖于修改boot分区。为了改变内核启动时的某些特性,可以通过修改过parameter文件中的CMDLINE来实现。

明白了以上的结论,下一步我们就可以通过修改boot分区内容来实现我们定制系统的启动。


下一篇将仔细说一下rockchip公司的bootimg吧。

你可能感兴趣的:(linux,嵌入式,反编译,bootloader,rk3188,MK908)