uboot启动流程-涉及board_init_f 函数

一.   uboot启动流程


_main 函数中会调用 board_init_f 函数,本文简单分析一下 board_init_f 函数。

二.   board_init_f 函数

board_init_f 函数主要有两个工作:

(1)   初始化一系列外设,比如串口、定时器,或者打印一些消息等。
(2)   初始化 gd 的各个成员变量,uboot 会将自己重定位到 DRAM 最后面的地址区域,也就
是将自己拷贝到 DRAM 最后面的内存区域中。
这么做的目的是给 Linux 腾出空间,防止 Linux kernel 覆盖掉 uboot ,将 DRAM 前面的区域完整的空出来。
在拷贝之前肯定要给 uboot 各部分 分配好内存位置和大小,比如 gd 应该存放到哪个位置, malloc 内存池应该存放到哪个位置等 等。这些信息都保存在 gd 的成员变量中,因此要对 gd 的这些成员变量做初始化。最终形成一 个完整的内存“分配图”,在后面重定位 uboot 的时候就会用到这个内存“分配图”。

下面简单分析一下 board_init_f 函数。 board_init_f 函数定义在文件 common/board_f.c 中定义,代码如下:
1035 void board_init_f(ulong boot_flags)
1036 {
1037 #ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
1038 /*
1039 * For some archtectures, global data is initialized and used 
1040 * before calling this function. The data should be preserved. 
1041 * For others, CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined 
1042 * and use the stack here to host global data until relocation.
1043 */
1044 gd_t data;
1045
1046 gd = &data;
1047
1048 /*
1049 * Clear global data before it is accessed at debug print
1050 * in initcall_run_list. Otherwise the debug print probably
1051 * get the wrong vaule of gd->have_console.
1052 */
1053 zero_global_data();
1054 #endif
1055
1056 gd->flags = boot_flags;
1057 gd->have_console = 0;
1058
1059 if (initcall_run_list(init_sequence_f))
1060 hang();
1061
1062 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
1063 !defined(CONFIG_EFI_APP)
1064 /* NOTREACHED - jump_to_copy() does not return */
1065 hang();
1066 #endif
1067 }

1037~1054行代码无效,因为没有定义 CONFIG_SYS_GENERIC_GLOBAL_DATA
1056 行,初始化 gd->flags=boot_flags=0
1057 行,设置 gd->have_console=0
重点在第 1059 行! 通过 initcall_run_list 函数 来运行初始化序列 init_sequence_f 里面的一些
列函数,init_sequence_f 里面包含了一系列的初始化函数。 
init_sequence_f 也是定义在文件 common/board_f.c 中,由于 init_sequence_f 的内容比较长,里面有大量的条件编译代码,这里 为了缩小篇幅,将条件编译部分删除掉了
去掉条件编译以后的 init_sequence_f 函数 前半部分代码 如下:
(因为 init_sequence_f 函数后半部分是内存分配,下一篇文章再分析)
/*****************去掉条件编译语句后的 init_sequence_f***************/
1 static init_fnc_t init_sequence_f[] = {
2 setup_mon_len, 
3 initf_malloc, 
4 initf_console_record, 
5 arch_cpu_init, /* basic arch cpu dependent setup */ 
6 initf_dm, 
7 arch_cpu_init_dm, 
8 mark_bootstage, /* need timer, go after init dm */ 
9 board_early_init_f, 
10 timer_init, /* initialize timer */ 
11 board_postclk_init, 
12 get_clocks, 
13 env_init, /* initialize environment */ 
14 init_baud_rate, /* initialze baudrate settings */ 
15 serial_init, /* serial communications setup */ 
16 console_init_f, /* stage 1 init of console */ 
17 display_options, /* say that we are here */ 
18 display_text_info, /* show debugging info if required */ 
19 print_cpuinfo, /* display cpu info (and speed) */ 
20 show_board_info, 
21 INIT_FUNC_WATCHDOG_INIT 
22 INIT_FUNC_WATCHDOG_RESET 
23 init_func_i2c, 
24 announce_dram_init, 
25 /* TODO: unify all these dram functions? */
26 dram_init, /* configure available RAM banks */ 
27 post_init_f, 
28 INIT_FUNC_WATCHDOG_RESET
29 testdram, 
30 INIT_FUNC_WATCHDOG_RESET
31 INIT_FUNC_WATCHDOG_RESET
......
62 NULL,
63 };

2 行, setup_mon_len 函数设置 gd mon_len 成员变量,此处为 __bss_end -_start ,也就 是整个代码的长度,即 uboot的镜像大小
3 行, initf_malloc 函数初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit ,此函 数会设置 gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN=0X400 malloc_limit 表示 malloc 内存池大小。
4 行 , initf_console_record 函数, 如 果 定 义 了 宏 CONFIG_CONSOLE_RECORD 和 宏
CONFIG_SYS_MALLOC_F_LEN ,则此函数就会调用函数 console_record_init ,但是 IMX6ULL
uboot 没有定义宏 CONFIG_CONSOLE_RECORD ,所以此函数直接返回 0
5 行, arch_cpu_init 函数,应该与架构相关的初始化。
6 行, initf_dm 函数,驱动模型的一些初始化。
7 行, arch_cpu_init_dm 函数未实现。
8 行, mark_bootstage 函数应该是和啥标记有关的
9 行, board_early_init_f 函数,板子相关的早期的一些初始化设置, I.MX6ULL 用来初始 化串口的 IO 配置 。
10 行, timer_init 函数,初始化定时器, Cortex-A7 内核有一个定时器,这里初始化的就 Cortex- A 内核的那个定时器。通过这个定时器来为 uboot 提供时间。就跟 Cortex-M 内核 Systick 定时 器一样。关于 Cortex-A 内部定时器的详细内容,请参考文档 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf 的“ Chapter B8 The Generic Timer ”章节。
11 行, board_postclk_init 函数 ,对于 I.MX6ULL 来说是设置 VDDSOC 电压。
12 行, get_clocks 函数,用于获取一些时钟值, I.MX6ULL 获取的是 sdhc_clk 时钟,也就 SD 卡外设的时钟。
13 行, env_init 函数,是和环境变量有关的,设置 gd 的成员变量 env_addr ,也就是环境变 量的保存地址。
14 行, init_baud_rate 函数,用于初始化波特率,根据环境变量 baudrate 来初始化 gd->baudrate
15 行,serial_init 函数,初始化串口。
16 行,console_init_f 函数,设置 gd->have_console 1 ,表示有个控制台,此函数也将前面 暂存在缓冲区中的数据通过控制台打印出来。
17 行, display_options 函数 ,通过串口输出一些信息:
U-Boot 2016.03 (Jul 07 2023 - 17:11:27 +0800)
18 行, display_text_info ,打印一些文本信息,如果开启 UBOOT DEBUG 功能的话就
会输出 text_base bss_start bss_end ,形式如下:
debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",text_base, bss_start, bss_end);
开启 UBOOT 的 DEBUG 功能的方法:

include/configs下有不用开发板的配置头文件,IMX6ULL使用的是 mx6ullevk.h,可以在mx6ullevk.h文件中加:

#define   DEBUG

重新编译后的 uboot镜像文件,烧录到设备,就可以打印 uboot的debug信息。

Board: I.MX6U ALPHA|MINI

19 行, print_cpuinfo 函数,用于打印 CPU 信息,打印结果如下:
CPU:   Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU:   Industrial temperature grade (-40C to 105C) at 35C
Reset cause: POR

20 行, show_board_info 函数,用于打印板子信息,会调用 checkboard 函数,打印如下:
21 行, INIT_FUNC_WATCHDOG_INIT ,初始化看门狗,对于 I.MX6ULL 来说是空函数
22 行, INIT_FUNC_WATCHDOG_RESET ,复位看门狗,对于 I.MX6ULL 来说是空函数
23 行, init_func_i2c 函数,用于初始化 I2C ,初始化完成以后会输出如下:、
I2C:   ready

24 行, announce_dram_init 函数 ,此函数很简单,就是输出字符串“ DRAM:
26 行, dram_init 函数,并非真正的初始化 DDR ,只是设置 gd->ram_size 的值,对于正点原 I.MX6ULL 开发板 EMMC 版本核心板来说就是 512MB
串口打印如下:

uboot启动流程-涉及board_init_f 函数_第1张图片

27 行, post_init_f 函数,此函数用来完成一些测试,初始化 gd->post_init_f_time
29 行, testdram 函数,测试 DRAM ,空函数。
以上是 board_init_f 函数的前半部分。
具体是初始化一系列外设,比如串口、定时器,或者打印一些消息等。
下一篇文章简单分析 board_init_f函数的后半部分代码,具体是内存分配的部分。

你可能感兴趣的:(uboot,系统移植篇,linux,arm开发)