S5PV210之uboot的start_armboot

前言

start_armboot我们一般认为是uboot的第二阶段,这个结算代码执行都是在ddr中的

相关数据结构

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

这个宏用来定义gd_t类型的gd指针,后面的asm (“r8”)代表指定arm里的r8寄存器存储。gd_t里面存储着很多全局变量供整个uboot使用,里面还有个bd_t存放了开发板的硬件相关的参数,这里用宏定义来声明这个变量,需要用到gd_t的地方就使用宏DECLARE_GLOBAL_DATA_PTR。

这个是在asm-arm/gloal_data.h文件里定义的全局变量gd_t,里面还用到了一个在asm-arm/uboot.h里定义的bd_t。

/*全局配置信息*/
typedefstruct global_data {
    bd_t        *bd;
    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 */
#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;
/*板级配置信息*/
typedef struct bd_info {
    int        bi_baudrate;   /* serial console baudrate */
    unsigned long bi_ip_addr;/* IP Address */
    unsigned char bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s          *bi_env;
    ulong           bi_arch_number;/* unique id for this board */
    ulong           bi_boot_params;/* where this board expects params */
    struct             /* RAM configuration */
    {
    ulong start;
    ulong size;
    }           bi_dram[CONFIG_NR_DRAM_BANKS];//CONFIG_NR_DRAM_BANKS 2
#ifdef CONFIG_HAS_ETH1
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t;
typedef int (init_fnc_t) (void);
init_fnc_t *init_sequence[] = {
	cpu_init,		/* basic cpu dependent setup */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)
	reloc_init,		/* Set the relocation done flag, mustdo this AFTER cpu_init(), but as soonas 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 */
	display_dram_config,
	NULL,
};

这个函数指针数组中存放的都是一些板级硬件初始化函数入口地址,最后一个是NULL即void *0,在后续需要执行这些硬件初始化的时候,只需要遍历这个数组就ok,最后一个元素是NULL,这个技巧kernel里面经常会有。
init_sequence函数就是把进行初始化的函数都集中在一起,这里面进行的初始化操作有:

    cpu初始化 (实际为空)
    板级初始化 网卡预配置,记录机器码和SDRAM信息
    时钟初始化
    环境变量初始化 这里还没有将环境变量从SD卡迁移到内存,基本都被判定为无效
    串口波特率初始化
    串口初始化 (实际为空)
    控制台初始化第一阶段
    打印banner uboot版本信息和日期时间
    打印cpu信息 各个时钟域的时钟频率
    检查板子信息并打印
    初始化i2c (无效,未配置宏)
    初始化DRAM 配置有几块DRAM和DRAM大小
    打印DRAM配置信息

S5PV210之uboot的start_armboot_第1张图片

代码分析

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;	//函数指针数组指针
	char *s;
	int mmc_exist = 0;
#if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
	ulong size;
#endif

#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
	unsigned long addr;
#endif


	/* Pointer is writable since we allocated a register for it */
	ulong gd_base;
	gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
	gd = (gd_t*)gd_base;//计算gd的基地址


	/* compiler optimization barrier needed for GCC >= 3.4 */
	__asm__ __volatile__("": : :"memory");//内存屏障

	memset ((void*)gd, 0, sizeof (gd_t));
	gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
	memset (gd->bd, 0, sizeof (bd_t));

	monitor_flash_len = _bss_start - _armboot_start;
	//板级硬件信息初始化
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}

#ifndef CFG_NO_FLASH
	/* 配置可用的flash */
	size = flash_init ();
	display_flash_config (size);
#endif /* CFG_NO_FLASH */

	/* armboot_start is defined in the board-specific linker script */
#ifdef CONFIG_MEMORY_UPPER_CODE /* 堆内存初始化*/
	mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);
#else
	mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#endif

#if defined(CONFIG_X210)

	#if defined(CONFIG_GENERIC_MMC)
		puts ("SD/MMC:  ");
		mmc_exist = mmc_initialize(gd->bd);//初始化mmc
		if (mmc_exist != 0)
		{
			puts ("0 MB\n");
		}
	#endif
#endif /* CONFIG_X210 */

	/* initialize environment */
	env_relocate ();

#ifdef CONFIG_VFD
	/* must do this after the framebuffer is allocated */
	drv_vfd_init();
#endif /* CONFIG_VFD */

#ifdef CONFIG_SERIAL_MULTI
	serial_initialize();
#endif

	/* IP Address 获取环境变量的 ipaddr*/
	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

	/* MAC Address 设置到DM9000中去 */
	{
		int i;
		ulong reg;
		char *s, *e;
		char tmp[64];

		i = getenv_r ("ethaddr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

		for (reg = 0; reg < 6; ++reg) {
			gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
			if (s)
				s = (*e) ? e + 1 : e;
		}
	}

	devices_init ();	/* get the devices list going. */
	jumptable_init ();
#if !defined(CONFIG_SMDK6442)
	console_init_r ();	/* 真正的初始化控制台的代码fully init console as a device */
#endif

	/* enable exceptions */
	enable_interrupts ();

	/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
	/* Initialize from environment */
	if ((s = getenv ("loadaddr")) != NULL) {
		load_addr = simple_strtoul (s, NULL, 16);
	}
#if defined(CONFIG_CMD_NET)
	if ((s = getenv ("bootfile")) != NULL) {
		copy_filename (BootFile, s, sizeof (BootFile));
	}
#endif

#ifdef BOARD_LATE_INIT
	board_late_init ();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
	puts ("Net:   ");
#endif
	eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
	debug ("Reset Ethernet PHY\n");
	reset_phy();
#endif
#endif

#if defined(CONFIG_CMD_IDE)
	puts("IDE:   ");
	ide_init();
#endif

/****************显示屏显示logolxg added**************/
#ifdef CONFIG_MPAD
	x210_preboot_init();
#endif
/****************end**********************/

	/* check menukey to update from sd是否从sd卡更新系统 */
	if(check_menu_update_from_sd()==0)//update mode
	{
		puts ("[LEFT DOWN] update mode\n");
		run_command("fdisk -c 0",0);
		update_all();
	}
	else
		puts ("[LEFT UP] boot mode\n");

	/* main_loop循环,在其中bootdelay延时,并最后do_bootm,或者delay被打断然后进入命令行模式,之后分析cmd实现方式 */
	for (;;) {
		main_loop ();
	}
}

你可能感兴趣的:(uboot和linux,kernel移植)