程序员的圣诞节后-零

it2025-02-08  10

u-boot-2014.10代码分析及移植说明

1 ENTRY(_main) 2 3 /* 4 * Set up initial C runtime environment and call board_init_f(0). 5 */ 6 7 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) 8 ldr sp, =(CONFIG_SPL_STACK) 9 #else 10 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 11 #endif 12 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 13 mov r2, sp 14 sub sp, sp, #GD_SIZE /* allocate one GD above SP */ 15 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 16 mov r9, sp /* GD is above SP */ 17 mov r1, sp 18 mov r0, #0 1 clr_gd: 2 cmp r1, r2 /* while not at end of GD */ 3 strlo r0, [r1] /* clear 32-bit GD word */ 4 addlo r1, r1, #4 /* move to next */ 5 blo clr_gd

_main位于crt0.S中,该段主要是给u-boot中最根本最重要的变量gd分配空间并清零。

gd是一个结构体变量,其地址被放置于r9寄存器中(如果没记错的话,以前的版本是放入r8寄存器的),它包含了u-boot程序中最重要的全局信息,包括时钟相关变量,页表,重定位信息等,另外还包括传递给内核的板级信息。

1 #if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD) 2 sub sp, sp, #CONFIG_SYS_MALLOC_F_LEN 3 str sp, [r9, #GD_MALLOC_BASE] 4 #endif 5 /* mov r0, #0 not needed due to above code */ 6 bl board_init_f

定义relocation之前所需的堆空间地址,之后转入board_init_f程序,从此处起,SPL即BL1阶段代码和U-BOOT即BL2阶段代码分开走向了不同的路线。

如果未定义CONFIG_SYS_GENERIC_BOARD,则为/arch/arm/lib/board.c

如果定了CONFIG_SYS_GENERIC_BOARD,则为common/board_f.c。

想了想,先以/arch/arm/lib/board.c为例讲吧,毕竟这个是针对具体architecture(真实原因是common下那个我还没看过)

1 void board_init_f(ulong bootflag) 2 { 3 bd_t *bd; 4 init_fnc_t **init_fnc_ptr; 5 gd_t *id; 6 ulong addr, addr_sp; 7 #ifdef CONFIG_PRAM 8 ulong reg; 9 #endif 10 void *new_fdt = NULL; 11 size_t fdt_size = 0; 12 13 memset((void *)gd, 0, sizeof(gd_t));

 此处又重新将gd清零了,似乎有点多余啊,难道是针对SPL的?(原因是针对common/board_f.c的,该文件中的函数没有gd初始化)

1 gd->mon_len = (ulong)&__bss_end - (ulong)_start; 2 #ifdef CONFIG_OF_EMBED 3 /* Get a pointer to the FDT */ 4 gd->fdt_blob = __dtb_dt_begin; 5 #elif defined CONFIG_OF_SEPARATE 6 /* FDT is at end of image */ 7 gd->fdt_blob = &_end; 8 #endif 9 /* Allow the early environment to override the fdt address */ 10 gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, 11 (uintptr_t)gd->fdt_blob);

gd->mon_len为uboot大小。

CONFIG_OF_EMBED决定着是否将dtb编入uboot,libs-$(CONFIG_OF_EMBED) += dts/

CONFIG_OF_SEPARATE也是在同时编译dtb,但是分开编译,并未编入uboot中,Makefile中可以看出,但是没找到为何是放在_end后。

1 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { 2 if ((*init_fnc_ptr)() != 0) { 3 hang (); 4 } 5 }

该段则是进行一部分初始化,init_sequence为一个函数指针数组,

1 init_fnc_t *init_sequence[] = { 2 arch_cpu_init, /* basic arch cpu dependent setup */ 3 mark_bootstage, 4 #ifdef CONFIG_OF_CONTROL 5 fdtdec_check_fdt, 6 #endif 7 #if defined(CONFIG_BOARD_EARLY_INIT_F) 8 board_early_init_f, 9 #endif 10 timer_init, /* initialize timer */ 11 #ifdef CONFIG_BOARD_POSTCLK_INIT 12 board_postclk_init, 13 #endif 14 #ifdef CONFIG_FSL_ESDHC 15 get_clocks, 16 #endif 17 env_init, /* initialize environment */ 18 init_baudrate, /* initialze baudrate settings */ 19 serial_init, /* serial communications setup */ 20 console_init_f, /* stage 1 init of console */ 21 display_banner, /* say that we are here */ 22 print_cpuinfo, /* display cpu info (and speed) */ 23 #if defined(CONFIG_DISPLAY_BOARDINFO) 24 checkboard, /* display board info */ 25 #endif 26 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C) 27 init_func_i2c, 28 #endif 29 dram_init, /* configure available RAM banks */ 30 NULL, 31 };

注意该处实际是个指向函数指针的数组,其好处我能想到的一点是末尾的NULL,通过指针为NULL判断作为结束标志。以下逐一分析各个初始化函数,

1.arch_cpu_init

该函数自然就是需要针对各个芯片自己实现了,通常可以在该函数中实现cache使能的控制

2.mark_bootstage

1 /* Record the board_init_f() bootstage (after arch_cpu_init()) */ 2 static int mark_bootstage(void) 3 { 4 bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); 5 6 return 0; 7 }

算是uboot的流程中做个标记,bootstage_mark_name函数最终可以通过和板级自己实现的一个函数挂接,实现通过打印或者led灯等各种方式来反应uboot的进程。

3.fdtdec_check_fdt

检测fdt是否存在

4.board_early_init_f

早期的一些初始化

如需要,定义宏CONFIG_BOARD_EARLY_INIT_F,并实现该函数

5.timer_init

timer初始化,题外:u-boot中timer驱动的作用是为了实现delay,因此timer驱动也是围绕udelay展开的。

6.board_postclk_init

早期时钟相关初始化

如需要,定义宏CONFIG_BOARD_POSTCLK_INIT,并实现该函数

7.get_clocks

看起来实际主要是为了获取gd->arch.sdhc_clk时钟,即为了获取sdmmc时钟,不过并不是必要。

如需要,定义宏CONFIG_FSL_ESDHC,并实现该函数

8.env_init

初始化gd中的两个成员,即环境变量表的地址,以及valid值

9.init_baudrate

初始化gd中的波特率成员变量

该处设计BAUDRATE的一个宏定义

10.serial_init

初始化串口驱动

对应串口驱动中必须添加的两个函数default_serial_console,以及serial_device结构体的start成员函数

11.console_init_f

其实没啥,只是在存在CONFIG_PRE_CONSOLE_BUFFER的情况下会有个buffer初始化的过程

12.display_banner

打印uboot版本信息等

13.print_cpuinfo

这个是各个芯片自己实现,打印一些cpu相关信息

14.checkboard

打印board相关信息

15.init_func_i2c

如果有且需要i2c的话,初始化

16.dram_init

自己实现,gd->ram_size的初始化,当然也有吧dram_bank的初始化写在这里

整个init_sequence初始化就结束了。

剩下的下期再说。

 

转载于:https://www.cnblogs.com/iambobor/p/4185763.html

最新回复(0)