u-boot2020.04移植(4、board_init_f)

接着上篇,执行了ldr pc, =_main后,就到arch/arm/lib/crt0.S文件了,本篇基本全是源码分析,是一个很枯燥的过程,如果你只想看修改的部分可直接搜索“修改”两个字,就能直接找到修改的地方,这个阶段只修改了三个地方:

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

/*未定义*/
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
	ldr	r0, =(CONFIG_TPL_STACK)
/*未定义*/
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	r0, =(CONFIG_SPL_STACK)
#else
	/*这里还是设置栈,但这个值和start.S中设置的是一样的值*/
	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0

我们画一个内存分布图,这样可以更好的理解后面u-boot的重定位:

图1

接下来调用board_init_f_alloc_reserve,位于common/init/board_init.c文件:

bl	board_init_f_alloc_reserve
/*又更改了一次栈*/
	mov	sp, r0
ulong board_init_f_alloc_reserve(ulong top)
{
	/* Reserve early malloc arena */
	/*定义了CONFIG_SYS_MALLOC_F_LEN,大小0x400*/
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
	top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
	/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
	/*sizeof(struct global_data)的大小定义在include/generated/generic-asm-offsets.h文件(自动生成的)*/
	top = rounddown(top-sizeof(struct global_data), 16);

	return top;
}

此函数又更改了sp的位置,现在内存分布如下:

图2

 调用board_init_f_init_reserve,主要干了两件事,将图2 sizeof(struct global_data)对应的区域清零,然后建立一个gd全局数据结构,并填充gd->malloc_base字段:

mov	r9, r0
	bl	board_init_f_init_reserve
void board_init_f_init_reserve(ulong base)
{
	struct global_data *gd_ptr;

	/*
	 * clear GD entirely and set it up.
	 * Use gd_ptr, as gd may not be properly set yet.
	 */

	gd_ptr = (struct global_data *)base;
	/* zero the area */
	memset(gd_ptr, '\0', sizeof(*gd));
	/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)
	arch_setup_gd(gd_ptr);
#endif

	/*未定义*/
	if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
		board_init_f_init_stack_protection_addr(base);

	/* next alloc will be higher by one GD plus 16-byte alignment */
	base += roundup(sizeof(struct global_data), 16);

	/*
	 * record early malloc arena start.
	 * Use gd as it is now properly set for all architectures.
	 */

#if CONFIG_VAL(SYS_MALLOC_F_LEN)
	/* go down one 'early malloc arena' */
	gd->malloc_base = base;
#endif

	/*未定义*/
	if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
		board_init_f_init_stack_protection();
}

gd这个全局变量的定义有点特殊,下面来看一下:

/*gd定义在common/board_f.c的顶部*/
#ifdef XTRN_DECLARE_GLOBAL_DATA_PTR/*未定义*/
#undef	XTRN_DECLARE_GLOBAL_DATA_PTR
#define XTRN_DECLARE_GLOBAL_DATA_PTR	/* empty = allocate here */
DECLARE_GLOBAL_DATA_PTR = (gd_t *)(CONFIG_SYS_INIT_GD_ADDR);
#else
DECLARE_GLOBAL_DATA_PTR;
#endif
/*此宏位于arch/arm/include/asm/global_data.h文件,原型如下,
这个是定义一个gd_t类型的指针,指针和r9这个寄存器绑定了,
也就是r9这个寄存器之后就不能用于别的用途了,调用board_init_f_init_reserve前,
将r0的值放到了r9里面,而r0指向的位置就是sizeof(struct global_data)对应的
那片内存区域的起始地址,所以r9当然就是gd这个数据结构的起始地址了*/
#define DECLARE_GLOBAL_DATA_PTR		register volatile gd_t *gd asm ("r9")

/*gd_t数据结构定义在include/asm-generic/global_data.h文件*/
typedef struct global_data {
	bd_t *bd;
	unsigned long flags;
	unsigned int baudrate;
	unsigned long cpu_clk;		/* CPU clock in Hz!		*/
	unsigned long bus_clk;
	/* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
	unsigned long pci_clk;
	unsigned long mem_clk;
	/*未定义*/
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) || defined(CONFIG_DM_VIDEO)
	unsigned long fb_base;		/* Base address of framebuffer mem */
#endif
/*未定义*/
#if defined(CONFIG_POST)
	unsigned long post_log_word;	/* Record POST activities */
	unsigned long post_log_res;	/* success of POST test */
	unsigned long post_init_f_time;	/* When post_init_f started */
#endif
/*未定义*/
#ifdef CONFIG_BOARD_TYPES
	unsigned long board_type;
#endif
	unsigned long have_console;	/* serial_init() was called */
	/*未定义*/
#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
	unsigned long precon_buf_idx;	/* Pre-Console buffer index */
#endif
	unsigned long env_addr;		/* Address  of Environment struct */
	unsigned long env_valid;	/* Environment valid? enum env_valid */
	unsigned long env_has_init;	/* Bitmask of boolean of struct env_location offsets */
	int env_load_prio;		/* Priority of the loaded environment */

	unsigned long ram_base;		/* Base address of RAM used by U-Boot */
	unsigned long ram_top;		/* Top address of RAM used by U-Boot */
	unsigned long relocaddr;	/* Start address of U-Boot in RAM */
	phys_size_t ram_size;		/* RAM size */
	unsigned long mon_len;		/* monitor len */
	unsigned long irq_sp;		/* irq stack pointer */
	unsigned long start_addr_sp;	/* start_addr_stackpointer */
	unsigned long reloc_off;
	struct global_data *new_gd;	/* relocated global data */

#ifdef CONFIG_DM
	struct udevice	*dm_root;	/* Root instance for Driver Model */
	struct udevice	*dm_root_f;	/* Pre-relocation root instance */
	struct list_head uclass_root;	/* Head of core tree */
#endif
/*未定义*/
#ifdef CONFIG_TIMER
	struct udevice	*timer;		/* Timer instance for Driver Model */
#endif

	const void *fdt_blob;		/* Our device tree, NULL if none */
	void *new_fdt;			/* Relocated FDT */
	unsigned long fdt_size;		/* Space reserved for relocated FDT */
	/*未定义*/
#ifdef CONFIG_OF_LIVE
	struct device_node *of_root;
#endif

/*未定义*/
#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
	const void *multi_dtb_fit;	/* uncompressed multi-dtb FIT image */
#endif
	struct jt_funcs *jt;		/* jump table */
	char env_buf[32];		/* buffer for env_get() before reloc. */
	/*未定义*/
#ifdef CONFIG_TRACE
	void		*trace_buff;	/* The trace buffer */
#endif
/*未定义*/
#if defined(CONFIG_SYS_I2C)
	int		cur_i2c_bus;	/* current used i2c bus */
#endif
	unsigned int timebase_h;
	unsigned int timebase_l;
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
	unsigned long malloc_base;	/* base address of early malloc() */
	unsigned long malloc_limit;	/* limit address */
	unsigned long malloc_ptr;	/* current address */
#endif
/*未定义*/
#ifdef CONFIG_PCI
	struct pci_controller *hose;	/* PCI hose for early use */
	phys_addr_t pci_ram_top;	/* top of region accessible to PCI */
#endif
/*未定义*/
#ifdef CONFIG_PCI_BOOTDELAY
	int pcidelay_done;
#endif
	struct udevice *cur_serial_dev;	/* current serial device */
	struct arch_global_data arch;	/* architecture-specific data */
	/*未定义*/
#ifdef CONFIG_CONSOLE_RECORD
	struct membuff console_out;	/* console output */
	struct membuff console_in;	/* console input */
#endif
/*未定义*/
#ifdef CONFIG_DM_VIDEO
	ulong video_top;		/* Top of video frame buffer area */
	ulong video_bottom;		/* Bottom of video frame buffer area */
#endif
/*未定义*/
#ifdef CONFIG_BOOTSTAGE
	struct bootstage_data *bootstage;	/* Bootstage information */
	struct bootstage_data *new_bootstage;	/* Relocated bootstage info */
#endif
/*未定义*/
#ifdef CONFIG_LOG
	int log_drop_count;		/* Number of dropped log messages */
	int default_log_level;		/* For devices with no filters */
	struct list_head log_head;	/* List of struct log_device */
	int log_fmt;			/* Mask containing log format info */
#endif

/*未定义*/
#if CONFIG_IS_ENABLED(BLOBLIST)
	struct bloblist_hdr *bloblist;	/* Bloblist information */
	struct bloblist_hdr *new_bloblist;	/* Relocated blolist info */
# ifdef CONFIG_SPL
	struct spl_handoff *spl_handoff;
# endif
#endif
/*未定义*/
#if defined(CONFIG_TRANSLATION_OFFSET)
	fdt_addr_t translation_offset;	/* optional translation offset */
#endif
/*未定义*/
#if CONFIG_IS_ENABLED(WDT)
	struct udevice *watchdog_dev;
#endif
} gd_t;

这里再建一张表,用于记录gd_t这个数据结构,未定义的不记录:

bd_t *bd;			
unsigned long flags;			
unsigned int baudrate;			
unsigned long cpu_clk;			
unsigned long bus_clk;			
			
unsigned long pci_clk;			
unsigned long mem_clk;			
unsigned long have_console;			
unsigned long env_addr;			
unsigned long env_valid;			
unsigned long env_has_init;			
int env_load_prio;			
			
unsigned long ram_base;			
unsigned long ram_top;			
unsigned long relocaddr;			
phys_size_t ram_size;			
unsigned long mon_len;			
unsigned long irq_sp;			
unsigned long start_addr_sp;			
unsigned long reloc_off;			
struct global_data *new_gd;			
struct udevice  *dm_root;			
struct udevice  *dm_root_f;			
struct list_head uclass_root;			
const void *fdt_blob;			
void *new_fdt;			
unsigned long fdt_size;			
struct jt_funcs *jt;			
char env_buf[32];			
unsigned int timebase_h;			
unsigned int timebase_l;			
unsigned long malloc_base;			
unsigned long malloc_limit;			
unsigned long malloc_ptr;			
struct udevice *cur_serial_dev;			
struct arch_global_data arch;			

新的内存分布图如下:

图3

正式进入board_init_f了,位于common/board_f.c:

/*未定义*/
#if defined(CONFIG_SPL_EARLY_BSS)
	SPL_CLEAR_BSS
#endif

	mov	r0, #0
	bl	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
}

填充了flags和have_console字段后就执行一个初始化列表循环,这个循环里面有很多的函数,只要其中一个出错,u-boot启动就会停止,initcall_run_list函数这里就不追进去看了(位于include/initcall.h),就是一个循环,直接看下需要循环执行哪些函数(由于这个列表太长了,未定义的这里就不列出来了):

/*虽然未定义的都删除了,但是还是有这么多*/
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,
	initf_console_record,
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,
	arch_cpu_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 */
	checkcpu,
	print_cpuinfo,		/* display cpu info (and speed) */
	show_board_info,
	INIT_FUNC_WATCHDOG_INIT
	INIT_FUNC_WATCHDOG_RESET
	announce_dram_init,
	dram_init,		/* configure available RAM banks */
	INIT_FUNC_WATCHDOG_RESET
	INIT_FUNC_WATCHDOG_RESET
	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,
	reserve_round_4k,
	reserve_mmu,
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_bloblist,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,
	display_new_sp,
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	reloc_bootstage,
	reloc_bloblist,
	setup_reloc,
	clear_bss,
	NULL,
};

一个函数一个函数的看:

/*common/board_f.c*/

static int setup_mon_len(void)
{
	/*__ARM__这个是编译的时候才给定的*/
#if defined(__ARM__) || defined(__MICROBLAZE__)
/*设置mon_len的值为整个u-boot的大小*/
	gd->mon_len = (ulong)&__bss_end - (ulong)_start;
/*
    省略
*/
	return 0;
}
/*lib/fdtdec.c*/

/*获取设备树存放的地址*/
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL)
/*未定义*/
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
	void *fdt_blob;
# endif
/*未定义*/
# ifdef CONFIG_OF_EMBED
	/* Get a pointer to the FDT */
#  ifdef CONFIG_SPL_BUILD
	gd->fdt_blob = __dtb_dt_spl_begin;
#  else
	gd->fdt_blob = __dtb_dt_begin;
#  endif
/*CONFIG_OF_SEPARATE定义了*/
# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
	/* Allow the board to override the fdt address. */
	/*这里设置设备树放的位置为u-boot的末尾,通过对比u-boot.bin和u-boot-nodtb.bin也可以证实这一点,board_fdt_blob_setup函数就在本文件,内容很简单,这里就不追进去了*/
	gd->fdt_blob = board_fdt_blob_setup();
# elif defined(CONFIG_OF_HOSTFILE)
	if (sandbox_read_fdt_from_file()) {
		puts("Failed to read control FDT\n");
		return -1;
	}
# elif defined(CONFIG_OF_PRIOR_STAGE)
	gd->fdt_blob = (void *)prior_stage_fdt_address;
# endif
# ifndef CONFIG_SPL_BUILD
	/* Allow the early environment to override the fdt address */
	/*如果环境变量定义了fdtcontroladdr,就重新设置设备树放置的位置,我们没有设置,所以使用默认值,还是上面设置的值*/
	gd->fdt_blob = map_sysmem
		(env_get_ulong("fdtcontroladdr", 16,
			       (unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
# endif
/*未定义*/
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
	/*
	 * Try and uncompress the blob.
	 * Unfortunately there is no way to know how big the input blob really
	 * is. So let us set the maximum input size arbitrarily high. 16MB
	 * ought to be more than enough for packed DTBs.
	 */
	if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
		gd->fdt_blob = fdt_blob;

	/*
	 * Check if blob is a FIT images containings DTBs.
	 * If so, pick the most relevant
	 */
	fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
	if (fdt_blob) {
		gd->multi_dtb_fit = gd->fdt_blob;
		gd->fdt_blob = fdt_blob;
	}

# endif
#endif

	/*没做什么,就是检查了一下设备树的头*/
	return fdtdec_prepare_fdt();
}
/*common/dlmalloc.c*/

/*堆相关的参数设置*/
int initf_malloc(void)
{
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
	assert(gd->malloc_base);	/* Set up by crt0.S */
	gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN);
	gd->malloc_ptr = 0;
#endif

	return 0;
}
/*include/log.h*/

/*log信息相关的*/
/*这个函数在common/log.c里面也有实现,但是头文件中由于宏的控制并没有声明,所以调用的实际上是下面的内联函数,什么也没做*/

#if CONFIG_IS_ENABLED(LOG)
/**
 * log_init() - Set up the log system ready for use
 *
 * @return 0 if OK, -ENOMEM if out of memory
 */
int log_init(void);
#else
static inline int log_init(void)
{
	return 0;
}
#endif
/*common/board_f.c*/
/*这个函数没有追进去的必要,基本最后全是空函数,主要就是用于显示当前u-boot运行的进度*/

static int initf_bootstage(void)
{
    /*
        省略
    */
}
/*common/board_f.c*/

static int setup_spl_handoff(void)
{
/*未定义*/
#if CONFIG_IS_ENABLED(HANDOFF)
	gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
					sizeof(struct spl_handoff));
	debug("Found SPL hand-off info %p\n", gd->spl_handoff);
#endif

	return 0;
}
/*common/board_f.c*/

static int initf_console_record(void)
{
	/*CONFIG_CONSOLE_RECORD未定义*/
#if defined(CONFIG_CONSOLE_RECORD) && CONFIG_VAL(SYS_MALLOC_F_LEN)
	return console_record_init();
#else
	return 0;
#endif
}
/*arch/arm/cpu/armv7/s5p-common/cpu_info.c*/

#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
	s5p_set_cpu_id();

	return 0;
}
#endif

-->

/*arch/arm/mach-s5pc1xx/include/mach/cpu.h*/

static inline void s5p_set_cpu_id(void)
{
	/*将CPU ID保存到s5p_cpu_id全局变量中*/
	s5p_cpu_id = readl(S5PC100_PRO_ID);
	s5p_cpu_rev = s5p_cpu_id & 0x000000FF;
	s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);
}
/*common/board_f.c*/

__weak int mach_cpu_init(void)
{
	return 0;
}
/*common/board_f.c*/

/*驱动模型相关的初始化,新版的u-boot引入的,以后专门的分析一下这部分*/
static int initf_dm(void)
{
#if defined(CONFIG_DM) && CONFIG_VAL(SYS_MALLOC_F_LEN)
	int ret;

	/*显示当前u-boot的进度,没有定义相关宏,不管*/
	bootstage_start(BOOTSTATE_ID_ACCUM_DM_F, "dm_f");
	ret = dm_init_and_scan(true);
	/*空函数*/
	bootstage_accum(BOOTSTATE_ID_ACCUM_DM_F);
	if (ret)
		return ret;
#endif
/*未定义*/
#ifdef CONFIG_TIMER_EARLY
	ret = dm_timer_init();
	if (ret)
		return ret;
#endif

	return 0;
}
/*common/board_f.c*/

__weak int arch_cpu_init_dm(void)
{
	return 0;
}
/*arch/arm/cpu/armv7/s5p-common/timer.c*/
/*这个在arch/arm/cpu/armv7/arch_timer.c里面也有定义,但是通过Makefile得知,是没有被编译的*/

int timer_init(void)
{
	/*初始化timer4,之后u-boot启动倒计时的时候需要*/
	/* PWM Timer 4 */
	pwm_init(4, MUX_DIV_4, 0);
	pwm_config(4, 100000, 100000);
	pwm_enable(4);

	/* Use this as the current monotonic time in us */
	gd->arch.timer_reset_value = 0;

	/* Use this as the last timer value we saw */
	gd->arch.lastinc = timer_get_us_down();
	reset_timer_masked();

	return 0;
}
/*env/env.c*/

/*环境变量初始化*/
int env_init(void)
{
	struct env_driver *drv;
	int ret = -ENOENT;
	int prio;

	/*遍历u-boot存放环境变量硬件驱动的那个段,取出相应的结构,然后执行初始化*/
	for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
		/*找到驱动后执行初始化操作,如果没有指定初始化函数(那可能已经初始化过硬件了)或者指定了初始化函数并且初始化成功就置位相应的标志位,表示环境变量的硬件驱动已经初始化了*/
		if (!drv->init || !(ret = drv->init()))
			env_set_inited(drv->location);

		debug("%s: Environment %s init done (ret=%d)\n", __func__,
		      drv->name, ret);
	}

	if (!prio)
		return -ENODEV;

	if (ret == -ENOENT) {
		/*因为env/mmc.c里面没有提供初始化函数,所以这里是满足条件的,设置环境变量为默认环境变量,并且标志环境变量可用*/
		gd->env_addr = (ulong)&default_environment[0];
		gd->env_valid = ENV_VALID;

		return 0;
	}

	return ret;
}

-->

static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
{
	enum env_location loc = env_get_location(op, prio);
	struct env_driver *drv;

	if (loc == ENVL_UNKNOWN)
		return NULL;

	/*这里就要去查找loc(也就是ENVL_MMC)对应的驱动了*/
	drv = _env_driver_lookup(loc);
	if (!drv) {
		debug("%s: No environment driver for location %d\n", __func__,
		      loc);
		return NULL;
	}

	return drv;
}

-->

__weak enum env_location env_get_location(enum env_operation op, int prio)
{
	/*env_locations定义在本文件中,是一个enum env_location类型的数组,
因为只定义了宏CONFIG_ENV_IS_IN_MMC,所以里面只有一个ENVL_MMC*/
	if (prio >= ARRAY_SIZE(env_locations))
		return ENVL_UNKNOWN;

	/*0*/
	gd->env_load_prio = prio;

	/*经过查表,返回值为ENVL_MMC*/
	return env_locations[prio];
}

-->

static struct env_driver *_env_driver_lookup(enum env_location loc)
{
	struct env_driver *drv;
	const int n_ents = ll_entry_count(struct env_driver, env_driver);
	struct env_driver *entry;

	/*这里遍历的是u-boot的一个段(从ll_entry_start得知),所有的存放环境变量的介质的硬件驱动都放在这个段,
	驱动直接搜的话是搜不到的,相关的文件都在env目录,比如这里是存放在MMC中,对应的驱动文件为env/mmc.c,
	通过U_BOOT_ENV_LOCATION宏定义*/
	drv = ll_entry_start(struct env_driver, env_driver);
	for (entry = drv; entry != drv + n_ents; entry++) {
		if (loc == entry->location)
			return entry;
	}

	/* Not found */
	return NULL;
}
/*common/board_f.c*/

static int init_baud_rate(void)
{
    /*从环境变量读取波特率,如果没有这个变量就设置为CONFIG_BAUDRATE*/
	gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE);
	return 0;
}
/*drivers/serial/serial-uclass.c*/

/*从Makefile得知,使用的serial-uclass.c文件,这是新引入驱动模型*/
ifdef CONFIG_DM_SERIAL
obj-y += serial-uclass.o
else
obj-y += serial.o
endif

int serial_init(void)
{
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
	/*在设备树中查找stdout-path或者console属性,并将其与驱动绑定起来,对设备树这块还不是很了解,没有深入的分析*/
	serial_find_console_or_panic();
	/*标记串口(终端)已经可用*/
	gd->flags |= GD_FLG_SERIAL_READY;
#endif

	return 0;
}
/*common/console.c*/

/* Called before relocation - use serial functions */
int console_init_f(void)
{
	/*标记终端可用*/
	gd->have_console = 1;

	/*静默终端,没有使用*/
	console_update_silent();

	/*空*/
	print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);

	return 0;
}
/*lib/display_options.c*/

int display_options(void)
{
	char buf[DISPLAY_OPTIONS_BANNER_LENGTH];

	/*显示当前的u-boot版本号*/
	display_options_get_banner(true, buf, sizeof(buf));
	printf("%s", buf);

	return 0;
}
/*common/board_f.c*/
/*显示bss段及u-boot的链接地址信息,但是没有开启输出调试信息,所以没有输出*/

static int display_text_info(void)
{
	/*都没有定义,要执行*/
#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP)
	ulong bss_start, bss_end, text_base;

	/*获取bss段的信息*/
	bss_start = (ulong)&__bss_start;
	bss_end = (ulong)&__bss_end;

#ifdef CONFIG_SYS_TEXT_BASE
	text_base = CONFIG_SYS_TEXT_BASE;
#else
	text_base = CONFIG_SYS_MONITOR_BASE;
#endif

	debug("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
	      text_base, bss_start, bss_end);
#endif

	return 0;
}
/*common/board_f.c*/

__weak int checkcpu(void)
{
	return 0;
}
/*arch/arm/cpu/armv7/s5p-common/cpu_info.c*/

int print_cpuinfo(void)
{
	const char *cpu_model;
	int len;

	/* For SoC with no real CPU ID in naming convention. */
	/*看设备树是否有cpu-model相关的描述,有的话就使用设备树中的*/
	cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
	if (cpu_model)
		printf("CPU:   %.*s @ ", len, cpu_model);
	else
		/*显示CPU型号*/
		printf("CPU:   %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);

	/*显示当前CPU时钟频率*/
	print_freq(get_arm_clk(), "\n");

	return 0;
}
/*common/board_info.c*/

int __weak show_board_info(void)
{
#ifdef CONFIG_OF_CONTROL
	DECLARE_GLOBAL_DATA_PTR;
	const char *model;

	/*从设备树中获取model这个属性*/
	model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);

	/*如果有的话就显示*/
	if (model)
		printf("Model: %s\n", model);
#endif

	/*board/samsung/goni/goni.c显示板子信息*/
	return checkboard();
}
/*common/board_f.c*/

static int announce_dram_init(void)
{
	/*表示要开始DRAM的一些初始化了*/
	puts("DRAM:  ");
	return 0;
}
/*board/samsung/goni/goni.c*/

int dram_init(void)
{
	/*将DRAM的大小填充到ram_size这个字段,由于我的板子只有两片DRAM(总共4片,因为每两片合并成了一片32bit的DRAM了,所以相当于两片),这里需要修改*/
	/*修改前*/
        /*gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE +
			PHYS_SDRAM_3_SIZE;*/
	/*修改后*/
	gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE;

	return 0;
}
/*common/board_f.c*/

/*设置重定位地址*/
static int setup_dest_addr(void)
{
	debug("Monitor len: %08lX\n", gd->mon_len);
	/*
	 * Ram is setup, size stored in gd !!
	 */
	debug("Ram size: %08lX\n", (ulong)gd->ram_size);
	/*未定义,是否隐藏DRAM的顶部一片内存*/
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
    /*
        省略
    */
	gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif
/*0x30000000,DRAM的基地址*/
#ifdef CONFIG_SYS_SDRAM_BASE
	gd->ram_base = CONFIG_SYS_SDRAM_BASE;
#endif
	/*设置ram_top的值*/
	gd->ram_top = gd->ram_base + get_effective_memsize();
	/*检查ram_top是不是小于内存基地址*/
	gd->ram_top = board_get_usable_ram_top(gd->mon_len);
	/*重定位地址设置为ram_top*/
	gd->relocaddr = gd->ram_top;
	debug("Ram top: %08lX\n", (ulong)gd->ram_top);
	/*未定义*/
    /*
        省略
    */
	return 0;
}

 执行到这里的内存图:

图4
/*common/board_f.c*/

static int reserve_round_4k(void)
{
	/*4k对齐*/
	gd->relocaddr &= ~(4096 - 1);
	return 0;
}

新的内存图如下:

图5 没有截取的没有变化
/*common/board_f.c*/

__weak int reserve_mmu(void)
{
	/*都没有定义,要执行*/
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
	/* reserve TLB table */
	/*arch/arm/include/asm/system.h*/
	gd->arch.tlb_size = PGTABLE_SIZE;
	gd->relocaddr -= gd->arch.tlb_size;

	/*保留页表的内存,保留64K*/
	/* round down to next 64 kB limit */
	gd->relocaddr &= ~(0x10000 - 1);

	/*设置页表的地址*/
	gd->arch.tlb_addr = gd->relocaddr;
	debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
	      gd->arch.tlb_addr + gd->arch.tlb_size);

/*未定义,安全启动相关*/
/*
    省略
*/
#endif

	return 0;
}

新的内存图如下:

图6
/*common/board_f.c*/

static int reserve_video(void)
{
/*未定义*/
#ifdef CONFIG_DM_VIDEO
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reserve_trace(void)
{
/*未定义*/
#ifdef CONFIG_TRACE
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reserve_uboot(void)
{
	if (!(gd->flags & GD_FLG_SKIP_RELOC)) {
		/*
		 * reserve memory for U-Boot code, data & bss
		 * round down to next 4 kB limit
		 */
		/*mon_len这个字段在前面已经填充了,也就是整个u-boot的大小*/
		gd->relocaddr -= gd->mon_len;
		/*4K对齐*/
		gd->relocaddr &= ~(4096 - 1);
		/*未定义*/
	#if defined(CONFIG_E500) || defined(CONFIG_MIPS)
		/* round down to next 64 kB limit so that IVPR stays aligned */
		gd->relocaddr &= ~(65536 - 1);
	#endif

		debug("Reserving %ldk for U-Boot at: %08lx\n",
		      gd->mon_len >> 10, gd->relocaddr);
	}

	/*用于栈*/
	gd->start_addr_sp = gd->relocaddr;

	return 0;
}

新的内存图如下:

图7
/*common/board_f.c*/

static int reserve_malloc(void)
{
	/*保留堆内存CONFIG_SYS_MALLOC_LEN = CONFIG_ENV_SIZE + (80 << 20),CONFIG_ENV_SIZE+80M*/
	gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
	debug("Reserving %dk for malloc() at: %08lx\n",
	      TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
		  /*未定义*/
#ifdef CONFIG_SYS_NONCACHED_MEMORY
	reserve_noncached();
#endif

	return 0;
}

新的内存图如下:

图8
/*common/board_f.c*/

static int reserve_board(void)
{
	/*为gd->bd保留内存,bd也是一个结构体,用于保存板子的一些信息*/
	if (!gd->bd) {
		gd->start_addr_sp -= sizeof(bd_t);
		gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
		memset(gd->bd, '\0', sizeof(bd_t));
		debug("Reserving %zu Bytes for Board Info at: %08lx\n",
		      sizeof(bd_t), gd->start_addr_sp);
	}
	return 0;
}

新的内存图如下:

图9

这里又看见了一个新的有用的数据结构,将其记录下来,未定义的没有列出来:

/*include/asm-generic/u-boot.h*/

unsigned long   bi_memstart;			
phys_size_t bi_memsize;			
unsigned long   bi_flashstart;			
unsigned long   bi_flashsize;			
unsigned long   bi_flashoffset;			
unsigned long   bi_sramstart;			
unsigned long   bi_sramsize;			
unsigned long   bi_arm_freq;			
unsigned long   bi_dsp_freq;			
unsigned long   bi_ddr_freq;			
unsigned long   bi_bootflags;			
unsigned long   bi_ip_addr;			
unsigned char  bi_enetaddr[6];			
unsigned short  bi_ethspeed;			
unsigned long   bi_intfreq;			
unsigned long   bi_busfreq;			
ulong           bi_arch_number;			
ulong           bi_boot_params;			
struct {			
    phys_addr_t start;			
    phys_size_t size;			
} bi_dram[CONFIG_NR_DRAM_BANKS];			
/*common/board_f.c*/

static int setup_machine(void)
{
	/*未定义,这个在board_init_r中会设置*/
#ifdef CONFIG_MACH_TYPE
	gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif
	return 0;
}
/*common/board_f.c*/

static int reserve_global_data(void)
{
	/*为gd_t这个数据结构保留内存*/
	gd->start_addr_sp -= sizeof(gd_t);
	gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
	debug("Reserving %zu Bytes for Global Data at: %08lx\n",
	      sizeof(gd_t), gd->start_addr_sp);
	return 0;
}
图10
/*common/board_f.c*/

static int reserve_fdt(void)
{
	/*未定义*/
#ifndef CONFIG_OF_EMBED
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reserve_bootstage(void)
{
	/*未定义*/
#ifdef CONFIG_BOOTSTAGE
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reserve_bloblist(void)
{
/*未定义*/
#ifdef CONFIG_BLOBLIST
	省略
#endif

	return 0;
}
/*common/board_f.c*/

__weak int reserve_arch(void)
{
	return 0;
}
/*common/board_f.c*/

static int reserve_stacks(void)
{
	/*16字节对齐*/
	/* make stack pointer 16-byte aligned */
	gd->start_addr_sp -= 16;
	gd->start_addr_sp &= ~0xf;

	/*
	 * let the architecture-specific code tailor gd->start_addr_sp and
	 * gd->irq_sp
	 */
	/*arch/arm/lib/stack.c*/
	return arch_reserve_stacks();
}

-->

/*arch/arm/lib/stack.c*/

int arch_reserve_stacks(void)
{
	/*未定义*/
#ifdef CONFIG_SPL_BUILD
	gd->start_addr_sp -= 128;	/* leave 32 words for abort-stack */
	gd->irq_sp = gd->start_addr_sp;
#else
	/* setup stack pointer for exceptions */
	/*设置irq的栈指针*/
	gd->irq_sp = gd->start_addr_sp;

# if !defined(CONFIG_ARM64)
	/*保留3个字给abort-stack,再加1字节对齐*/
	/* leave 3 words for abort-stack, plus 1 for alignment */
	gd->start_addr_sp -= 16;
# endif
#endif

	return 0;
}

新的内存图如下,这里有点疑惑,貌似irq栈不止3个字的大小,但这里只保留了三个字:

图11
/*board/samsung/goni/goni.c*/

int dram_init_banksize(void)
{
	/*我的板子只有两片内存*/
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
	gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
	/*删掉下面这一块内存*/
	/*
	gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
	gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
	*/

	return 0;
}

/*这里顺便修改一下DDR的配置,现在的DDR配置是三星的goni这块板子,要修改成我们的板子,修改include/configs/s5p_goni.h头文件*/
#if 0/*修改前*/
/* Goni has 3 banks of DRAM, but swap the bank */
#define PHYS_SDRAM_1		CONFIG_SYS_SDRAM_BASE	/* OneDRAM Bank #0 */
#define PHYS_SDRAM_1_SIZE	(80 << 20)		/* 80 MB in Bank #0 */
#define PHYS_SDRAM_2		0x40000000		/* mDDR DMC1 Bank #1 */
#define PHYS_SDRAM_2_SIZE	(256 << 20)		/* 256 MB in Bank #1 */
#define PHYS_SDRAM_3		0x50000000		/* mDDR DMC2 Bank #2 */
#define PHYS_SDRAM_3_SIZE	(128 << 20)		/* 128 MB in Bank #2 */
#else/*修改后*/
#define PHYS_SDRAM_1		CONFIG_SYS_SDRAM_BASE	/* OneDRAM Bank #0 */
#define PHYS_SDRAM_1_SIZE	(256 << 20)		/* 256 MB in Bank #0 */
#define PHYS_SDRAM_2		0x40000000		/* mDDR DMC1 Bank #1 */
#define PHYS_SDRAM_2_SIZE	(256 << 20)		/* 256 MB in Bank #1 */
#endif
/*common/board_f.c*/

static int show_dram_config(void)
{
	unsigned long long size;

/*显示DDR的信息*/
#ifdef CONFIG_NR_DRAM_BANKS
	int i;

	debug("\nRAM Configuration:\n");
	for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
		size += gd->bd->bi_dram[i].size;
		debug("Bank #%d: %llx ", i,
		      (unsigned long long)(gd->bd->bi_dram[i].start));
#ifdef DEBUG
		print_size(gd->bd->bi_dram[i].size, "\n");
#endif
	}
	debug("\nDRAM:  ");
#else
	size = gd->ram_size;
#endif

	print_size(size, "");
	board_add_ram_info(0);
	putc('\n');

	return 0;
}
/*common/board_f.c*/

static int display_new_sp(void)
{
	debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);

	return 0;
}
/*common/board_f.c*/

static int reloc_fdt(void)
{
/*未定义*/
#ifndef CONFIG_OF_EMBED
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reloc_bootstage(void)
{
/*未定义*/
#ifdef CONFIG_BOOTSTAGE
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int reloc_bloblist(void)
{
/*未定义*/
#ifdef CONFIG_BLOBLIST
	省略
#endif

	return 0;
}
/*common/board_f.c*/

static int setup_reloc(void)
{
	if (gd->flags & GD_FLG_SKIP_RELOC) {
		debug("Skipping relocation due to flag\n");
		return 0;
	}

#ifdef CONFIG_SYS_TEXT_BASE
#ifdef ARM
	/*计算u-boot重定位的偏移值*/
	gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
#elif defined(CONFIG_M68K)
	/*
	 * On all ColdFire arch cpu, monitor code starts always
	 * just after the default vector table location, so at 0x400
	 */
	gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
#elif !defined(CONFIG_SANDBOX)
	gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
#endif
#endif
	/*将gd拷贝到新的地址*/
	memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));

	debug("Relocation Offset is: %08lx\n", gd->reloc_off);
	debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
	      gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
	      gd->start_addr_sp);

	return 0;
}

新的内存图如下:

图12
/*common/board_f.c*/

__weak int clear_bss(void)
{
	return 0;
}

到了这里board_init_f这个循环就结束了,下面将前面提到的两个重要的数据结构贴出来,有些值没有填进去,可能是我忘记填了,也有一些是还没出现的:

gd_t:

bd_t *bd;     指向gd_t这个数据结构      
unsigned long flags;   0 > GD_FLG_SERIAL_READY  
unsigned int baudrate;   115200          
unsigned long cpu_clk;              
unsigned long bus_clk;              
                   
unsigned long pci_clk;              
unsigned long mem_clk;              
unsigned long have_console; 0 > 1      
unsigned long env_addr;   default_environment      
unsigned long env_valid;   ENV_VALID        
unsigned long env_has_init; 设置为对应的存放环境变量介质的枚举值    
int env_load_prio;   ENVL_MMC          
                   
unsigned long ram_base;   CONFIG_SYS_SDRAM_BASE      
unsigned long ram_top;   ram_base+ram_size        
unsigned long relocaddr;   参考内存图        
phys_size_t ram_size;   设置为DRAM的大小        
unsigned long mon_len;   __bss_end - _start      
unsigned long irq_sp;   参考内存图        
unsigned long start_addr_sp; 参考内存图        
unsigned long reloc_off;   gd->relocaddr - (unsigned long)__image_copy_start
struct global_data *new_gd; 参考内存图        
struct udevice  *dm_root;              
struct udevice  *dm_root_f;            
struct list_head uclass_root;            
const void *fdt_blob;   _end          
void *new_fdt;                
unsigned long fdt_size;              
struct jt_funcs *jt;              
char env_buf[32];                
unsigned int timebase_h;              
unsigned int timebase_l;              
unsigned long malloc_base; 参考内存图          
unsigned long malloc_limit; CONFIG_SYS_MALLOC_F_LEN      
unsigned long malloc_ptr;   0          
struct udevice *cur_serial_dev;            
struct arch_global_data arch;            

bd_t: 

unsigned long   bi_memstart;        
phys_size_t bi_memsize;          
unsigned long   bi_flashstart;        
unsigned long   bi_flashsize;        
unsigned long   bi_flashoffset;        
unsigned long   bi_sramstart;        
unsigned long   bi_sramsize;        
unsigned long   bi_arm_freq;        
unsigned long   bi_dsp_freq;        
unsigned long   bi_ddr_freq;        
unsigned long   bi_bootflags;        
unsigned long   bi_ip_addr;        
unsigned char  bi_enetaddr[6];        
unsigned short  bi_ethspeed;        
unsigned long   bi_intfreq;        
unsigned long   bi_busfreq;        
ulong           bi_arch_number; MACH_TYPE_SMDKV210  
ulong           bi_boot_params;        
struct {              
    phys_addr_t start;   0x30000000 0x40000000
    phys_size_t size;   256M   256M  
} bi_dram[CONFIG_NR_DRAM_BANKS];        

总结一下:对于board_init_f主要干的事就是在重定位之前规划好内存的划分,分析完这个函数最后能绘出内存图就差不多明白这个阶段了。 

欢迎扫码关注我的微信公众号

漫长当下

猜你喜欢

转载自blog.csdn.net/a1598025967/article/details/106960642