1.1 硬件配置
这是一个16M flash, 128M内存,mips架构的IPC芯片,因为OTA升级过程中,可能会升级kernel和rootfs,如果这两个分区升级过程断电,板子永远变砖,因此,考虑做成一个双系统,A系统升级挂掉,则由B系统恢复A系统。
1.2 分区信息
#16M flash 空间划分 (16M flash被划分为8个分区)
256k(boot) 只读
1536k(kernel 1) 只读
2944k(rootfs 1) 只读
128k(config) 只读,配置分区1,可以uboot中读取配置,比如升级失败时,用来保存升级失败状态,从而决定启动A系统还是B系统
6528k(app) 只读,应用分区,主要是应用程序,经常修改升级的分区
512k(config1) 可读可写 ,配置分区2
1536k(kernel 2) 只读
2944k(rootfs 2) 只读
以上8个分区,加起来的大小,刚好是16M
各个分区的地址偏移量及起始地址
1.3 简单讲一下uboot的启动流程
uboot启动是从start.S 文件开始启动的,这是文件是汇编代码,初始化完之后,将从board_init_f跳转到c语言部分
就是:
start.S-> board_init_f ->
-> board_init_r -> main_loop -> process_boot_delay(倒数3s,如果按下key,则进入for循环)
-> 否则进入内核
->一系列初始化->do_bootm_linux->theKernel(进入内核)
1.4 在uboot阶段,读取config的变量值,决定启动A系统还是B系统
从flash中读取config分区
把这个128k的数据,强制转化成结构体操作
read_flash_config_data 函数被process_boot_delay调用 ,从0x4A0000地址区,读取(size=128*1024)在大小的内容, 进入A还是B系统的决定变量,保存这个分区中,如果A系统升级失败,会把u32FwUpgradeStatus这个变量设置成1,成功则等于0,这里uboot在这个阶段,可以根据这个环境变量,决定启动A系统还是B系统。
1.5 根据1.4的变量值,设置环境变量,决定跳转到A系统还是B系统
/*A系统的启动环境变量*/
#define CONFIG_BOOTARGS BOOTARGS_COMMON " init=/linuxrc rootfstype=squashfs root=/dev/mtdblock2 rw mtdparts=jz_sfc:256k(boot),1536k(kernel),2944k(rootfs),128k(config),6528k(appfs),512k(config1),1536k(kernel2),2944k(rootfs2) ja_version=01.31X.20201219.01"
/*B系统的启动环境变量设置*/
#define CONFIG_BOOTARGS_B BOOTARGS_COMMON " init=/linuxrc rootfstype=squashfs root=/dev/mtdblock7 rw mtdparts=jz_sfc:256k(boot),1536k(kernel),2944k(rootfs),128k(config),6528k(appfs),512k(config1),1536k(kernel2),2944k(rootfs2) ja_version=01.31X.20201219.01"
/*不同的地方是:root=/dev/mtdblock2 此为A系统内核分区所在位置
root=/dev/mtdblock7 此为B系统内核分区所在位置
*/
/*value就是等于1.4中u32FwUpgradeStatus这个变量, set_bootargs在uboot阶段的process_boot_delay中调用*/
void set_bootargs(int value)
{
char *cmdline = getenv("bootargs");
int len = strlen(cmdline);
char *buf = malloc(len+1);
if(buf == NULL){
printf("joa_set_bootargs,malloc for buf failed\n");
return;
}
memset(buf,0,len+1);
if(value == 1){/*A*/
strncpy(buf,CONFIG_BOOTARGS,len);
}
else{/*B*/
strncpy(buf,CONFIG_BOOTARGS_B,len);
}
printf("joa_set_bootargs set buf=%s\n",buf);
setenv("bootargs", buf);
free(buf);
}
// set_bootargs函数调用完,就能决定进入A系统还是B系统
1.6 end
嵌入式双系统的关键在于uboot阶段能读取到config分区,这个分区在保存了OTA升级的时候,失败或者成功的状态,从而进入uboot阶段之后,决定启动A系统,还是B系统,而启动A系统还是B系统,又可以通过设置环境变量来设置。