[39]_uboot启动第二阶段分析

前面分析了  [38]_uboot启动第一阶阶段分析,主要是关注start.S和lowlevel_init.S 这两个文件即可

现在分析它的第二阶段,从start_armboot函数开始分析,这个函数非常长,足足有400多行,还没包括中间要调用的其它函数,分析文件是board.c文件:

1.先来看看这两个结构体,一个是关于uboot全局变量的结构体gd_t,一个是关于板级信息的结构体bd_t,代码如下:

typedef	struct	global_data {
	bd_t		*bd;  				// 存放开发板相关的信息 ,譬如波特率、IP地址、网卡地址、机器码、启动参数
	unsigned long	flags;
	unsigned long	baudrate;		//通信的波特率
	unsigned long	have_console;	/* serial_init() was called */ 			//控制台
	unsigned long	reloc_off;		/* Relocation Offset 		*/ 	//重定位偏移量
	unsigned long	env_addr;		/* Address  of Environment struct */	//环境变量的地址
	unsigned long	env_valid;		/* Checksum of Environment valid? */	//内存中的那份环境变量的值,原来的环境变量可能存在其它启动介质中
	unsigned long	fb_base;		/* base address of frame buffer */	//LCD缓存的起始地址
#ifdef CONFIG_VFD
	unsigned char	vfd_type;		/* display type */
#endif
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	phys_size_t	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table */
} gd_t;      // 根据结构体内存对齐特性,这个结构体的大小为36字节
------------------------------------------
typedef struct bd_info {
    int			bi_baudrate;		/* serial console baudrate */ 	//串口控制台波特率
    unsigned long	bi_ip_addr;		/* IP Address */		//板子上的ip地址
    unsigned char	bi_enetaddr[6]; /* Ethernet adress */			//网卡ip地址
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/* unique id for this board */	//uboot机器码
    ulong	        bi_boot_params;	/* where this board expects params */  //uboot启动参数
    struct							/* RAM configuration */
    {
	ulong start;
	ulong size;
    }			bi_dram[CONFIG_NR_DRAM_BANKS];				//内存信息,板子有几块内存、内存分布、大小等。
#ifdef CONFIG_HAS_ETH1
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t;   // 根据结构体内存对齐特性,这个结构体的大小为44字节

2.因为上面两个结构体定义时在内存中是没有被分配内存,还有此时目前还是处于uboot的启动阶段,不能使用malloc去申请内存,只能是手工分配gd_base:

#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
	ulong gd_base;  //gd_base是DDR
	//内存排布:uboot的起始地址(0xc3e00000)、uboot的大小2M、堆大小912KB、栈大小512KB、gd_t大小36字节
	gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
#ifdef CONFIG_USE_IRQ
	gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif
3.内存排布总结如下:
  (1)uboot区 CFG_UBOOT_BASE-xx (长度为uboot的实际长度CFG_UBOOT_SIZE )
  (2)堆区 长度为CFG_MALLOC_LEN,实际为912KB,包括环境变量的大小。
  (3)栈区 长度为CFG_STACK_SIZE,实际为512KB
  (4)gd 长度为sizeof(gd_t),实际36字节
  (5)bd 长度为sizeof(bd_t),实际为44字节左右

  (6)内存间隔 为了防止高版本的gcc的优化造成错误。譬如在uboot中使用C语言内嵌汇编的方式来实现

/* compiler optimization barrier needed for GCC >= 3.4 */
	__asm__ __volatile__("": : :"memory");   //“ __asm__ ”表示在C语言中内嵌汇编,防止高版本gcc优化它
//这里一个for循环,主要是为了去遍历函数指针数组init_sequence,目的是依次执行init_sequence这个函数指针数组中元素
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) { //如果遍历执行的这些函数的结果不等于0,则初始化就会失败被挂起
			hang ();   //挂起
		}
	}

4.关于init_sequence函数指针数组的定义如:

init_fnc_t *init_sequence[] = {   /* 这些函数指针数组 */
	cpu_init,		/* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
	reloc_init,		/* Set the relocation done flag, must
				   do this AFTER cpu_init(), but as soon
				   as possible */
#endif
	board_init,		/* basic board dependent setup */
	interrupt_init,		/* set up exceptions */
	env_init,		/* initialize environment */
	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */ /*控制台的第一阶段初始化*/
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */ /*bank的个数配置*/
	display_dram_config,
	NULL,
};

init_sequence这个函数指针数组里面囊括了一个个的函数,我们很多工作都是在这些函数中展开的,譬如CPU初始化(cpu_init)、板级初始化(board_init)、中断初始化(interrupt_init)、环境变量初始化(env_init) ...........等等。所以这个函数指针数组是我们需要分析的关键。

-----------------------------------------------------------------------------------------------------------------------

int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ     / /
IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
return 0;

}

解析:CONFIG_USE_IRQ没有被定义,所以这里不成立,cpu_init是空函数,原因是该做的事在start.S中都做了。

--------------------------------------------------

/*
 * This routine sets the relocation done flag, because even if
 * relocation is skipped, the flag is used by other generic code.
 */
static int reloc_init(void)
{
gd->flags |= GD_FLG_RELOC;
return 0;
}

#endif

解析:reloc_init这个函数只是对gd_t结构体中的flag标志位进行置位,表示介质中的uboot的BL2部分已经被拷贝到DDR中了。

-----------------------------------------------------

int board_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DRIVER_SMC911X
smc9115_pre_init();    //网卡相关
#endif


#ifdef CONFIG_DRIVER_DM9000
dm9000_pre_init();
#endif


gd->bd->bi_arch_number = MACH_TYPE; //机器码
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100); //uboot启动参数:0x30000000 + 0x100 = 0x30000100
//uboot启动内核后,内核在bi_boot_params内存内地址(0x30000100)处读取uboot传给它的参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值