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主要乾的事就是在重定位之前規劃好內存的劃分,分析完這個函數最後能繪出內存圖就差不多明白這個階段了。 

 

歡迎掃碼關注我的微信公衆號

漫長當下
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章