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重啟開發版吧!