最近在看全志D1的SDK,一头雾水。整个打包过程太多脚本,搞不清楚执行过程。在经过好多天的奋斗后,把一下搞明白的东西记录下来。
首先SD启动镜像是一个GPT分区的硬盘镜像,在第一个分区之前存放了一些固件。
尽管磁盘镜像是GPT,但依然有一份传统的MBR(分区表)。我的SD镜像来自伟东山的buildroot
➜ /tmp xxd -s 446 -l 64 disk.img
000001be: 8032 1102 0c46 2006 e089 0000 0000 0100 .2...F .........
000001ce: 0046 2106 8304 1e46 e089 0100 00a0 0f00 .F!....F........
000001de: 0000 0200 ee21 0100 0100 0000 1f08 0000 .....!..........
000001ee: 0000 0000 0000 0000 0000 0000 0000 0000 ................
我尝试清除了sd卡中的MBR,发现不能从sd卡启动了。从sd卡启动是会卡在uboot,日志如下:
[00.442][mmc]: get sdc_type fail and use default host:tm1.
[00.449][mmc]: can't find node "mmc0",will add new node
[00.453][mmc]: fdt err returned <no error>
[00.457][mmc]: Using default timing para
[00.461][mmc]: SUNXI SDMMC Controller Version:0x50310
[00.489][mmc]: card_caps:0x3000000a
[00.492][mmc]: host_caps:0x3000003f
[00.509]set disp.dev2_output_type fail. using defval=0
[00.533]Get bootloader and boot-resource partition number fail!
[00.562]out of usb burn from boot: not need burn key
这个程序存放在磁盘镜像8K字节偏移量的位置,被称为boot0。它的代码位于官方SDK的lichee/brandy-2.0/spl
目录。它被CPU内部的代码自动加载执行。它有一个头部用于记录一些参数,以及用于让CPU内部代码识别它是否为一个有效的boot0。这个头部比较复杂,相关代码参考官方SDK的lichee/brandy-2.0/spl/include/private_boot0.h
。此程序的主体代码位于lichee/brandy-2.0/spl/nboot/main/boot0_main.c
。它的主要工作为:初始化时钟、内存,并加载下一阶段的程序。
下一阶段的是一个程序包,被成为toc1
toc1存放在磁盘镜像的32800扇区,并且备份了一份在24576扇区。boot0会选择一个没有被破坏的toc1进行加载。toc1中存放了opensbi/uboot/dtb。toc1的格式:
最前面是一个toc1的头部,结构如下:
typedef struct sbrom_toc1_head_info
{
char name[16] ; //user can modify
u32 magic ; //must equal TOC_U32_MAGIC
u32 add_sum ;
u32 serial_num ; //user can modify
u32 status ; //user can modify,such as TOC_MAIN_INFO_STATUS_ENCRYP_NOT_USED
u32 items_nr; //total entry number
u32 valid_len;
u32 reserved[5]; //reserved for future
u32 end;
}
sbrom_toc1_head_info_t;
紧跟着头部是一些item head。这个用于描述item的位置,结构如下:
typedef struct sbrom_toc1_item_info
{
char name[64]; //such as ITEM_NAME_SBROMSW_CERTIF
u32 data_offset;
u32 data_len;
u32 encrypt; //0: no aes //1: aes
u32 type; //0: normal file, dont care 1: key certif 2: sign certif 3: bin file
u32 run_addr; //if it is a bin file, then run on this address; if not, it should be 0
u32 index; //if it is a bin file, this value shows the index to run; if not
//if it is a certif file, it should equal to the bin file index
//that they are in the same group
//it should be 0 when it anyother data type
u32 reserved[69]; //reserved for future;
u32 end;
}sbrom_toc1_item_info_t;
最后没一个镜像还有一个头部描述自己加载到何处
typedef struct _sunxi_image_head
{
unsigned int jump_instruction;
unsigned char magic[MAGIC_SIZE];
unsigned int res1;
unsigned int res2;
unsigned int res3;
unsigned int res4;
unsigned char res5[8];
unsigned char res6[8];
int run_addr;
}sunxi_image_head;
加载完成后运行opensbi
opensbi是jmp类型的固件,dtb的加载地址,和uboot的加载地址都是通过精心设计的编译脚本控制的。