1.前言
本文主要就Hi3556v200的U-boot+Liteos方案的启动流程做简要介绍, 前面主要分析了Hi3556v200下的start.S文件,在这之后它将解压通用uboot的代码执行,执行的入口位于通用uboot的start.S文件。
通过_main最终调用到board_init_f函数,board_init_f将遍历执行init_sequence_f函数数组。
U-boot版本:u-boot-2016.11
2.init_sequence_f函数数组
位于/u-boot-2016.11/common/board_f.c
board_init_f主要是调用了init_sequence_f函数数组,下面简要说明一下init_sequence_f的关键函数:
-
setup_mon_len
设置 gd->mon_len 成员变量,此处为_bss_end -start,也就是整个代码的长度
注意:此时gd变量地址主要是在board_init_f中分配,由于是局部变量,因此主要保存在栈里,栈指针为0x04014000-0x2000, 此位于sram的空间,如下类同。 -
fdtdec_setup
fdt相关配置,主要获取了fdt的地址
/* Get a pointer to the FDT */
gd->fdt_blob = __dtb_dt_begin; -
trace_early_init
-
trace buffer的初始化
-
initf_malloc
设置 malloc相关变量:
gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
堆大小为CONFIG_SYS_MALLOC_F_LEN -
arch_cpu_init
basic arch cpu dependent setup,Hi3556未实现 -
mach_cpu_init,
SoC/machine dependent CPU setup,Hi3556未实现 -
initf_dm
驱动模型的一些初始化 -
initf_console_record
如 果 定 义 了宏 CONFIG_CONSOLE_RECORD 和 宏CONFIG_SYS_MALLOC_F_LEN 的话此函数就会调用函数 console_record_init,但是 Hi3556v200的 uboot 没有定义宏 CONFIG_CONSOLE_RECORD,所以此函数直接返回 0 -
arch_cpu_init
basic arch cpu dependent setup -
mach_cpu_init, /* SoC/machine dependent CPU setup */
-
timer_init
初始化定时器,Cortex-A7 内核有一个定时器,这里初始化的就是 Cortex-A 内核的那个定时器。通过这个定时器来为 uboot 提供时间。就跟 Cortex-M 内核 Systick 定时器一样 -
board_early_init_f
板子相关的早期的一些初始化设置
osdrv/opensource/uboot/u-boot-2016.11/board/hisilicon/hi3556v200/hi3556v200.c中,返回0. -
env_init
初始化环境变量地址
gd->env_addr = (ulong)&default_environment[0]
设置 gd 的成员变量 env_addr,也就是环境变量的保存地址。 -
init_baud_rate,
/* initialze baudrate settings */ -
serial_init,
/* serial communications setup */ -
console_init_f,
/* stage 1 init of console */ -
show_board_info
If the root node of the DTB has a “model” property, show it -
INIT_FUNC_WATCHDOG_INIT
-
dram_init
只是设置了ddr大小
gd->ram_size += gd->bd->bi_dram[i].size -
testdram
dram测试程序 -
display_options, /* say that we are here */
-
display_text_info, /* show debugging info if required */
-
setup_dest_addr
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*
* Reserve memory at end of RAM for (top down in that order):
* - area that won’t get touched by U-Boot and Linux (optional)
* - kernel log buffer
* - protected RAM
* - LCD framebuffer
* - monitor code
* - board info struct
*/
如上为setup_dest_addr的注释,setup_dest_addr将设置uboot的重定位地址,后面就可以执行重定位并转向重定位后的地址执行
编译阶段osdrv_mem_cfg.sh脚本按照soc来进行修改位于osdrv/opensource/uboot/u-boot-2016.11/tools/include/configs/hi3559v200.h中的宏,包括:
#define PHYS_SDRAM_1 0x80000000
#define PHYS_SDRAM_1_SIZE 0x10000000
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
setup_dest_addr主要初始化了gd的如下成员变量
gd->ram_top = CONFIG_SYS_SDRAM_BASE//DRAM基地址
gd->ram_top += get_effective_memsize();//gd->ram_top被初始化为DRAM的最顶端地址
gd->ram_top = board_get_usable_ram_top(gd->mon_len);
gd->relocaddr = gd->ram_top;//uboot的重定位地址,当前为DRAM最顶端地址,会根据预留空间逐步调整 -
reserve_logbuffer
为logbuffer预留空间,同时下调gd->relocaddr
gd->relocaddr -= LOGBUFF_RESERVE -
reserve_pram
参数预留,同时下调gd->relocaddr
reg = getenv_ulong(“pram”, 10, CONFIG_PRAM);
gd->relocaddr -= (reg << 10); /* size is in kB */ -
reserve_mmu
为mmu预留空间,同时下调gd->relocaddr
gd->arch.tlb_size = PGTABLE_SIZE;
gd->relocaddr -= gd->arch.tlb_size; -
reserve_lcd
gd->fb_base = CONFIG_FB_ADDR;
gd->relocaddr = lcd_setmem(gd->relocaddr);
gd->fb_base = gd->relocaddr; -
reserve_uboot
gd->relocaddr -= gd->mon_len;//为uboot预留空间,同时下调gd->relocaddr
gd->relocaddr &= ~(4096 - 1);
debug(“Reserving %ldk for U-Boot at: %08lx\n”, gd->mon_len >> 10,
gd->relocaddr);
gd->start_addr_sp = gd->relocaddr;
留出重定位后的 uboot 所占用的内存区域,uboot 所占用大小由gd->mon_len 所指定
留出 uboot 的空间以后还要对 gd->relocaddr 做 4K 字节对齐,并且重新设置
gd->start_addr_sp = gd->relocaddr;
从上面的预留方法可以看出,是通过dram的最高地址开始,一直递减来为各部分预留空间
到此处已经确认出 -
reserve_malloc
为malloc预留空间
gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; -
reserve_board
为bd_t结构体预留空间 -
setup_machine
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ -
reserve_global_data
设置新的global data空间
gd->start_addr_sp -= sizeof(gd_t);
gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
debug(“Reserving %zu Bytes for Global Data at: %08lx\n”,
sizeof(gd_t), gd->start_addr_sp); -
reserve_fdt
为fdt预留空间
gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
gd->start_addr_sp -= gd->fdt_size;
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
debug(“Reserving %lu Bytes for FDT at: %08lx\n”,
gd->fdt_size, gd->start_addr_sp); -
reserve_stacks
为栈预留16字节
int arch_reserve_stacks(void)
{
/* setup stack pointer for exceptions */
gd->irq_sp = gd->start_addr_sp;
# if !defined(CONFIG_ARM64)
# ifdef CONFIG_USE_IRQ
gd->start_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ);
debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->start_addr_sp);
/* 8-byte alignment for ARM ABI compliance */
gd->start_addr_sp &= ~0x07;
# endif
/* leave 3 words for abort-stack, plus 1 for alignment */
gd->start_addr_sp -= 16;
# endif
return 0;
}
-
setup_dram_config
-
show_dram_config
显示RAM信息 -
display_new_sp
debug(“New Stack Pointer is: %08lx\n”, gd->start_addr_sp); -
setup_reloc
gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
获取当前uboot代码与重定位后的uboot代码之间的偏移,其中
osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3556v200.h中有如下的定义:
#define CONFIG_SYS_TEXT_BASE 0x80800000
memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
将global data从sram重定位到dram中的reloc addr
也就是说setup_reloc首先计算重定位的偏移,并完成global data的重定位
3. 总结
综上所述,可以画出如下的内存布局