fastboot刷机的前提是你的开发板uboot良好并能正常启动进入fastboot模式,你的开发版的nand分区已存在。对于Android的uboot而言, 已经实现了fastboot命令,当你进入uboot命令行时键入fastboot即可进入fastboot模式,这个时候会调用usb相关驱动,和外部建立连接,如果你使用的是windows系统,那么你需要下载相应版本的fastboot,然后安装对应你开发板的usb驱动程序,当启动fastboot命令后便能通过usb连接上开发板,通过fastboot提供的命令进行刷机操作,而这些所有的操作其实都是基于fastboot与usb通信约定的,当你将镜像文件通过fastboot命令经过usb传入ram时,这个时候另一端的开发板正在监听usb传递过来的数据,然后通过fastboot约定好的命令对这些数据进行处理,处理的实质就是uboot通过查找对应的分区表,然后对这些数据使用命令mmc,或者是nand命令写入到对应的分区中。
下面介绍一种裸刷机而非fastboot刷机(fastboot的刷机实质),在刷机前你需要满足3个条件:
1.你能够进入你的uboot控制台。
2.你的uboot控制台支持mmc/nand命令(实现mmc命令的格式可能不同)
3.你得知道你分区的情况。例如下面的分区:
efi partition table:
ptbl slot: EMMC:(1).
256 128K xloader
512 256K bootloader
1024 128K misc
2048 16M efs
34816 16K crypto
34848 8M recovery
51232 8M boot
67616 512M system
1116192 256M cache
1640480 29630M userdata
Net: KS8851SNL
表示的意思依次是: 分区起始块(十进制) 分区大小 分区名,排列如下:
0 --------+
+ 分区表
256------+
+ xloader
512------+
+ bootloader
1024----+
........
(通常,对于nand分区来说是按照块大小进行划分的,最小单位就是块(512字节),如上面xloader分区,计算一下128*1024/(512-256)= 512(byte))所以上面的块起始也表示该分区的起始地址,如boot的起始地址就是0xc820 (按照块寻址)。
假设当前我的android启动后控制台是普通权限,为了能启动后为管理员权限,我必须修改init.rc中的console服务,修改前后如下:
修改前:
service console /system/bin/sh
class core
console
disabled
user shell
group log
修改后:
service console /system/bin/sh
class core
console
disabled
user root
group root
为了能刷机后正常启动,我们先提取上面的boot分区中的boot.img镜像,boot分区保存着boot.img镜像文件数据,而boot.img包含了android使用的ramdisk.img和kernel文件以及bootarmgs参数(可选),所以我们只需要将boot.img提取出来然后分离里面的ramdisk.img,接着对ramdisk.img解压后修改init.rc文件,然后重新打包ramdisk.img,在将这个修改过的ramdisk.img和内核以及bootarmgs重新打包为boot.img,之后写入到boot分区中,总结一下就是如下步骤;
1.提取boot.img和kernrl
通过上面不难发现boot对应的分区节点是mmcblk0p7,执行如下命令:
$dd if=/dev/block/mmcblk0p7 of=/data/boot.img
得到boot.img后,直接通过C32二进制编辑工具,提取ramdisk.img,这里需要对boot.img文件构成进行了解,boot.img主要是由2kb大小的头+ramdisk.img+kernel构成,前2kb头信息由结构体struct boot_img_hdr表示,具体可以参考$(TOP)/system/core/mkbootimg/bootimg.h源码文件。
将boot.img载入C32如下图:
上面贴出了128字节的数据,其中红色划线部分表示BOOT_MAGIC,蓝色的前面部分表示内核大小,后面为内核的载入物理地址,
紫色划线的前面部分表示ramdisk.img大小,后面表示ramdisk载入的物理地址,由上面我们可以知道:
kernel_size = 0x43e598 (大约4.1M)
ramdisk_size = 0x28b9e (大约162KB)
载入基址(base)= 0x80000000 //打包boot.img用
由于数据按照页对齐,通过源码不难发现一页大小为2kb,那么根据boot.img的格式分析得出:
kernel数据范围:0x800 --> 0x43F000(本来实际是到0x800-->0x800+0x43e598,由于按照2k页对齐,所以超出部分按照1页计算)
ramdisk数据范围:0x43F000 -------> 0x468000(实际是0x43F000 -->0x43F000 +0x28b9e)
这样我们就确定了实际的kernel和ramdisk数据范围:
kernel实际数据范围:0x800-->0x43ED98
ramdisk实际数据范围:0x43F000 -->0x467B9E
之后通过单击右键选择块复制-》新建文件粘贴另存,就提取了ramdisk和kernel.
2.解压ramdisk.img修改并打包
解压步骤如下:
$mv ramdisk.img ramdisk.img.gz
$gunzip ramdisk.img.gz
$mkdir ramdisk
$cd ramdisk
$cpio -i -F ../ramdisk.img
经过修改后打包,打包如下:
(mkbootfs 和minigzip可以在android源码生成的out/host/linux-x86/bin/下找到)
$mkbootfs ramdisk | minigzip > ./ramdisk.img
3.生成boot.img
mkbootimg --kernel out/target/product/panda/kernel --ramdisk out/target/product/panda/ramdisk.img --cmdline "console=ttyO2,115200n8 mem=1024M androidboot.console=ttyO2 vram=20M omapfb.vram=0:16M" --base 0x80000000 --output out/target/product/panda/boot.img
由于本boot.img中未见cmdline参数,所以不需要加--cmdline,正确命令如下:
(mkbootimg 在out/host/linux-x86/bin/可以找到,kernel 为你提取的源内核,ramdisk.img为修改后的,0x80000000为上面计算出来的基址)
$mkbootimg --kernel kernel --ramdisk ramdisk.img --base 0x80000000 --output ./boot.img
4.烧写boot.img到boot分区
1.确保你的tftp搭建好。
2.进入uboot模式,配置ipaddr和serverip,需要的话可配置ethaddr网卡地址。
3.执行如下命令。mmc命令格式可能不太一样:
$mmcinit 1 ;1表示mmc槽位
$mmc 1 erase 0xc820 0x800000 ;意思是擦除起始地址为0xc820大小为8M的块
$tftp 0x81000000 boot.img ;意思是通过tftp命令将boot.img文件先载入到内存地址为0x81000000的地方,这里下载完毕后得到boot.img大小记为ramdisk_size.
$mmc 1 write 0x81000000 0xc820 ramdisk_size ;意思是将内存地址为0x81000000的地方的大小为ramdisk_size的数据拷贝到起始地址为0xc820中
这样烧写完毕,你可以通过#mmc 1 read 0x80000000 0xc820 0x200 将起始地址0xc820大小为512字节的数据复制到内存起始地址为0x80000000的地方,然后通过$md 0x81000000 0x200命令进行查看对比是否和boot.img开头数据一致。
所有操作完毕,reset重启开发版吧!