1、
A20板,开机启动首先检测TF卡是否有卡及启动程序,如果有,就TF卡引导系统;如果没有,就接着检测Nand Flash中是否有启动程序去引导系统。
关于启动:
分区篇
如何引导系统之前, 了解一下机器内部Flash空间是如何划分的. 各个分区又是用作存储什么内容的.
下面以我手头上4G A20为例. 内部Flash芯片空间是4G, 这4G空间一共被分为9个分区.
+---------------------+
| 分区1: BOOTLOADER (64M) | 存放的是官方多系统引导方案的文件 (官方说可引导多系统,但我配置不出来)
| 厂商引导分区 | 关机充电控制代码也在这里分区中, 也负责部分核心硬件的地址配置和初始化工作
+---------------------+
| 分区2: ENV (2M) | 这个分区保存的是UBOOT引导器的配置信息, 包括启动时执行的命令, 从那个分区加载
| 内核配置信息 | 内核, 又是从哪个分区加载恢复系统内核
+---------------------+
| 分区3: BOOT(32M) | 存放基础的Linux内核文件(boot.img)分区没有文件系统, 是直接把可运行的内核
| Linux内核分区 | 文件写入分区空间, BOOT分区的uboot引导区会加载本分区内容到内存运行
+---------------------+
| 分区4: SYSTEM (400M)| Android系统分区, 也就是/system目录下的所有文件存放的分区, 为ext3/ext4格式
| Android系统分区 | 本分区包括Java格式的系统运行库还有部分没有编译进内核的硬件驱动库(bin格式)
+---------------------+
| 分区5: DATA (1G) | Android数据分区, 也就是/data目录对应的分区, 为ext3/ext4格式
| Android数据分区 | 这就是我们所说的把应用安装到机器内存所对应的空间, 同时保存各种动态系统设置
+---------------------+
| 分区6: MISC (1M) | 这个分区一般不使用, 唯一作用是为了让Android系统与内核引导时交流, 可以指引
| Android配置分区 | 重启机器后让内核进行一些特殊的操作, 如:进入恢复程序, 更新系统文件等操作
+---------------------+
| 分区7: RECOVERY(32M)| 一个特殊的微型Linux系统, 可以不依靠BOOT和SYSTEM分区启动, 类似PC的一键还原
| Android恢复系统 | 可对其他分区进行更新或备份. 如何实现恢复损坏的系统或者系统内核在后面说明.
+---------------------+
| 分区8: CACHE(256M) | 这个分区并不是做虚拟内存之类的缓存, 这个分区最大的 作用是做系统升级时保存
| 缓存分区 | 更新文件的(FAT格式). 配合MISC分区的配置语句来使用, 详细以后介绍.
+---------------------+
| 分区9: STORAGE(所有)| 没错, 剩下的所有空间, 都被划分给内置卡作为存储空间, 4G空间扣除1-7分区的
| 内置存储卡分区 | 使用后, 大概就是剩下的空间, 这就是为什么内置卡容量只有很小一部分
+---------------------+
引导篇
A20的上电引导大致上可以分为以下阶段: BROM -> Boot0 -> Boot1 -> Boot.axf -> u-boot -> kernel -> Android
下面介绍每个阶段所完成的事情.
BROM
BROM, 其实是一段已经固化在A20芯片里面的引导代码, BROM代码存放的地址是0xFFFF0000, 在A20芯片上电后,CPU自动的从0xFFFF0000地址上加载第一条指令并执行, 因此这里的BROM就和我们电脑主板上的BIOS是一样的, 只是BROM完成的功能没有BIOS强大. 简单的说, BROM只有2个功能, 第一个就是正常启动从外部存储器中加载运行代码,第二个也是最重要的一个就是FEL功能。FEL功能, 就是我们接触到的刷机接口. 官方的ROM更新程序就是通过FEL功能刷写机器的闪存的.
正是由于刷机接口的代码是固化在CPU内部, 不能被改写的原因,可以说,所有A20的机器都是刷不死的,没有变砖的可能。所以喜欢折腾的朋友请用力折腾,只要做好数据的备份,大不了就是重新用官方的升级工具重刷固件就可以了。机器进入FEL功能的有两种情况, 第一种就是常用的正常刷机方法: 关机状态下按住菜单键不放连接USB接口。另外一种就是Boot0代码的验证标记不正确,BROM也会自动进入FEL功能。
如果机器完全变砖,没有任何显示,正常按住菜单键连接USB也不能进入FEL,那可能就是你机器根本没有完全关闭,一般A20芯片方案所配合使用的电源控制芯片都是AXP209, 该芯片长按电源开关6秒以上会强制断电, 可先确认断电后再操作。
A20芯片的BROM还有一个的特性,那就是会优先从0号SD卡引导系统,没错,是SD卡,不是内部闪存NAND。而一般0号SD卡所对应的都是机器的的TF卡槽,因此制作SD卡上的系统完全可以的。
正是由于是优先从TF引导,所以通过在TF卡上写入特殊的,不能通过检验的Boot0代码,就可以通过插入TF卡后开机强制机器进入FEL功能进行刷机。
再总结一下BROM的启动流程:
(1). BROM是一段固化在CPU内部的代码,不能被修改和删除。代码会初始化外部存 储设备(内部Flash和SD卡);
(2). 检查刷机按钮是否被按下,有就跳转到3,没有就跳转到4继续执行;
(3). 启动FEL功能,初始化USB接口等等PC端连接;
(3). 正常引导过程,检查是否有0号SD卡插入,有则跳转到4,没有则跳转到7;
(4). 读取0号SD卡的8K地址处的内容,检查是否有Boot0标志,有则跳转到5,没 有则跳转到7;
(5). 根据Boot0头部指定的大小加载所有的Boot0代码到内存中, 检验校验值, 正确跳 转到6, 不正确跳转到3;
(6). CPU跳转到内存中的Boot0代码上继续执行, BROM工作完成, 控制权交给Boot0 的代码;
(7). 检查NAND(内部闪存)是否存在, 存在跳转到8, 不存在则跳转到3;
(8). 读取NAND的8K地址处的内容, 检查是否有Boot0标志, 有则跳转到9, 没有则跳 转到3;
(9). 根据Boot0头部指定的大小加载所有的Boot0代码到内存中, 检验校验值, 正确跳 转到6, 不正确跳转到3;
2、针对A20 EVB板
A20启动代码流程分析:
(1)、全志的启动包括boot0、boot1、u-boot,boot0与boot1源码在lichee/boot/目录下,机器上电执行boot0,boot0就会引导boot1,boot1再引导u-boot。
(2)、在lichee/boot/目录下的Makefile文件指定了boot1的编译目录,例如
make -f make_sdmmc -C boot1/core -j8
//命令就是调用lichee/boot/boot1/core目录下make_sdmmc脚本编译, make_sdmmc最终又调用make.cfg脚本编译,所以lichee/boot/目录下的Makefile文件指定的编译路径最终都会调用各自目录下的make.cfg来编译。
(3)、使用make_nand与make_sdmmc脚本是core目录生成的boot1_nand.bin与boot1_sdcard.bin,同时在
lichee/boot/workspace/egon/与
lichee/tools/pack/chips/sun7i/eGon/目录生成,他们分别调用
lichee/boot/boot1/driver/drv_nand/与lichee/boot/boot1/driver/drv_sd/目录下的文件;boot1_nand.bin与boot1_sdcard.bin分别对应启动模式:nandflash与inand启动,配置文件是在lichee/boot/pack/chips/sun7i/configs/android/sugar-cubieboard2目录下sys_config.fex文件指定,由storage_type字段指定,1为card0启动,0为nandflash启动,-1为自动扫描;
Boot_Android是正常启动模式,Boot_Burn是调试模式,Card_Android是升级模式,他们分别生成boot.axf,prvt.axf与sprite.axf镜像,同时
lichee/boot/workspace/wboot/bootfs/与
lichee/tools/pack/chips/sun7i/wboot/bootfs/目录生成;
lichee/boot/boot1/driver/drv_de/目录是多媒体库源码,是Lcd与HDMI等显示源码,同时在
lichee/boot/workspace/wboot/bootfs/与
lichee/tools/pack/chips/sun7i/wboot/bootfs/目录生成drv_de.drv镜像。
(4)、
arm_start.S(boot1/core/arm_board)->eGon2_swi_handler->eGon2_swi_handler_entry->eGon2_init->eGon2_start->eGon2_storage_type_set(判断启动模式,加载boot.axf或者sprite.axf),eGon2_run_app->FS_fread(加载.axf文件),elf_loader[*entry = (__u32)priv->main;],func(argc, argv)[该函数就是 BootMain()的指针]->BootMain。
A、正常启动模式:
BootMain->BoardInit_Display[加载drv_de.drv,判断显示模式,LCD、TV、HDMI等],check_power_status[检测电压与电池状态,判断是否开机],BootOS_detect_os_type[加载u-boot.bin,PreBootOS-> boot_dsipatch_kernal[设置u-boot的物理地址是
*kernal_addr=0x4a000000]->wBoot_fopen("c:\\linux\\u-boot.bin","rb")],
BootOS[wBoot_jump_to_linux->EGON2_SWI_JUMP_TO_LINUX->eGon2_jump_to_android_linux直接进入u-boot接口]。
B、升级模式:
BootMain->boot_ui_init[加载drv_de.drv,判断显示模式,LCD、TV、HDMI等],card_sprite->update_flash_hardware_scan[扫描当前存储设备是nand还是inand,update_boot0,update_boot1,根据sprite_type判断升级nand还是inand]。
(5)、
A、lichee/tools/pack/pack脚本打包镜像文件。
B、编译kernel的时候首调用
./build.sh -p sun7i_android->buildroot/scripts/common.sh->
lichee/linux-3.3/build.sh->lichee/buildroot/scripts/build_sun7i_android.sh编译。
在编译kernel的时候也编译u-boot,调用
./build.sh -p sun7i_android->buildroot/scripts/common.sh->
lichee/u-boot/build.sh编译。
(6)、
lichee/boot/pack/chips/sun7i/wboot/bootfs.ini
或lichee/tools/pack/chips/sun7i/wboot/bootfs.ini
把文件系统盘符映射成C盘,就是代码中使用的c:\\boot.ini","c:\\sprite.axf"等。 lichee/tools/pack/chips/sun7i/configs/android/default/下有env.cfg与image.cfg配置文件,nv.cfg是u-boot使用的配置文件,包括nand_root,mmc_root,loglevel,bootcmd等参数;image.cfg是boot使用的文件列表与ITEM_ROOTFSFAT32等重要符号。
(7)、sys_partition.fex文件中各个分区与下载对应的文件如下:
bootloader分区保存bootloader.fex,bootloader.fex就是由boot.axf 、u-boot.bin等组成。
env分区保存env.fex,env.fex就是
lichee/tools/pack/chips/sun4i/configs/crane/default/env.cfg文件,它是u-boot的基本配置。
boot分区保存boot.fex,boot.fex是boot.img的链接,它由kernel与ramdisk组成,使用fastboot下载的时候就是下载boot.img。
system分区保存system.fex,system.fex是system.img的链接,它是android系统,使用fastboot下载的时候就是下载system.img。
recovery分区保存recovery.fex,recovery.fex是recovery.img的链接,它也是由kernel与ramdisk组成,用于系统恢复,使用fastboot下载的时候就是下载recovery.img。
misc分区用于恢复系统设置的时候在uboot中保存一些变量与命令的值。
*.fex文件在lichee/tools/pack/out/目录,*.img在anroid/out/...下。
(8)、A20的分区如下:单位:512B
--------fastboot partitions--------
-total partitions:11-
-name- -start- -size-
bootloader : 8000 8000
env : 10000 8000
boot : 18000 8000
system : 20000 100000
data : 120000 100000
misc : 220000 8000
recovery : 228000 10000
cache : 238000 80000
private : 2b8000 8000
databk : 2c0000 80000
UDISK : 340000 3e0000
-----------------------------------
其中UDISK就是作为SDCARD分区,bootloader是从16MB开始,在bootloader的前面是16KB的MBR_SIZE与16KB的DL_SIZE。
(9)、各个镜像的对应的内存地址:
在read_boot_img()或者do_boota()都可以打印这些信息。
u-boot的地址为0x4a000000,在boot_dsipatch_kernal函数里强制赋值,也在该函数里
使用wBoot_fopen("c:\\linux\\u-boot.bin", "rb")与
wBoot_fread((void *)(*kernal_addr), 1, file_length, hd_file)
把u-boot.bin从存储设备加载到0x4a000000内存地址,之后boot1从BootOS(para_addr, kernal_addr)跳转到u-boot。
*kernal_addr = 0x4a000000。
kernel地址为0x40008000,ramdisk地址为0x41000000,在CONFIG_EXTRA_ENV_SETTINGS中的boota 40007800其实是把boot.img下载到内存中的地址,由于boot.img中包含了kernel与ramdisk,也包含了这两个镜像在内存中的地址,还有检查boot.img的magic是不是ANDROID,从存储设备加载这个两个镜像到内存的操作是在read_boot_img函数里,在u-boot是do_boota函数里再次检查boot.img的合法性。