目录
一、crt0_64.S
文件位置:u-boot-2022.01/arch/arm/lib/crt0_64.S
_main入口
bl board_init_f_alloc_reserve
mov sp, x0
/* set up gd here, outside any C code */
mov x18, x0
bl board_init_f_init_reserve
mov x0, #0
bl board_init_f
- 执行3函数,前2个在u-boot-2022.01\common\init\board_init.c 中
board_init_f_alloc_reserve
board_init_f_init_reserve
board_init_f 在u-boot-2022.01\common\board_f.c -
board_init_f_alloc_reserve,board_init_f_init_reserve主要实现内存排布:
uboot区,堆区,栈区,gd(bd)
board_init_f_alloc_reserve:最终算出gd的内存地址,top指向
board_init_f_init_reserve:实例化gd,并初始化为0
二、board_init_f函数
void board_init_f(ulong boot_flags)
{
gd->flags = boot_flags;
gd->have_console = 0;
if (initcall_run_list(init_sequence_f))
hang();
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64) && \
!defined(CONFIG_ARC)
/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
}
static inline int initcall_run_list(const init_fnc_t init_sequence[])
{
const init_fnc_t *init_fnc_ptr;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
unsigned long reloc_ofs = 0;
int ret;
/*
* Sandbox is relocated by the OS, so symbols always appear at
* the relocated address.
*/
if (IS_ENABLED(CONFIG_SANDBOX) || (gd->flags & GD_FLG_RELOC))
reloc_ofs = gd->reloc_off;
#ifdef CONFIG_EFI_APP //debug开关
reloc_ofs = (unsigned long)image_base;
#endif
if (reloc_ofs)
debug("initcall: %p (relocated to %p)\n",
(char *)*init_fnc_ptr - reloc_ofs,
(char *)*init_fnc_ptr);
else
debug("initcall: %p\n", (char *)*init_fnc_ptr - reloc_ofs);
ret = (*init_fnc_ptr)();
if (ret) {
printf("initcall sequence %p failed at call %p (err=%d)\n",
init_sequence,
(char *)*init_fnc_ptr - reloc_ofs, ret);
return -1;
}
}
return 0;
}
static const init_fnc_t init_sequence_f[] = {
setup_mon_len,
#ifdef CONFIG_OF_CONTROL
fdtdec_setup,
#endif
#ifdef CONFIG_TRACE_EARLY
trace_early_init,
#endif
initf_malloc,
log_init,
initf_bootstage, /* uses its own timer, so does not need DM */
#ifdef CONFIG_BLOBLIST
bloblist_init,
#endif
setup_spl_handoff,
#if defined(CONFIG_CONSOLE_RECORD_INIT_F)
console_record_init,
#endif
#if defined(CONFIG_HAVE_FSP)
arch_fsp_init,
#endif
arch_cpu_init, /* basic arch cpu dependent setup */
mach_cpu_init, /* SoC/machine dependent CPU setup */
initf_dm,
arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
/* get CPU and bus clocks according to the environment variable */
get_clocks, /* get CPU and bus clocks (etc.) */
#endif
#if !defined(CONFIG_M68K)
timer_init, /* initialize timer */
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
board_postclk_init,
#endif
env_init, /* initialize environment */
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
checkcpu,
#if defined(CONFIG_SYSRESET)
print_resetinfo,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DTB_RESELECT)
embedded_dtb_select,
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
show_board_info,
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
misc_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if CONFIG_IS_ENABLED(SYS_I2C_LEGACY)
init_func_i2c,
#endif
#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
init_func_vid,
#endif
announce_dram_init,
dram_init, /* configure available RAM banks */
#ifdef CONFIG_POST
post_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_POST
init_post,
#endif
INIT_FUNC_WATCHDOG_RESET
/*
* 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,
#ifdef CONFIG_OF_BOARD_FIXUP
fix_fdt,
#endif
#ifdef CONFIG_PRAM
reserve_pram,
#endif
reserve_round_4k,
arch_reserve_mmu,
reserve_video,
reserve_trace,
reserve_uboot,
reserve_malloc,
reserve_board,
reserve_global_data,
reserve_fdt,
reserve_bootstage,
reserve_bloblist,
reserve_arch,
reserve_stacks,
dram_init_banksize,
show_dram_config,
INIT_FUNC_WATCHDOG_RESET
setup_bdinfo,
display_new_sp,
INIT_FUNC_WATCHDOG_RESET
reloc_fdt,
reloc_bootstage,
reloc_bloblist,
setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
copy_uboot_to_ram,
do_elf_reloc_fixups,
#endif
clear_bss,
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!CONFIG_IS_ENABLED(X86_64)
jump_to_copy,
#endif
NULL,
};
- gd->flags = boot_flags;
gd->have_console = 0;
flags:全局数据标志
have_console:控制台1可用,0不可用 - typedef int (*init_fnc_t)(void); 一个函数类型
- init_sequence是一个函数指针数组,数组中存储了很多个函数指针,这些指向指向的函数都是init_fnc_t类型(参数是void类型,返回值是int)
都是board级别的各种硬件初始化 - 函数:int initcall_run_list(const init_fnc_t init_sequence[])
返回值int,参数是一个二级指针init_sequence这个函数指针数组 - for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
依次执行init_sequence这个函数指针数组里的函数,直到NULL退出循环
函数执行出错返回-1,退出到board_init_f()函数,进入hang()函数 - hang() 死循环,只能重新上电
三、init_sequence_f[] 函数数组(一)
串口、定时器、设备树、malloc、cpu、DM驱动模型、dram、
static const init_fnc_t init_sequence_f[] = {
setup_mon_len,
fdtdec_setup,
initf_malloc,
log_init,
initf_bootstage, /* uses its own timer, so does not need DM */
setup_spl_handoff,
arch_cpu_init, /* basic arch cpu dependent setup */
mach_cpu_init, /* SoC/machine dependent CPU setup */
initf_dm,
arch_cpu_init_dm,
get_clocks, /* get CPU and bus clocks (etc.) */
board_postclk_init,
env_init, /* initialize environment */
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
checkcpu,
announce_dram_init,
dram_init, /* configure available RAM banks */
testdram,
setup_dest_addr,
reserve_pram,
reserve_round_4k,
arch_reserve_mmu,
reserve_video,
reserve_trace,
reserve_uboot,
reserve_malloc,
reserve_board,
reserve_global_data,
reserve_fdt,
reserve_bootstage,
reserve_bloblist,
reserve_arch,
reserve_stacks,
dram_init_banksize,
show_dram_config,
setup_bdinfo,
display_new_sp,
reloc_fdt,
reloc_bootstage,
reloc_bloblist,
setup_reloc,
clear_bss,
NULL,
};
- setup_mon_len:设置 gd 的 mon_len 成员变量,整个代码的长度
- fdtdec_setup:获取设备树地址
- initf_malloc:设置gd 的malloc_limit,malloc内存池大小
CONFIG_SYS_MALLOC_F_LEN=0x2000 - log_init,initf_bootstage,setup_spl_handoff:什么也没做返回0
- arch_cpu_init:硬件 CPU初始化
- mach_cpu_init:特定SoC的初始化
- initf_dm,arch_cpu_init_dm:DM驱动模型的一些初始化,DM驱动模型参考
- get_clocks:获取一些时钟值
- timer_init:初始化定时器,为 uboot 提供时间
- board_postclk_init:对于 I.MX6ULL 来说是设置 VDDSOC 电压
- env_init:设置 gd 的成员变量 env_addr,也就是环境变量的保存地址
- init_baud_rate:初始化波特率,env_get函数用来读取环境变量的值 baudrate
初始化 gd->baudrate
baudrate初始化时的规则是:先去环境变量中读取"baudrate"这个环境变量的值。如果读取成功则使用这个值作为环境变量,记录在gd->baudrate中;如果读取不成功则使用CONFIG_BAUDRATE的值作为波特率 - serial_init:初始化串口
加一句自己调试,验证初始化成功
drivers/serial/serial-uclass.cU-Boot 2022.09.21xiaowei (Oct 01 2022 - 22:53:14 -0700) DRAM: 128 MiB 128 MiB RPI 3 Model B (0xa32082) xw: serial MMC: mmc@7e202000: 0, sdhci@7e300000: 1 Loading Environment from FAT... *** Warning - bad CRC, using default environment In: serial Out: vidconsole Err: vidconsole Net: No ethernet found. starting USB... Bus usb@7e980000: USB DWC2 scanning bus usb@7e980000 for devices... 3 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found Hit any key to stop autoboot: 0 U-Boot>
- console_init_f:设置 gd->have_console 为 1表示有个控制台,此函数也将前面暂存在缓冲区中的数据通过控制台打印出来。
- display_options:通过串口输出一些信息,如u-boot的版本信息,注释到可以发现版本信息没有了
lib/display_options.cMESS:00:00:03.389240:0: uart: Baud rateDRAM: 128 MiB 128 MiB RPI 3 Model B (0xa32082) xw: serial init xw: pirntf serial init xw: env_addr: 133816044 MMC: mmc@7e202000: 0, sdhci@7e300000: 1 Loading Environment from FAT... *** Warning - bad CRC, using default environment In: serial Out: vidconsole Err: vidconsole Net: No ethernet found. starting USB... Bus usb@7e980000: USB DWC2 scanning bus usb@7e980000 for devices... 3 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found Hit any key to stop autoboot: 0 U-Boot>
- display_text_info:打印一些文本信息,如果开启 UBOOT 的 DEBUG 功能的话就会输出 text_base、bss_start、bss_end
开启DEBUG方法:在include/common.h文件添加 #define DEBUG
也可以自己添加调试信息打印(printf)xw: u-boot code: 00080000 -> 00104340 BSS: -> 0010F130
- checkcpu:什么也没做返回0
- announce_dram_init:打印字符串DRAM:
- dram_init:DRAM初始化
- testdram:测试DRAM,并打印一些信息
现在我们已经映射了DRAM并开始工作,我们可以重新定位代码并继续从DRAM运行
四、init_sequence_f[] 函数数组(二)
对uboot重定位的一些地址设置
- setup_dest_addr:uboot重定位设置gd->ram_size,gd->ram_top,gd->relocaddr这三个的值
xw: gd->ram_size: 0x8000000 //RAM大小128M xw: gd->ram_top: 0x7fe0000 //U-Boot使用的RAM顶部地址 xw: gd->relocaddr: 0x7fe0000 //RAM中U-Boot的起始地址,跟随设置空间变化
- reserve_round_4k:对gd->relocaddr做4KB对齐
- arch_reserve_mmu:预留空间存放TLB表,以及64kb对齐
文件位置:arch\arm\lib\cache.cxw: cache:arm_reserve_mmu: gd->arch.tlb_size = 00008000 //TLB 表大小32kb gd->arch.tlb_addr = 07fd0000 //TLB 表起始地址, 64KB 对齐以后 gd->relocaddr = 07fd0000 //现在地址,7fe0000-7fd0000=64kb
- reserve_trace:留出跟踪调试的内存
- reserve_uboot: 留出重定位后的 uboot 所占用的内存区域
xw: board_f.c:reserve_uboot:gd->mon_len=0008f3b0 //uboot 所占用大小 xw: board_f.c:reserve_uboot:gd->relocaddr=07f40000 //4K 字节对齐,现在的地址,大小90000,576kb xw: board_f.c:reserve_uboot:gd->start_addr_sp=07f40000 // 栈指针地址
- reserve_malloc:留出malloc区域
malloc 区域由宏TOTAL_MALLOC_LEN 定义xw: board_f.c:reserve_malloc:TOTAL_MALLOC_LEN = 00404000 //长度大小,4M xw: board_f.c:reserve_malloc:gd->start_addr_sp = 07b3c000M
- reserve_board:预留bd_info结构体大小空间,并清零
xw: board_f.c:reserve_board:gd->bd(struct bd_info) = 136byte xw: board_f.c:reserve_board:gd->start_addr_sp = 07b3bf70 //7b3bf70-7b3bf70=144 多预留8b
- reserve_global_data:预留空间给gd_t结构体
xw: board_f.c:reserve_global_data:gd_t = 408byte xw: board_f.c:reserve_global_data:gd->start_addr_sp = 07b3bdd0 //07b3bf70-07b3bdd0=416 多预留8b
- reserve_fdt:预留空间给设备树驱动,没有使用,所以没预留
xw: board_f.c:reserve_fdt:gd->fdt_size = 0byte xw: board_f.c:reserve_fdt:gd->start_addr_sp = 07b3bdd0
- reserve_bootstage,reserve_bloblist:什么也没做
- reserve_arch:空函数
- reserve_stacks:预留空间给栈16字节
xw: board_f.c:reserve_stacks:gd->start_addr_sp = 07b3bdc0
- dram_init_banksize:设置 dram 信息,gd->bd->bi_dram[0].start,gd->bd->bi_dram[0].size
- show_dram_config:显示 DRAM 的配置start,size
xw: board_f.c:show_dram_config:gd->bd->bi_dram[0].start = 0 xw: board_f.c:show_dram_config:gd->bd->bi_dram[0].size = 8000000
- setup_bdinfo:什么也没做
- display_new_sp:debug打印当前start_addr_sp
xw: board_f.c:display_new_sp:gd->start_addr_sp = 07b3bdc0
- reloc_fdt,reloc_bootstage,reloc_bloblist:什么也没做
- setup_reloc:设置gd结构体的其他一些成员变量,供后面重定位的时候使用,并且将以前的 gd 拷贝到 gd->new_gd 处
xw: board_f.c:setup_reloc:gd->reloc_off = 07ec0000 xw: board_f.c:setup_reloc:gd->relocaddr = 07f40000 //重定位后uboot地址 xw: board_f.c:setup_reloc:gd->new_gd = 07b3bdd0 //gd首地址 xw: board_f.c:setup_reloc:gd->start_addr_sp = 07b3bdc0 //sp
- clear_bss:空函数
五、内存分配如图