实现Linux/Android双系统启动和重启切换的一个思路

来源:互联网 发布:性价比帽子品牌知乎 编辑:程序博客网 时间:2024/05/14 07:30
双系统启动的方式不止一种。
一、对于双系统的启动镜像来说:
     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)。
     这样就完成了双系统的启动。
 
 
          本文只是一种思路,有更好的请广大码友指教!
 
1 0