1、海思分段式uboot鏡像
(1)uboot鏡像的生成參考部落格:《海思晶片(hi3516dv300)uboot鏡像生成過程詳解》;
(2)海思uboot鏡像類似于核心的zImage鏡像,大緻組成就是未壓縮的頭部+壓縮的鏡像,先運作未壓縮的頭部代碼,頭部代碼會解壓縮鏡像并調用;
2、海思分段式uboot鏡像的優劣
優點:
(1)将寄存器的設定單獨用表格形式,形象直覺并修改友善;
(2)壓縮的鏡像占的空間更小,傳統的uboot.bin大小有501KB,經壓縮行成的u-boot-hi3516dv300.bin大小隻有21KB;
缺點:
(1)uboot鏡像的生成過程變得更複雜;
(2)uboot的啟動過程也變得複雜,先運作未壓縮代碼去解壓縮,再運作壓縮部分代碼;
補充:海思晶片内置了硬體解壓縮子產品,解壓縮工作是硬體完成的;
3、dv300晶片的位址映射
(1)海思hi3516dv300晶片内置BOOTROM是64KB,片内RAM是40KB,可以推測uboot啟動第一階段讀進去的資料不會超過40KB;
(2)海思晶片是ARM結構,采用統一編址,32位CPU理論上可以接4G的記憶體,但是實際最多可以接2G記憶體,其餘的位址空間被配置設定給寄存器、BOOTROM、片内RAM;
4、海思uboot啟動流程
(1)海思晶片内置BOOTROM代碼會從序列槽/網絡/eMMC/Nor flash/Nand flash等方式讀取uboot鏡像的頭部(讀取的頭部資料具體大小不确定,但肯定不超過40KB)到晶片内部的RAM中運作;
(2)讀進去的uboot頭部程式,會解析.reg檔案去設定寄存器,初始化DDR;
(3)将整個uboot鏡像重定位到DDR中,利用晶片硬體解壓縮子產品,将壓縮的uboot.bin解壓縮到DDR中,然後執行解壓縮後的uboot代碼;
(4)解壓縮後的uboot代碼會去初始化闆級硬體,比如螢幕、觸摸屏等等,最終啟動核心;
5、啟動第一階段
5.1、第一階段定義
這裡說的第一階段不是官方定義,隻是個人了解,将執行壓縮uboot鏡像前的過程叫做第一階段。
5.2、第一階段涉及的源代碼
u-boot-2016.11/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/Makefile
u-boot-2016.11/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/u-boot.lds
u-boot-2016.11/.reg
u-boot-2016.11/u-boot.bin
//.o檔案,在Makefile中指定,按照連結腳本u-boot.lds用于生成u-boot-hi3516dv300.elf
START := start.o
COBJS := lowlevel_init_v300.o \
init_registers.o \
emmc_boot.o \
uart.o \
ddr_training_impl.o \
ddr_training_ctl.o \
ddr_training_boot.o \
ddr_training_custom.o \
ddr_training_console.o \
startup.o \
image_data.o \
div0.o \
reset.o
(1)根據連結腳本u-boot.lds可知,第一階段的入口是u-boot-2016.11/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/start.S的_start标号處;
(2)從start.S的_start标号處開始分析彙編代碼,涉及的檔案在Makefile中指定,注意檔案的路徑,因為在uboot源碼中有很多同名檔案;
5.3、第一階段的代碼流程

5.4、uboot鏡像的解壓縮代碼
//u-boot-2016.11/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/image_data.S
.section .image,#alloc
.globl input_data
/*gzip source addr must be 16 bytes aligned*/
.balign 16
input_data:
.incbin "image_data.gzip"
.globl input_data_end
input_data_end:
#define CONFIG_SYS_TEXT_BASE 0x80800000
#define GZIP_SIZE_OFFSET 0x4
const unsigned long IMAGE_ENTRY = (CONFIG_SYS_TEXT_BASE);
//u-boot-2016.11/arch/arm/cpu/armv7/hi3516dv300/hw_compressed/startup.c
void start_armboot(void)
{
unsigned char *pdst_l32;
unsigned int image_data_len;
int pdst_len;
int ret;
int i;
char *p;
char *q;
uart_early_init();
uart_early_puts("\r\nUncompress ");
/*use direct address mode*/
hw_dec_type=0;
/*初始化硬體解壓縮子產品*/
hw_dec_init();
/*将壓縮鏡像解壓後存放的記憶體位址*/
pdst_l32 = (unsigned char *)IMAGE_ENTRY;
//整個被壓縮鏡像(image_data.gzip)的長度
image_data_len = input_data_end - input_data;
/*擷取被壓縮鏡像本來的大小,也就是uboot.bin的大小*/
p = (char *)&pdst_len;
q = (char *)(input_data_end - GZIP_SIZE_OFFSET);
for (i = 0; i < sizeof(int); i++) {
p[i] = q[i];
}
//解壓u-boot.bin到記憶體位址0x80800000
ret = hw_dec_decompress(pdst_l32, &pdst_len, input_data, image_data_len, NULL);
if (!ret)
uart_early_puts("Ok!");
else {
uart_early_puts("Fail!");
while(1);
}
/*反初始化硬體解壓縮子產品,節省性能,降低功耗*/
hw_dec_uinit();
//調用解壓縮後的uboot代碼,直接調用記憶體位址0x80800000,也就是uboot.bin鏡像的入口
void (*uboot)(void);
uboot = (void (*))CONFIG_SYS_TEXT_BASE;
invalidate_icache_all();
uboot();
}
(1)input_data和input_data_end是壓縮核心鏡像(image_data.gzip)在記憶體中的起始/結束位址;
(2)解壓縮子產品是海思晶片内置的硬體子產品,我們不用關心,隻要按照解壓函數的參數要求進行傳參即可;
6、啟動第二階段
(1)在uboot啟動第一階段調用了uboot啟動的第二階段,也就是執行u-boot.bin;
(2)u-boot.bin就是一般的uboot啟動流程,具體去分析頂層Makefile中是如何生成u-boot.bin的,根據連結腳本找到入口位址,這裡不再贅述,可以參考我以前的uboot啟動流程分析的部落格;