从零开始之uboot、移植uboot2017.01(五、board_init_f分析)

接着第四节的继续分析,下面的是整个uboot前半部分的核心。


/*
 * entry point of crt0 sequence
 */

ENTRY(_main)

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

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)    /* 我们没定义这个 */

	ldr	sp, =(CONFIG_SPL_STACK)
#else
    /* 在s5pv210.h中定义,上一节有分析,0x33000000 */
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination 没定义 不用分析*/
	mov	r3, sp
	bic	r3, r3, #7
	mov	sp, r3
#else
	bic	sp, sp, #7	    /* 8-byte alignment for ABI compliance,sp 8字节对齐,我们本就是对齐的*/
#endif
	mov	r0, sp          /* 把上面的0x33000000,作为参数传给下面c函数 */          
	bl	board_init_f_alloc_reserve
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0          /* r0即当前sp给r9,  r9是gd全局变量的指针,同时作为参数传递给下面函数 */
	bl	board_init_f_init_reserve

	mov	r0, #0
	bl	board_init_f    /* 把参数0,传给下面函数,并调用它 */

#if ! defined(CONFIG_SPL_BUILD)        /* 没定义,所以下面的要执行,先分析完前面的,再分析后面的 */

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */

	ldr	sp, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
#if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination */
	mov	r3, sp
	bic	r3, r3, #7
	mov	sp, r3
#else
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
#endif
	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
	sub	r9, r9, #GD_SIZE		/* new GD is below bd */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0					/* lr = new_uboot-old_uboot + here */
#if defined(CONFIG_CPU_V7M)
	orr	lr, #1				/* As required by Thumb-only */
#endif
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code
here:
/*
 * now relocate vectors
 */

	bl	relocate_vectors

/* Set up final (full) environment */

	bl	c_runtime_cpu_setup	/* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
# ifdef CONFIG_SPL_BUILD
	/* Use a DRAM stack for the rest of SPL, if requested */
	bl	spl_relocate_stack_gd
	cmp	r0, #0
	movne	sp, r0
	movne	r9, r0
# endif
	ldr	r0, =__bss_start	/* this is auto-relocated! */

#ifdef CONFIG_USE_ARCH_MEMSET
	ldr	r3, =__bss_end		/* this is auto-relocated! */
	mov	r1, #0x00000000		/* prepare zero to clear BSS */

	subs	r2, r3, r0		/* r2 = memset len */
	bl	memset
#else
	ldr	r1, =__bss_end		/* this is auto-relocated! */
	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l:cmp	r0, r1			/* while not at end of BSS */
#if defined(CONFIG_CPU_V7M)
	itt	lo
#endif
	strlo	r2, [r0]		/* clear 32-bit BSS word */
	addlo	r0, r0, #4		/* move to next */
	blo	clbss_l
#endif

#if ! defined(CONFIG_SPL_BUILD)
	bl coloured_LED_init
	bl red_led_on
#endif
	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
#if defined(CONFIG_SYS_THUMB_BUILD)
	ldr	lr, =board_init_r	/* this is auto-relocated! */
	bx	lr
#else
	ldr	pc, =board_init_r	/* this is auto-relocated! */
#endif
	/* we should not return here. */
#endif

ENDPROC(_main)

在board_init_f_alloc_reserve函数之前的状态sp

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第1张图片

 

1.board_init_f_alloc_reserve

ulong board_init_f_alloc_reserve(ulong top)
{
	/* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F)    /* 我有定义这个宏,是0x400 */
	top -= CONFIG_SYS_MALLOC_F_LEN;
#endif
	/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
	top = rounddown(top-sizeof(struct global_data), 16);    /* 再次16字节对齐 */

	return top;
}

搜索uboot下面的.config可以确认

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第2张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第3张图片

 

#define DECLARE_GLOBAL_DATA_PTR		register volatile gd_t *gd asm ("r9")

上面这句话是定义一个寄存器全局变量指针,指定使用的寄存器是r9,类型为gd_t

gd_t是下面的这个结构体,因为我们没定义整个全局结构体变量,所以自己指定位置做这个结构体的存放地

/*
 * The following data structure is placed in some memory which is
 * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
 * some locked parts of the data cache) to allow for a minimum set of
 * global variables during system initialization (until we have set
 * up the memory controller so that we can use RAM).
 *
 * Keep it *SMALL* and remember to set GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
 *
 * Each architecture has its own private fields. For now all are private
 */

#ifndef __ASSEMBLY__
#include 
#include 

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)
	unsigned long fb_base;		/* Base address of framebuffer mem */
#endif
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
	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;	/* Checksum of Environment valid? */

	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 */
	struct jt_funcs *jt;		/* jump table */
	char env_buf[32];		/* buffer for getenv() 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
#ifdef CONFIG_SYS_I2C_MXC
	void *srdata[10];
#endif
	unsigned long timebase_h;
	unsigned long timebase_l;
#ifdef CONFIG_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
} gd_t;
#endif

2.board_init_f_init_reserve


void board_init_f_init_reserve(ulong base)
{
	struct global_data *gd_ptr;
#ifndef _USE_MEMCPY        /* 是否使用memcopy函数,通过meke menuconfig配置 */
	int *ptr;
#endif

	/*
	 * 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 把gd_t大小空间的内存置位0 */
#ifdef _USE_MEMCPY
	memset(gd_ptr, '\0', sizeof(*gd));
#else
    /* 如果使用这种方式,gd_ptr + 1是指针+1,即增加一个struct  global_data类型  */
	for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
		*ptr++ = 0;
#endif
	/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)    /* 咱们是ARM,所以不用管 */
	arch_setup_gd(gd_ptr);
#endif
	/* next alloc will be higher by one GD plus 16-byte alignment */
	base += roundup(sizeof(struct global_data), 16);        /* global_data大小以16字节向上对齐 */

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

#if defined(CONFIG_SYS_MALLOC_F)
	/* go down one 'early malloc arena' */
	gd->malloc_base = base;
	/* next alloc will be higher by one 'early malloc arena' size */
	base += CONFIG_SYS_MALLOC_F_LEN;
#endif
}

下面的gd_t是16字节向上对齐的。

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第4张图片

 

3.board_init_f

DECLARE_GLOBAL_DATA_PTR;  //注意这里声明了gd指针,下面就可以使用了


void board_init_f(ulong boot_flags)
{
#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA    /* 这个我们没定义 */
	/*
	 * For some architectures, global data is initialized and used before
	 * calling this function. The data should be preserved. For others,
	 * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
	 * here to host global data until relocation.
	 */
	gd_t data;       

	gd = &data;

	/*
	 * Clear global data before it is accessed at debug print
	 * in initcall_run_list. Otherwise the debug print probably
	 * get the wrong value of gd->have_console.
	 */
	zero_global_data();
#endif


	gd->flags = boot_flags;      /* flag = 0 */
	gd->have_console = 0;        /* 标记console未初始化 */

	if (initcall_run_list(init_sequence_f))    /* 调用这个函数初始化uboot的前半段 */
		hang();

#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!defined(CONFIG_EFI_APP)
	/* NOTREACHED - jump_to_copy() does not return */
	hang();
#endif
}

做一个表格把常用的gd_t填充在里面,已被后面分析使用

bd_t  
flag 0
baudrate  
cpu_clk  
bus_clk  
pci_clk  
mem_clk  
have_console 0
env_addr  
env_valid  
ram_top  
relocaddr  
ram_size  
mon_len  
irq_sp  
start_addr_sp  
reloc_off  
new_gd  
fdt_blob  
fdt_blob  
new_fdt  
fdt_size  
jt  
env_buf  

3.initcall_run_list


DECLARE_GLOBAL_DATA_PTR;

int initcall_run_list(const init_fnc_t init_sequence[])
{
	const init_fnc_t *init_fnc_ptr;
    
    /* 循环执行函数指针数组里面放的每个函数 */
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		unsigned long reloc_ofs = 0;
		int ret;

		if (gd->flags & GD_FLG_RELOC)
			reloc_ofs = gd->reloc_off;
#ifdef CONFIG_EFI_APP        /* 我们没定义,所以后面elf相关的都不再分析 */
		reloc_ofs = (unsigned long)image_base;
#endif
		debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
		if (gd->flags & GD_FLG_RELOC)
			debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);
		else
			debug("\n");
		ret = (*init_fnc_ptr)();    /* 执行函数 */
		if (ret) {
			printf("initcall sequence %p failed at call %p (err=%d)\n",
			       init_sequence,
			       (char *)*init_fnc_ptr - reloc_ofs, ret);
			return -1;
		}
	}
	return 0;
}

3.1、init_sequence_f初始化uboot的前半段


static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX                                             /* 没定义不分析 */   
	setup_ram_buf,        
#endif
	setup_mon_len,                                                /* 设置gd->mon_len为编译出来的u-boot.bin+bss段的大小 */
#ifdef CONFIG_OF_CONTROL                                          /* 定义了,设备树相关,先不分析 */
	fdtdec_setup,
#endif
#ifdef CONFIG_TRACE                                               /* 没定义 */
	trace_early_init,
#endif
	initf_malloc,                                                 /* 设置内存池的大小 */
	initf_console_record,                                         /* 平台信息记录初始化 */
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)            /* 没定义 */
	/* TODO: can this go into arch_cpu_init()? */
	probecpu,
#endif
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)               /* 没定义 */
	x86_fsp_init,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,                                                     /* dm 初始化 */
	arch_cpu_init_dm,
	mark_bootstage,		/* need timer, go after init dm */
#if defined(CONFIG_BOARD_EARLY_INIT_F)                            /* 没定义 */
	board_early_init_f,                                           /* 时钟和GPIO口设置 */   
#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) || \            /* 定义arm了 */
		defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \
		defined(CONFIG_SH) || defined(CONFIG_SPARC)
	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
#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)        CONFIG_SYS_FSL_CLK
	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
	display_options,	    /* say that we are here 打印当前banner 信息 */
	display_text_info,	    /* show debugging info if required 显示 debug 信息 */
#if defined(CONFIG_MPC8260)                                    /* 没定义 */
	prt_8260_rsr,
	prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)                                    /* 没定义 */
	prt_83xx_rsr,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SH)  /* 没定义 */
	checkcpu,
#endif
	print_cpuinfo,		    /* display cpu info (and speed)显示CPU信息 */
#if defined(CONFIG_MPC5xxx)                                    /* 没定义 */
	prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)                           /* 定义了 */
	show_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,                                        /* 准备显示 DRAM 大小 */
	/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \
		defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || \
		defined(CONFIG_SH)                                     /* 定义arm 了 */
	dram_init,		/* configure available RAM banks DRAM 初始化,打印DRAM大小*/
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)  /* 没定义 */
	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,                                                  /* 设置重定位地址,gd->relocaddr  */
#if defined(CONFIG_BLACKFIN) || defined(CONFIG_XTENSA)                /* 没定义 */
	/* Blackfin u-boot monitor should be on top of the ram */
	reserve_uboot,    
#endif
#if defined(CONFIG_SPARC)                                            /* 没定义 */
	reserve_prom,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)        /* 没定义 */
	reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM                                                   /* 没定义 */ 
	reserve_pram,
#endif
	reserve_round_4k,                                                /* 4 字节对齐 */
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
		defined(CONFIG_ARM)                                        /* 这里要执行 */
	reserve_mmu,                                                    /* 预留 MMU 区域 */
#endif
#ifdef CONFIG_DM_VIDEO                                             /* 没定义 */ 
	reserve_video,                                                /* 预留 video 区 */
#else
# ifdef CONFIG_LCD                                                 /* 没定义 */ 
	reserve_lcd,
# endif
	/* 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) && !defined(CONFIG_M68K)         /* 没定义 */ 
	reserve_legacy_video,
# endif
#endif /* CONFIG_DM_VIDEO */                                     /* 没定义 */ 
	reserve_trace,
#if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_XTENSA)  /* 没定义,要执行 */ 
	reserve_uboot,                                                /* 预留 uboot 区,gd->start_addr_sp = gd->relocaddr -= gd->mon_len  */
#endif
#ifndef CONFIG_SPL_BUILD                                        /* 没定义 */ 
	reserve_malloc,                                            /* 预留堆区 gd->start_addr_sp 指向 malloc 段基地址*/
	reserve_board,                                             /* board 信息结构体分配区域 栈 gd->start_addr_sp 指向 bd 段 基地址*/
#endif
	setup_machine,                                            /* 板子ID 如果定义则有,我们没有 */ */
	reserve_global_data,                                      /* 预留 GD 区域,栈 gd->start_addr_sp 指向 gd 段 基地址*/
	reserve_fdt,                                              /* 预留设备树区域 */
	reserve_arch,                                             /* 架构相关预留区 */
	reserve_stacks,                                           /* 栈区预留区,gd->start_addr_sp 指向 栈底基地址 */
	setup_dram_config,                                        /* DRAM 的大小初始化 */
	show_dram_config,                                        /* 显示 DRAM 的配置 */
#if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
	defined(CONFIG_SH)                                            /* 没定义 */ 
	setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)                    /* 没定义 */ 
	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,                                                   /* 建立重定向,设置 gd->rellocoff和新gd */
#if defined(CONFIG_X86) || defined(CONFIG_ARC)                    /* 没定义 */ 
	copy_uboot_to_ram,
	clear_bss,
	do_elf_reloc_fixups,
#endif
#if defined(CONFIG_XTENSA)                                        /* 没定义 */ 
	clear_bss,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)              /* 不执行 */ 
	jump_to_copy,
#endif
	NULL,
};

现在就先逐个分析,其实现的功能

 

在分析之前,我先列出来连接脚本中每个段的标记,方便下面使用到的时候过来查询。

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第5张图片

 

3.1.1、setup_mon_len

/* _start为我们的.text的首地址
 * _bss_end为我们uboot包含所有段的结束地址
*/

static int setup_mon_len(void)
{
#if defined(__ARM__) || defined(__MICROBLAZE__)
	gd->mon_len = (ulong)&__bss_end - (ulong)_start;        /* 得到uboot的总长度 */
#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP)
	gd->mon_len = (ulong)&_end - (ulong)_init;
#elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2) || \
	defined(CONFIG_XTENSA)
	gd->mon_len = CONFIG_SYS_MONITOR_LEN;
#elif defined(CONFIG_NDS32) || defined(CONFIG_SH)
	gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
#elif defined(CONFIG_SYS_MONITOR_BASE)
	/* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
	gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
#endif
	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第6张图片

3.1.2、initf_malloc内存池大小

int initf_malloc(void)
{
#ifdef CONFIG_SYS_MALLOC_F_LEN
	assert(gd->malloc_base);	/* Set up by crt0.S */
	gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;    /* 我们这里是0x400 */
	gd->malloc_ptr = 0;
#endif

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第7张图片

3.1.3、initf_console_record

static int initf_console_record(void)
{
/* CONFIG_CONSOLE_RECORD这个我们没定义 */
#if defined(CONFIG_CONSOLE_RECORD) && defined(CONFIG_SYS_MALLOC_F_LEN)
	return console_record_init();
#else
	return 0;
#endif
}

3.1.4、arch_cpu_init

/* S5PC100_PRO_ID 地址是0xe0000000 */
/* 我们最终计算完出来是0xC110 */
static inline void s5p_set_cpu_id(void)
{
	s5p_cpu_id = readl(S5PC100_PRO_ID);
	s5p_cpu_rev = s5p_cpu_id & 0x000000FF;
	s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);
}


int arch_cpu_init(void)
{
	s5p_set_cpu_id();

	return 0;
}

3.1.5、timer_init

int timer_init(void)
{
	/* 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;
}

3.1.6、env_init

int env_init(void)
{
    /* 默认环境变量初始化 */
	gd->env_addr	= (ulong)&default_environment[0];
	gd->env_valid	= 0;

	return 0;
}

3.1.7、初始化波特率,是从环境变量里面找,找不到了用后面的默认值,我们都是115200

static int init_baud_rate(void)
{
    /* 设置波特率值,CONFIG_BAUDRATE是我们在smdkv210里面定义的115200 */
	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第8张图片

3.1.8、serial_init

/* Called prior to relocation */
int serial_init(void)
{
	serial_find_console_or_panic();    /* 通过设备树方式初始化串口 */
	gd->flags |= GD_FLG_SERIAL_READY;    /* 标记串口初始化ready */

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第9张图片

3.1.9、console_init_f

int console_init_f(void)
{
	gd->have_console = 1;

	console_update_silent();    /* 设置flag,表明要不要静默控制台,我们没配置,不管 */
    /* 如果有配置早期console,会把要发送的数据存储在一个buf中,这里统一输出,我们前面都没使用过标准的输出,所以这里对我们没用到 */
	print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);    

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第10张图片

3.1.10、display_options 

#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
	U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING

//我们的这个定义为空

int display_options (void)
{
#if defined(BUILD_TAG)        /* 我们没定义BUILD_TAG,所以不打印编译标签 */
	printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG);
#else
	printf ("\n\n%s\n\n", version_string);
#endif
	return 0;
}

实际上面的函数,作用如下图的红框

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第11张图片

3.1.11、print_cpuinfo

#define S5P_CPU_NAME		"S5P"

static inline char *s5p_get_cpu_name(void)
{
	return S5P_CPU_NAME;
}


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

	/* For SoC with no real CPU ID in naming convention. */
	cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
	if (cpu_model)
		printf("CPU:   %.*s @ ", len, cpu_model);
	else    /* 我们使用下面这个的 */
        /* 可以通过上面的函数看到,会打印出"CPU:   S5PC110",s5p_cpu_id是前面判断cpu时确定的 */
		printf("CPU:   %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
    
    /* 前面没有换行,所以时钟继续跟在后面打印 */
	print_freq(get_arm_clk(), "\n");

	return 0;
}

可以看到CPU时钟1G,说明我们前面自己改的时钟初始化没问题。

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第12张图片

3.1.12、show_board_info

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

	model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);    /* 设备树得到一些板子信息 */

	if (model)
		printf("Model: %s\n", model);
#endif

	return checkboard();
}

int checkboard(void)
{
	puts("Board:\tGoni\n");        /* 后面我们把这个改了,改成SMDKV210 */
	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第13张图片

 

3.1.13、announce_dram_init

static int announce_dram_init(void)
{
	puts("DRAM:  ");        /* 打印出"DRAM:  "*/
	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第14张图片

3.1.14、dram_init

int dram_init(void)
{
    /* 已经配置过来了,2块256Mddr */
	gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE ;

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第15张图片

3.1.15、setup_dest_addr

__weak phys_size_t board_reserve_ram_top(phys_size_t ram_size)
{
#ifdef CONFIG_SYS_MEM_TOP_HIDE        /* 没定义 */
	return ram_size - CONFIG_SYS_MEM_TOP_HIDE;
#else
	return ram_size;                /* 返回512M  0x20000000 */ 
#endif
}


__weak ulong board_get_usable_ram_top(ulong total_size)
{
#ifdef CONFIG_SYS_SDRAM_BASE
	/*
	 * Detect whether we have so much RAM that it goes past the end of our
	 * 32-bit address space. If so, clip the usable RAM so it doesn't.
	 */
	if (gd->ram_top < CONFIG_SYS_SDRAM_BASE) 
		/*
		 * Will wrap back to top of 32-bit space when reservations
		 * are made.
		 */
		return 0;
#endif
	return gd->ram_top;        /* 我们返回这里0x50000000 */
}


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);
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE        /* 没定义 */
	/* Reserve memory for secure MMU tables, and/or security monitor */
	gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE;
	/*
	 * Record secure memory location. Need recalcuate if memory splits
	 * into banks, or the ram base is not zero.
	 */
	gd->arch.secure_ram = gd->ram_size;
#endif
	/*
	 * Subtract specified amount of memory to hide so that it won't
	 * get "touched" at all by U-Boot. By fixing up gd->ram_size
	 * the Linux kernel should now get passed the now "corrected"
	 * memory size and won't touch it either. This has been used
	 * by arch/powerpc exclusively. Now ARMv8 takes advantage of
	 * thie mechanism. If memory is split into banks, addresses
	 * need to be calculated.
	 */
    /* 从前面的函数,我们记录的表格查询ram_size = 512M */
	gd->ram_size = board_reserve_ram_top(gd->ram_size);

#ifdef CONFIG_SYS_SDRAM_BASE
	gd->ram_top = CONFIG_SYS_SDRAM_BASE;    /* 我们在smdkv210.h定义的0x30000000 */
#endif
	gd->ram_top += get_effective_memsize();    /* 返回0x20000000,ram_top = 0x50000000 */
	gd->ram_top = board_get_usable_ram_top(gd->mon_len);    /* 还是返回0x50000000 */
	gd->relocaddr = gd->ram_top;            /* 0x50000000  */
	debug("Ram top: %08lX\n", (ulong)gd->ram_top);
#if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
	/*
	 * We need to make sure the location we intend to put secondary core
	 * boot code is reserved and not used by any part of u-boot
	 */
	if (gd->relocaddr > determine_mp_bootpg(NULL)) {
		gd->relocaddr = determine_mp_bootpg(NULL);
		debug("Reserving MP boot page to %08lx\n", gd->relocaddr);
	}
#endif
	return 0;
}

目前gd->relocaddr = 0x50000000 指向DDR的顶端

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第16张图片

3.1.16、reserve_round_4k

/* Round memory pointer down to next 4 kB limit */
static int reserve_round_4k(void)
{
	gd->relocaddr &= ~(4096 - 1);    /* 4k向下对齐 */
	return 0;
}

这里4K先不放图了

3.1.17、reserve_mmu

#define PGTABLE_SIZE		(4096 * 4)       /* 16K的页表 */ 

static int reserve_mmu(void)
{
	/* reserve TLB table */
	gd->arch.tlb_size = PGTABLE_SIZE;
	gd->relocaddr -= gd->arch.tlb_size;    /* 从ox50000000向下少了16+4K */

	/* round down to next 64 kB limit */
	gd->relocaddr &= ~(0x10000 - 1);       /* 64k向下对齐 */

	gd->arch.tlb_addr = gd->relocaddr;     /* 页表必须64k对齐存放 */
	debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
	      gd->arch.tlb_addr + gd->arch.tlb_size);

#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
	/*
	 * Record allocated tlb_addr in case gd->tlb_addr to be overwritten
	 * with location within secure ram.
	 */
	gd->arch.tlb_allocated = gd->arch.tlb_addr;
#endif

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第17张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第18张图片

3.1.18、reserve_uboot


static int reserve_uboot(void)
{
	/*
	 * reserve memory for U-Boot code, data & bss
	 * round down to next 4 kB limit
	 */
	gd->relocaddr -= gd->mon_len;    /* 减去boot的总长度(包括bss) */
	gd->relocaddr &= ~(4096 - 1);    /* 4k对齐 */
#ifdef CONFIG_E500
	/* 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;    /* 把 start_addr_sp 也置为同样的位置 */

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第19张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第20张图片

3.1.19、reserve_malloc,保留一段malloc的空间

/* reserve memory for malloc() area */
static int reserve_malloc(void)
{
	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);
	

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第21张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第22张图片

3.1.20、reserve_board保留bd的空间

/* (permanently) allocate a Board Info struct */
static int reserve_board(void)
{
	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;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第23张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第24张图片

3.1.19、reserve_global_data

static int reserve_global_data(void)
{
	gd->start_addr_sp -= sizeof(gd_t);        /* 保留gd_t */
	gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));    /* 设置新的gd地址 */
	debug("Reserving %zu Bytes for Global Data at: %08lx\n",
			sizeof(gd_t), gd->start_addr_sp);
	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第25张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第26张图片

 

 

 

3.1.20、reserve_fdt

static int reserve_fdt(void)
{
#ifndef CONFIG_OF_EMBED        /* 没定义,要分析 */
	/*
	 * If the device tree is sitting immediately above our image then we
	 * must relocate it. If it is embedded in the data section, then it
	 * will be relocated with other data.
	 */
    /* 前面的没分析,所以这里先假设有 */
	if (gd->fdt_blob) {
		gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

		gd->start_addr_sp -= gd->fdt_size;
		gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
		debug("Reserving %lu Bytes for FDT at: %08lx\n",
		      gd->fdt_size, gd->start_addr_sp);
	}
#endif

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第27张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第28张图片

3.1.21、reserve_stacks

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

	/*
	 * let the architecture-specific code tailor gd->start_addr_sp and
	 * gd->irq_sp
	 */
	return arch_reserve_stacks();
}

这里就不画图了

3.1.22、setup_dram_config,配置每个ddr的bank大小

void 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;
}


static int setup_dram_config(void)
{
	/* Ram is board specific, so move it to board code ... */
	dram_init_banksize();

	return 0;
}

bd里面是板子相关的,这里就不列表了

2.1.23、show_dram_config


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

#ifdef CONFIG_NR_DRAM_BANKS        /* 我们是2 */
	int i;

	debug("\nRAM Configuration:\n");
	for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
		size += gd->bd->bi_dram[i].size;        /* debug我们没配置,所以这里就计算了总大小 */
		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;    /* 512M */
#endif

	print_size(size, "");    /* 打印512 Mib */
	board_add_ram_info(0);    /*具体的细节我们没配,所以这个函数是空的 */
	putc('\n');

	return 0;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第29张图片

2.1.24、display_new_sp我们没开debug功能,看不到

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

	return 0;
}

2.1.25、reloc_fdt重定位设备树

static int reloc_fdt(void)
{
#ifndef CONFIG_OF_EMBED        /* 没定义,要执行 */
	if (gd->flags & GD_FLG_SKIP_RELOC)
		return 0;
	if (gd->new_fdt) {    把设备树段拷贝到新的位置
		memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);
		gd->fdt_blob = gd->new_fdt;    /* 然后把老的地址跟新为新地址 */
	}
#endif

	return 0;
}

深色表明已经拷贝成功

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第30张图片

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第31张图片

 

2.1.26、setup_reloc重定位gd_t


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
	gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;    /* 得到新旧uboot的偏移 */
#ifdef 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);
#endif
#endif
	memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));          /* 拷贝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;
}

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第32张图片

 

从零开始之uboot、移植uboot2017.01(五、board_init_f分析)_第33张图片

 

board_init_f中的内容就已经分析完了。

接下来就剩下uboot本身的搬移和bss段的初始化。

 

你可能感兴趣的:(从零开始系列,从零开始学linux驱动)