您当前的位置:首页 > 计算机 > 精彩资源

(三)u-boot启动流程分析(C语言部分board_f.c)

时间:04-17来源:作者:点击数:

从上节我们知道,C语言部分主要集中在两个函数board_init_f和board_init_r,主要是board初始化的前部分(front)及后部分(rear),我们先来看board_init_f函数的实现:

common/board_f.c

void board_init_f(ulong boot_flags)
{
....

    gd->flags = boot_flags;
    gd->have_console = 0;

    if (initcall_run_list(init_sequence_f))
	hang();

....
}

board_init_f() 函数的实现很简单,主要就是执行init_sequence_f里面包含的函数的初始化。

static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
	setup_ram_buf,
#endif
	setup_mon_len,
	setup_fdt,
#ifdef CONFIG_TRACE
	trace_early_init,
#endif
	initf_malloc,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
	/* TODO: can this go into arch_cpu_init()? */
	probecpu,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mark_bootstage,
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
	initf_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
	/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
	get_clocks,		/* get CPU and bus clocks (etc.) */
#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
		&& !defined(CONFIG_TQM885D)
	adjust_sdram_tbs_8xx,
#endif
	/* TODO: can we rename this to timer_init()? */
	init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_BLACKFIN)
	timer_init,		/* initialize timer */
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM
#if !defined(CONFIG_CPM2)
	dpram_init,
#endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT)
	/* get CPU and bus clocks according to the environment variable */
	get_clocks_866,
	/* adjust sdram refresh rate according to the new clock */
	sdram_adjust_866,
	init_timebase,
#endif
	init_baud_rate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
#ifdef CONFIG_SANDBOX
	sandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROL
	fdtdec_prepare_fdt,
#endif
	display_options,	/* say that we are here */
	display_text_info,	/* show debugging info if required */
#if defined(CONFIG_MPC8260)
	prt_8260_rsr,
	prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)
	prt_83xx_rsr,
#endif
#ifdef CONFIG_PPC
	checkcpu,
#endif
	print_cpuinfo,		/* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)
	prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
	INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
	misc_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
	init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
	init_func_spi,
#endif
	announce_dram_init,
	/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86)
	dram_init,		/* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC)
	init_func_ram,
#endif
#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,
#if defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2)
	/* Blackfin u-boot monitor should be on top of the ram */
	reserve_uboot,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
	reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
		defined(CONFIG_ARM)
	reserve_mmu,
#endif
#ifdef CONFIG_LCD
	reserve_lcd,
#endif
	reserve_trace,
	/* TODO: Why the dependency on CONFIG_8xx? */
#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
		!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
		!defined(CONFIG_BLACKFIN)
	reserve_video,
#endif
#if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_NIOS2)
	reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
	reserve_malloc,
	reserve_board,
#endif
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_stacks,
	setup_dram_config,
	show_dram_config,
#ifdef CONFIG_PPC
	setup_board_part1,
	INIT_FUNC_WATCHDOG_RESET
	setup_board_part2,
#endif
	display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO
	setup_board_extra,
#endif
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	setup_reloc,
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
	jump_to_copy,
#endif
	NULL,
};

这里面的函数初始化很多,我们也不是都了解,大致的解释下我们知道的函数:

setup_fdt device tree相关的

initf_malloc 初始化malloc相关的global data

arch_cpu_init cpu级别的初始化操作

initf_dm driver model相关的初始化

board_early_init_f board相关的early的初始化操作,可以根据实际的情况完成board的early初始化,

具体定义在项目对于的C文件中,例如(axg_s400_v1.c)

get_clocks 获取CPU和BUS的时钟频率,并保存在global data中

timer_init 初始化系统的timer

env_init 环境变量相关的初始化

init_baud_rate 设置波特率

serial_init 初始化串口,初始化之后串口即可用

console_init_f 初始化控制台,

fdtdec_prepare_fdt device tree相关的准备操作

display_options

display_text_info 显示及打印一些debug信息

misc_init_f misc driver相关的初始化

init_func_i2c i2c driver相关的初始化

init_func_spi spi driver相关的初始化

announce_dram_init 仅仅打印DRAM,提示即将DDR的初始化

dram_init DDR初始化

testdram DDR测试

setup_dram_config 调用dram_init_banksize接口,初始化DDR的bank信息。

reloc_fdt device tree的relocation操作

setup_reloc 计算relocation有关的信息,主要是 gd->reloc_off

由于env是uboot中比较重要的一部分,我们来看看uboot相关的操作:

int env_init(void)
{
	/* use default */
	gd->env_addr = (ulong)&default_environment[0];
	gd->env_valid = 1;

	return 0;
}

缺省的env主要是来自于default_environment, 我们来看看default_environment的定义(include/env_default.h):

const uchar default_environment[] = {......
	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
	"bootargs="	CONFIG_BOOTARGS			"\0"
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
	"bootdelay="	__stringify(CONFIG_BOOTDELAY)	"\0"
	"baudrate="	__stringify(CONFIG_BAUDRATE)	"\0"
	"loads_echo="	__stringify(CONFIG_LOADS_ECHO)	"\0"
	"ethaddr="	__stringify(CONFIG_ETHADDR)	"\0"
	"eth1addr="	__stringify(CONFIG_ETH1ADDR)	"\0"
	"eth2addr="	__stringify(CONFIG_ETH2ADDR)	"\0"
	"eth3addr="	__stringify(CONFIG_ETH3ADDR)	"\0"
	"eth4addr="	__stringify(CONFIG_ETH4ADDR)	"\0"
	"eth5addr="	__stringify(CONFIG_ETH5ADDR)	"\0"
	"ethprime="	CONFIG_ETHPRIME			"\0"
	"ipaddr="	__stringify(CONFIG_IPADDR)	"\0"
	"serverip="	__stringify(CONFIG_SERVERIP)	"\0"
	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
	"preboot="	CONFIG_PREBOOT			"\0"
	"rootpath="	CONFIG_ROOTPATH			"\0"
	"gatewayip="	__stringify(CONFIG_GATEWAYIP)	"\0"
	"netmask="	__stringify(CONFIG_NETMASK)	"\0
	"hostname="	__stringify(CONFIG_HOSTNAME)	"\0"
	"bootfile="	CONFIG_BOOTFILE			"\0"
	"loadaddr="	__stringify(CONFIG_LOADADDR)	"\0"
	"clocks_in_mhz=1\0"
	"pcidelay="	__stringify(CONFIG_PCI_BOOTDELAY)"\0"
	"arch="		CONFIG_SYS_ARCH			"\0"
	"cpu="		CONFIG_SYS_CPU			"\0"
	"board="	CONFIG_SYS_BOARD		"\0"
	"board_name="	CONFIG_SYS_BOARD		"\0"
	"vendor="	CONFIG_SYS_VENDOR		"\0"
	"soc="		CONFIG_SYS_SOC			"\0"
};

这里定义了一系列的uboot env变量及赋值,包括bootcmd,preboot等变量

我们在头文件axg_s400_v1.h头文件中,可以看到CONFIG_BOOTCOMMAND,CONFIG_PREBOOT,CONFIG_EXTRA_ENV_SETTINGS等的定义:

#define CONFIG_EXTRA_ENV_SETTINGS \
        "firstboot=1\0"\
        "jtag=apao\0"\
        "loadaddr=1080000\0"\
        "panel_type=lcd_0\0" \
        "outputmode=panel\0" \
        "osd_reverse=0\0"\
        "video_reverse=0\0"\
        bcb_cmd; "\..................
        "factory_reset_poweroff_protect="\.......................................
        "switch_bootmode="\....................................
        ................................
        .................................
        "storeboot="\.........................................
        ......................................................

#define CONFIG_PREBOOT  \
            "run bcb_cmd; "\
            "run factory_reset_poweroff_protect;"\
            "run upgrade_check;"\
            "run init_display;"\
            "run storeargs;"\
            "run switch_bootmode;"
#define CONFIG_BOOTCOMMAND "run storeboot"

没有列出所有的,中间部分省略.......

CONFIG_EXTRA_ENV_SETTINGS: 定义的一些额外的env变量

CONFIG_PREBOOT:启动前执行的命令

CONFIG_BOOTCOMMAND:启动命令

我们分别解释下这几个命令:

CONFIG_BOOTCOMMAND "run storeboot"

 "storeboot="\
            "hdmitx output 1080p60hz;"\
            "if imgread kernel boot ${loadaddr}; then bootm ${loadaddr}; fi;"\
            "run update;"\
            "\0"\

设置hdmi输出为1080p60Hz,读取boot分区到${loadaddr}即0x1080000地址,然后从0x1080000地址启动boot,如果启动失败,则run update,走升级烧录流程。

CONFIG_PREBOOT \

"run bcb_cmd; "\

"run factory_reset_poweroff_protect;"\

"run upgrade_check;"\

"run init_display;"\

"run storeargs;"\

"run switch_bootmode;"

读取misc分区的bcb command,查看是否有进入recovery的标志

判断是否有恢复出厂过程掉电标志,如果有,则进入recovery继续执行恢复出厂设置

判断是否有升级掉电标志,如果有升级过程掉电,则进入recovery继续升级。

OSD初始化,显示开机logo

设置启动参数bootargs

根据bootmode,选择进入不同的系统(recovery,fastboot等)

board_f.c主要的功能就是完成board的前部分初始化工作,我们主要关心的是uboot env的初始化的,后部分board_r.c的流程我们下节再详细描述。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门