雙系統啓動的方式不止一種。
一、對於雙系統的啓動鏡像來說:
1、Linux系統和Android系統的uboot、kernel鏡像相同而文件系統(rootfs)不同;
2、Linux系統和Android系統的uboot鏡像相同而kernel鏡像和文件系統(roofts)不同。
這兩種情況都可以實現對雙系統的啓動和切換。
二、雙系統啓動和相互切換的實質是設置標誌位,在啓動時讀取標誌位信息從而啓動相應的系統!下面是兩種實現方式。
1、啓動(重啓)時,單獨分出一個分區存儲標誌位(保證兩個系統都能對這一塊分區操作);
在應用程序中向分區寫入標誌位,然後重啓在uboot階段自動scan讀取這個分區中的標誌位(對應啓動相應的系統)。
2、在文件系統分區寫入一個.txt文件(文件存儲標誌位);
在uboot中scan讀取該.txt文件的中的內容(標誌位),然後決定啓動相應的系統。
三、本次主要討論Linux系統和Android共uboot的情況,實現方式爲單獨分出一個分區存儲標誌位。已實現。
1、要實現雙系統的啓動和相互切換,需要對uboot啓動過程、bootargs引導參數有相應的瞭解。
2、首先,將uboot,Android系統的kernel和file system,Linux系統的kernel和file system燒寫到emmc中,如下圖所示。
注意:燒寫的物理位置應與下面講到的bootargs引導參數相對應,否則系統啓動會失敗!!!
圖中爲主要燒寫部分,其他的燒寫按照自己思路稍微調整。
設置flags分區,存儲我們的啓動標誌位。
3、對uboot的修改:
(1)將bootargs引導參數寫入uboot中,並且製作command命令,至於怎樣將製作的command命令放在".u_boot_cmd"段: ,用下面例子講解。
例子:
a)在common文件夾下創建cmd_sunplus.c;
b)在cmd_sunplus.c中添加“sunplus_linuxemmcboot 和sunplus_androidemmcboot”命令的響應函數的實現。具體的實現代碼如下:
//====================================================================
int do_sunplus_linuxemmcboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int ret = 0;
/*①
設置bootargs引導參數
//這裏BOOT_TYPE_LINUX_EMMC爲 "console=ttyAMA0,115200 root=/dev/mmcblk0p8 rootfstype=ext4 rootwait blkdevparts=mmcblk0:1M(boot),1M(bootargs),4M(baseparam),4M(pqparam),4M(logo),3058M(unused),8M(kernel),96M(rootfs),1M(flags),-(others)
coherent_pool=1M"
*/
setenv("bootargs", BOOT_TYPE_ANDROID_EMMC );
/*②
從emmc中讀取kernel到內存中:起始地址爲0x600000(內核文件存儲的實際物理地址),長度爲0x4000,讀到起始地址爲0x1000000的內存中
*/
ret = run_command("mmc read 0 0x1000000 0x600000 0x4000" , 0);
if(ret == -1) {
printf("read kernel failed.\n");
sp_failed();
}
/* ③
啓動Linux的kernel
*/
printf(GREEN"Boot to linux.\n"NONE);
run_command("bootm 0x1000000" , 0);
printf("bootm linux sys failed.\n");
return ret;
}
U_BOOT_CMD(
sunplus_linuxemmcboot, 1, 0, do_sunplus_linuxemmcboot,
"[sunplus app func]:boot up linux from emmc",
"\n"
);
int do_sunplus_androidemmcboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int ret = 0;
/*①
設置bootargs引導參數
//這裏BOOT_TYPE_ANDROID_EMMC爲 "console=ttyAMA0,115200 blkdevparts=mmcblk0:1M(fastboot),1M(bootargs),10M(recovery),2M(deviceinfo),8M(baseparam),8M(pqparam),20M(logo),20M(logobak),40M(fastplay),40M(fastplaybak),40M(kernel),20M(misc),8M(userapi),8M(hibdrv),8M(qbflag),300M(qbdata),800M(system),1024M(userdata),500M(cache),50M(private),50M(sdcard),218M(unused),1M(flags),-(others)
coherent_pool=1M"
*/
setenv("bootargs", BOOT_TYPE_ANDROID_EMMC );
/*②
從emmc中讀取kernel到內存中:起始地址爲0x4B000(內核文件存儲的實際物理地址) ,長度爲0x5000,讀到起始地址爲0x1FFBFC0的內存中
*/
ret = run_command("mmc read 0 0x1FFBFC0 0x4B000 0x5000" , 0);
if(ret == -1) {
printf("read kernel failed.\n");
sp_failed();
}
/* ③
啓動Android的kernel
*/
printf(GREEN"Boot to android.\n"NONE);
run_command("bootm 0x1FFBFC0" , 0);
printf("bootm android sys failed.\n");
return ret;
}
U_BOOT_CMD(
sunplus_androidemmcboot, 1, 0, do_sunplus_androidemmcboot,
"[sunplus app func]:boot up android from emmc",
"\n"
);
//====================================================================
c)將common/cmd_sunplus.c編譯進u-boot.bin,在common/Makefile中加入如下代碼:
COBJS-$(CONFIG_BOOT_SUNPLUS) += cmd_sunplus.o
d)在include/configs/hi3798mx.h(代碼相應位置)加入如代碼:
#define CONFIG_BOOT_SUNPLUS
e)重新編譯下載U-Boot就可以使用sunplus_linuxemmcboot 和sunplus_androidemmcboot 命令了
(2)在boot源碼的Main.c中,找到main_loop()函數。
要實現雙系統啓動,需要在boot啓動階段掃描咱們定義的標誌位,然後啓動相應的系統。下圖是main_loop()函數的掃描標誌位操作,在如圖所示位置加入掃描標誌位分區,既能率先掃描分區,又能達到控制Ctrl+C到boot命令下
4、編譯boot,燒寫完成之後啓動系統。
啓動完成後,在Linux系統下,flags(標誌位分區)是/dev/mmcblock0p9第九分區,在/dev/mmcblock0p9設備文件中寫入“android”,重啓即可切換到Android系統。同理,在Android系統下,flags(標誌位分區)在/dev/block/mmcblock0p23第23分區,在/dev/block/mmcblock0p23設備文件中寫入“linuxaa”,即可切換到Linux系統。
兩個系統雖然是不同的設備文件名,但都是操作的同一塊物理地址(起始地址爲0x63400)。
這樣就完成了雙系統的啓動。
本文只是一種思路,有更好的請廣大碼友指教!