这么做的目的是给
Linux
腾出空间,防止
Linux kernel
覆盖掉
uboot
,将
DRAM
前面的区域完整的空出来。
在拷贝之前肯定要给
uboot
各部分
分配好内存位置和大小,比如
gd
应该存放到哪个位置,
malloc
内存池应该存放到哪个位置等
等。这些信息都保存在
gd
的成员变量中,因此要对
gd
的这些成员变量做初始化。最终形成一
个完整的内存“分配图”,在后面重定位
uboot
的时候就会用到这个内存“分配图”。
下面简单分析一下 board_init_f 函数。 board_init_f 函数定义在文件 common/board_f.c 中定义,代码如下:
void board_init_f(ulong boot_flags)
if (initcall_run_list(init_sequence_f))
重点在第 4
行! 通过 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
函数后半部分是内存分配,下一篇文章再分析)
static init_fnc_t init_sequence_f[] = {
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage, /* need timer, go after init dm */
timer_init, /* initialize timer */
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 */
print_cpuinfo, /* display cpu info (and speed) */
/* TODO: unify all these dram functions? */
dram_init, /* configure available RAM banks */
第
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信息。
第
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
第
20
行,
show_board_info
函数,用于打印板子信息,会调用
checkboard
函数,打印如下:
第
21
行,
INIT_FUNC_WATCHDOG_INIT
,初始化看门狗,对于
I.MX6ULL
来说是空函数
第
22
行,
INIT_FUNC_WATCHDOG_RESET
,复位看门狗,对于
I.MX6ULL
来说是空函数
第
23
行,
init_func_i2c
函数,用于初始化
I2C
,初始化完成以后会输出如下:、
第
24
行,
announce_dram_init 函数
,此函数很简单,就是输出字符串“
DRAM:
”
第
26
行,
dram_init
函数,并非真正的初始化
DDR
,只是设置
gd->ram_size
的值,对于正点原
子
I.MX6ULL
开发板
EMMC
版本核心板来说就是
512MB
。
串口打印如下:
第
27
行,
post_init_f
函数,此函数用来完成一些测试,初始化
gd->post_init_f_time
第
29
行,
testdram
函数,测试
DRAM
,空函数。
以上是
board_init_f 函数的前半部分。
具体是初始化一系列外设,比如串口、定时器,或者打印一些消息等。
下一篇文章简单分析 board_init_f函数的后半部分代码,具体是内存分配的部分。