u-boot第二阶段start.s分析:start_armboot部分(一)

  在第一部分说过u-boot的第一阶段是汇编语言部分,那重头戏就是这第二部分了:start_armboot部分。

  首先将编译好的u-boot烧写完成,启动,并打印出环境变量:



bootargs=root=/dev/mtdblock2 console=ttySAC0,115200
bootcmd=nand read.i c0008000 80000 500000;bootm c0008000
bootdelay=3
baudrate=115200
ethaddr=08:90:90:90:90:90
ipaddr=192.168.1.230
serverip=192.168.1.88
gatewayip=192.168.1.1
netmask=255.255.255.0
stdin=serial
stdout=serial
stderr=serial

Environment size: 291/131068 bytes

  着重注意bootcmd=nand read.i c0008000 80000 500000;bootm c0008000这句话,因为这是u-boot传递给内核的参数!

  怎么理解bootcmd?首先必须要理解u-boot的最终目标就是从flash中读出内核,然后启动内核,所以就很好理解这句话了:在nand中0x80000处开始的5M的数据拷到sdram0xc0008000处,从这个地址开始执行。

  然后利用source insight定位到start_armboot的位置:lib_arm\board.c

  代码如下:

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;
	char *s;
#ifndef CFG_NO_FLASH
	ulong size;
#endif

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

#if defined(CONFIG_BOOT_MOVINAND)
	uint *magic = (uint *) (PHYS_SDRAM_1);
#endif

	/* Pointer is writable since we allocated a register for it */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
	ulong gd_base;

	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
	gd = (gd_t*)gd_base;
#else
	gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
    //给gd结构体分配内存
#endif

	/* 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
	/* configure available FLASH banks */
	size = flash_init ();
	display_flash_config (size);
#endif /* CFG_NO_FLASH */

#ifdef CONFIG_VFD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
	/*
	 * reserve memory for VFD display (always full pages)
	 */
	/* bss_end is defined in the board-specific linker script */
	addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
	size = vfd_setmem (addr);
	gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
	/*
	 * reserve memory for LCD display (always full pages)
	 */
	/* bss_end is defined in the board-specific linker script */
	addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
	size = lcd_setmem (addr);
	gd->fb_base = addr;
#endif /* CONFIG_LCD */

	/* armboot_start is defined in the board-specific linker script */
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
	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_SMDK6400) || defined(CONFIG_SMDK6410) || defined(CONFIG_SMDK6430) || defined(CONFIG_SMDK2450) || defined(CONFIG_SMDK2416) || \
defined(CONFIG_MINI6410)

#if defined(CONFIG_NAND)
	puts ("NAND:    ");
	nand_init();		/* go init the NAND */
	NAND_Init();
#endif

#if defined(CONFIG_ONENAND)
	puts ("OneNAND: ");
	onenand_init();		/* go init the One-NAND */
#endif

#if defined(CONFIG_BOOT_MOVINAND)
	puts ("MMC:     ");

	if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
		printf("Boot up for burning\n");
	} else {
		movi_set_capacity();
		movi_set_ofs(MOVI_TOTAL_BLKCNT);
		movi_init();
	}
#endif

#else

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
	puts ("NAND:    ");
	nand_init();		/* go init the NAND */
#endif

#endif

#ifdef CONFIG_HAS_DATAFLASH
	AT91F_DataflashInit();
	dataflash_print_info();
#endif

	/* initialize environment */
	env_relocate ();

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

	/* IP Address */
	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

	/* MAC Address */
	{
		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;
		}

#ifdef CONFIG_HAS_ETH1
		i = getenv_r ("eth1addr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

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

	devices_init ();	/* get the devices list going. */

#ifdef CONFIG_CMC_PU2
	load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */

	jumptable_init ();

	console_init_r ();	/* fully init console as a device */

#if defined(CONFIG_MISC_INIT_R)
	/* miscellaneous platform dependent initialisations */
	misc_init_r ();
#endif

	/* enable exceptions */
	enable_interrupts ();

	/* Perform network card initialisation if necessary */
#if defined(CONFIG_DRIVER_DM9000) && defined(CONFIG_DRIVER_DM9000_NO_EEPROM)
extern int eth_set_mac(bd_t * bd);
	if (getenv ("ethaddr")) {
		eth_set_mac(gd->bd);
	}
#endif

#ifdef CONFIG_DRIVER_CS8900
	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
	if (getenv ("ethaddr")) {
		smc_set_mac_addr(gd->bd->bi_enetaddr);
	}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

	/* Initialize from environment */
	if ((s = getenv ("loadaddr")) != NULL) {
		load_addr = simple_strtoul (s, NULL, 16);
	}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
	if ((s = getenv ("bootfile")) != NULL) {
		copy_filename (BootFile, s, sizeof (BootFile));
	}
#endif	/* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
	board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
	puts ("Net:     ");
#endif
	eth_initialize(gd->bd);
#endif
	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop ();
	}

	/* NOTREACHED - no way out of command loop except booting */
}

  而init_sequence是进行一系列初始化,如CPU、开发板、中断、环境、波特率、串口、控制台、显示的初始化:

init_fnc_t *init_sequence[] = {
	cpu_init,		/* basic cpu dependent setup */
	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
	dram_init,		/* configure available RAM banks */
	display_dram_config,
	NULL,
};

  cpu_init是在cpu\s3c64xx\Cpu.c文件里面进行:

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

  board_init是在board\samsung\mini6410\Mini6410.c文件里面进行:包括初始化网卡、获得机器的ID、启动的默认参数。

  一般而言linux内核的机器码比允许要和u-boot的机器码一致内核才能正常启动,不然u-boot启动之后会提示机器码不一致导致系统无法启动:linux内核的机器码,在arch/arm/tools/mach-types.h中,u-boot的机器码是在u-boot/include/asm-arm/mach-types.h文件中,此外这个文件也用到了u-boot的机器码,查看此处的机器码的出处:在include\configs\Mini6410.h的70行有定义:#define MACH_TYPE        2520,具体是哪一个文件请查看该文章的第5点。

int board_init(void)
{
	DECLARE_GLOBAL_DATA_PTR;
	u32 reg;

	dm9000_pre_init();

	/* set GPIO for Display Controller */
	reg = readl(MIFPCON);
	reg &= ~(1 << 3);
	writel(reg, MIFPCON);

	reg = readl(SPCON);
	reg &= ~(3 << 0);
	writel(reg | 0x1, SPCON);

	writel(0xaaaaaaaa, GPICON);
	writel(0xaaaaaa, GPJCON);

	gd->bd->bi_arch_number = MACH_TYPE;
    //机器码,在调用linux内核中用到,要和linux机器码一致内核才能工作
	gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
    //启动内核时,参数的存放位置
#if 0
	icache_enable();
	dcache_enable();
#endif
	return 0;
}

  而interrupt_init就是初始化中断,代码位于cpu\s3c64xx\Interrupts.c中,代码如下:

int interrupt_init(void)
{
	S3C64XX_TIMERS *const timers = S3C64XX_GetBase_TIMERS();

	/* use PWM Timer 4 because it has no output */
	/* prescaler for Timer 4 is 16 */
	timers->TCFG0 = 0x0101;
	if (timer_load_val == 0) {
		/*
		 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
		 * (default) and prescaler = 16. Should be 10390
		 * @33.25MHz and 15625 @ 50 MHz
		 * alex: 20625 @ 66MHz
		 */
		timer_load_val = get_PCLK() / (2 * 16 * 100);
		timers->TCFG1 = (timers->TCFG1 & ~0xf0000) | 0x40000;
	}

	/* load value for 10 ms timeout */
	lastdec = timers->TCNTB4 = timer_load_val;
	/* auto load, manual update of Timer 4 */
	timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;
	/* auto load, start Timer 4 */
	timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
	timestamp = 0;

	return (0);
}

  而init_baudrate在lib_arm\Board.c中被定义,代码如下,是用来定义波特率的:

static int init_baudrate (void)
{
	char tmp[64];	/* long enough for environment variables */
	int i = getenv_r ("baudrate", tmp, sizeof (tmp));
	gd->bd->bi_baudrate = gd->baudrate = (i > 0)
			? (int) simple_strtoul (tmp, NULL, 10)
			: CONFIG_BAUDRATE;

	return (0);
}

  serial_init是用来初始化串口的,代码在cpu\s3c64xx\Serial.c中:

void serial_setbrg(void)
{
	DECLARE_GLOBAL_DATA_PTR;

	int i;
	for (i = 0; i < 100; i++);
}

int serial_init(void)
{
	serial_setbrg();

	return (0);
}

  console_init_f在common\Console.c中被定义,代码如下:

/* Called before relocation - use serial functions */
int console_init_f (void)
{
	gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE
	if (getenv("silent") != NULL)
		gd->flags |= GD_FLG_SILENT;
#endif

	return (0);
}

  display_banner函数在lib_arm\Board.c中被定义,代码如下:

static int display_banner (void)
{
	printf ("\n\n%s\n\n", version_string);
	debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
	       _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
	debug("\t\bMalloc and Stack is above the U-Boot Code.\n");
#else
	debug("\t\bMalloc and Stack is below the U-Boot Code.\n");
#endif
#ifdef CONFIG_MODEM_SUPPORT
	debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
	debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
	debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

	return (0);
}

  然后CONFIG_DISPLAY_CPUINFO已经在文件中被定义了,故会运行print_cpuinfo函数,该函数在cpu\s3c64xx\s3c6410中被定义为如下:

int print_cpuinfo(void)
{
	printf("\nCPU:     S3C6410@%dMHz\n", get_ARMCLK()/1000000);
	printf("         Fclk = %dMHz, Hclk = %dMHz, Pclk = %dMHz",
			get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000);

/**************
* Display Serial SRC
***************/

#if defined(CONFIG_CLKSRC_CLKUART)
	puts(", Serial = CLKUART ");
#else
	puts(", Serial = PCLK ");
#endif

	if(OTHERS_REG & 0x80)
		printf("(SYNC Mode) \n");
	else
		printf("(ASYNC Mode) \n");
	return 0;
}

然后启动u-boot查看串口输出的信息:


U-Boot 1.1.6 (Apr  9 2019 - 14:48:24) for FriendlyARM MINI6410


CPU:     S3C6410@532MHz
         Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz, Serial = CLKUART (SYNC Mode) 
Board:   MINI6410
DRAM:    256 MB
Flash:   0 kB
NAND:    256 MB 
*** Warning - bad CRC or NAND, using default environment

In:      serial
Out:     serial
Err:     serial
MAC: 08:90:90:90:90:90
Hit any key to stop autoboot:  0 

NAND read: device 0 offset 0x80000, size 0x500000
........................................ 5242880 bytes read: OK
## Booting image at c0008000 ...
Boot with Image

Starting kernel ...

  恰好与之对应。

  check_board是在board\samsung\mini6410.c里面有定义,如下:

#ifdef CONFIG_DISPLAY_BOARDINFO
int checkboard(void)
{
	printf("Board:   MINI6410\n");
	return (0);
}
#endif

dram_init与check_board在同一个文件里面,定义如下:

int dram_init(void)
{
	DECLARE_GLOBAL_DATA_PTR;

	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

	return 0;
}

  而display_dram_config是在lib_arm\Board.c里面定义的,这个函数会打印出DRAM的大小,定义如下:

static int display_dram_config (void)
{
	int i;

#ifdef DEBUG
	puts ("RAM Configuration:\n");

	for(i=0; ibd->bi_dram[i].start);
		print_size (gd->bd->bi_dram[i].size, "\n");
	}
#else
	ulong size = 0;

	for (i=0; ibd->bi_dram[i].size;
	}

	puts("DRAM:    ");
	print_size(size, "\n");
#endif

	return (0);
}

    flash_init在board\samsung\mini6410\Flash.c里面定义的,而display_flash_config是在lib_arm\Board.c里面定义的:

#ifndef CFG_NO_FLASH
static void display_flash_config (ulong size)
{
	puts ("Flash:  ");
	print_size (size, "\n");
}
#endif /* CFG_NO_FLASH */

  接下来是vfd_setmem,在board\trab\Vfd.c里面定义,用以支持ROM初始化:

ulong vfd_setmem (ulong addr)
{
	ulong size;

	/* Round up to nearest full page */
	size = (FRAME_BUF_SIZE + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

	debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);

	return (size);
}

  接下来是初始化LCD屏的,由于此处作者并未使用,所以略过。紧随其后的是mem_malloc_init,在lib_arm\Board.c中被定义,函数的意思就是划分出CFG_MALLOC_LEN这么大一块大小,而这个CFG_MALLOC_LEN在include\configs\Mini6410.h中被定义:#define CFG_MALLOC_LEN        (CFG_ENV_SIZE + 1024*1024),以下是mem_malloc_init的代码内容:

static
void mem_malloc_init (ulong dest_addr)
{
	mem_malloc_start = dest_addr;
	mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
	mem_malloc_brk = mem_malloc_start;

	/* memset ((void *) mem_malloc_start, 0,
			mem_malloc_end - mem_malloc_start); */
}

  然后是nand_init,nand_init在board\samsung\mini6410\Mini6410.c中被定义:

void nand_init(void)
{
	nand_probe(CFG_NAND_BASE);
        if (nand_dev_desc[0].ChipID != NAND_ChipID_UNKNOWN) {
                print_size(nand_dev_desc[0].totlen, "\n");
        }
}

  然后是env_relocate函数,初始化一些环境变量,那么这个环境变量怎么来的呢?一是默认的环境变量,二是自己是设置的。该函数在common\Env_common.c中被定义:

void env_relocate (void)
{
	DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
		gd->reloc_off);

#ifdef CONFIG_AMIGAONEG3SE
	enable_nvram();
#endif

#ifdef ENV_IS_EMBEDDED
	/*
	 * The environment buffer is embedded with the text segment,
	 * just relocate the environment pointer
	 */
	env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
	DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
	/*
	 * We must allocate a buffer for the environment
	 */
	env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
	DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

	/*
	 * After relocation to RAM, we can always use the "memory" functions
	 */
	env_get_char = env_get_char_memory;

	if (gd->env_valid == 0) {
#if defined(CONFIG_GTH)	|| defined(CFG_ENV_IS_NOWHERE)	/* Environment not changable */
		puts ("Using default environment\n\n");
#else
		puts ("*** Warning - bad CRC, using default environment\n\n");
		SHOW_BOOT_PROGRESS (-1);
#endif

		if (sizeof(default_environment) > ENV_SIZE)
		{
			puts ("*** Error - default environment is too large\n\n");
			return;
		}

		memset (env_ptr, 0, sizeof(env_t));
		memcpy (env_ptr->data,
			default_environment,
			sizeof(default_environment));
#ifdef CFG_REDUNDAND_ENVIRONMENT
		env_ptr->flags = 0xFF;
#endif
		env_crc_update ();
		gd->env_valid = 1;
	}
	else {
		env_relocate_spec ();
	}
	gd->env_addr = (ulong)&(env_ptr->data);

#ifdef CONFIG_AMIGAONEG3SE
	disable_nvram();
#endif
}

  然后得到ip地址:gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");和MAC地址:

	/* IP Address */
	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

	/* MAC Address */
	{
		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;
		}

#ifdef CONFIG_HAS_ETH1
		i = getenv_r ("eth1addr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

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

  然后是devices_init函数,在common\Devices.c中被定义,完成设备的初始化,包括初始化列表等等。。。

int devices_init (void)
{
#ifndef CONFIG_ARM     /* already relocated for current ARM implementation */
	ulong relocation_offset = gd->reloc_off;
	int i;

	/* relocate device name pointers */
	for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
		stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
						relocation_offset);
	}
#endif

	/* Initialize the list */
	devlist = ListCreate (sizeof (device_t));

	if (devlist == NULL) {
		eputs ("Cannot initialize the list of devices!\n");
		return -1;
	}
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD
	drv_lcd_init ();
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
	drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD
	drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
	drv_logbuff_init ();
#endif
	drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI
	serial_devices_init ();
#endif
#ifdef CONFIG_USB_TTY
	drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
	drv_nc_init ();
#endif

	return (0);
}

  然后是jumptable_init函数,功能是安装系统函数指针,在common\Exports.c中被定义:

void jumptable_init (void)
{
	int i;

	gd->jt = (void **) malloc (XF_MAX * sizeof (void *));
	for (i = 0; i < XF_MAX; i++)
		gd->jt[i] = (void *) dummy;

	gd->jt[XF_get_version] = (void *) get_version;
	gd->jt[XF_malloc] = (void *) malloc;
	gd->jt[XF_free] = (void *) free;
	gd->jt[XF_getenv] = (void *) getenv;
	gd->jt[XF_setenv] = (void *) setenv;
	gd->jt[XF_get_timer] = (void *) get_timer;
	gd->jt[XF_simple_strtoul] = (void *) simple_strtoul;
	gd->jt[XF_udelay] = (void *) udelay;
#if defined(CONFIG_I386) || defined(CONFIG_PPC)
	gd->jt[XF_install_hdlr] = (void *) irq_install_handler;
	gd->jt[XF_free_hdlr] = (void *) irq_free_handler;
#endif	/* I386 || PPC */
#if (CONFIG_COMMANDS & CFG_CMD_I2C)
	gd->jt[XF_i2c_write] = (void *) i2c_write;
	gd->jt[XF_i2c_read] = (void *) i2c_read;
#endif	/* CFG_CMD_I2C */
}

  而console_init_r函数则是将控制台输出作为一个设备,该函数在lib_arm\Board.c中被定义:

int console_init_r (void)
{
	char *stdinname, *stdoutname, *stderrname;
	device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
#ifdef CFG_CONSOLE_ENV_OVERWRITE
	int i;
#endif /* CFG_CONSOLE_ENV_OVERWRITE */

	/* set default handlers at first */
	gd->jt[XF_getc] = serial_getc;
	gd->jt[XF_tstc] = serial_tstc;
	gd->jt[XF_putc] = serial_putc;
	gd->jt[XF_puts] = serial_puts;
	gd->jt[XF_printf] = serial_printf;

	/* stdin stdout and stderr are in environment */
	/* scan for it */
	stdinname  = getenv ("stdin");
	stdoutname = getenv ("stdout");
	stderrname = getenv ("stderr");

	if (OVERWRITE_CONSOLE == 0) { 	/* if not overwritten by config switch */
		inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname);
		outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname);
		errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname);
	}
	/* if the devices are overwritten or not found, use default device */
	if (inputdev == NULL) {
		inputdev  = search_device (DEV_FLAGS_INPUT,  "serial");
	}
	if (outputdev == NULL) {
		outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
	}
	if (errdev == NULL) {
		errdev    = search_device (DEV_FLAGS_OUTPUT, "serial");
	}
	/* Initializes output console first */
	if (outputdev != NULL) {
		console_setfile (stdout, outputdev);
	}
	if (errdev != NULL) {
		console_setfile (stderr, errdev);
	}
	if (inputdev != NULL) {
		console_setfile (stdin, inputdev);
	}

	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */

#ifndef CFG_CONSOLE_INFO_QUIET
	/* Print information */
	puts ("In:      ");
	if (stdio_devices[stdin] == NULL) {
		puts ("No input devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stdin]->name);
	}

	puts ("Out:     ");
	if (stdio_devices[stdout] == NULL) {
		puts ("No output devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stdout]->name);
	}

	puts ("Err:     ");
	if (stdio_devices[stderr] == NULL) {
		puts ("No error devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stderr]->name);
	}
#endif /* CFG_CONSOLE_INFO_QUIET */

#ifdef CFG_CONSOLE_ENV_OVERWRITE
	/* set the environment variables (will overwrite previous env settings) */
	for (i = 0; i < 3; i++) {
		setenv (stdio_names[i], stdio_devices[i]->name);
	}
#endif /* CFG_CONSOLE_ENV_OVERWRITE */

#if 0
	/* If nothing usable installed, use only the initial console */
	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
		return (0);
#endif
	return (0);
}

  然后使能中断:enable_interrupts。然后对输入的ip地址进行处理。因为网卡芯片是DM9000,故会执行这个语句:if (getenv ("ethaddr")) {eth_set_mac(gd->bd);}。然后执行board_late_init函数,该函数在board\samsung\mini6410\Mini6410.c中被定义,代码如下:

int board_late_init (void)
{
	uint *magic = (uint*)(PHYS_SDRAM_1);
	char boot_cmd[100];

	if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
		sprintf(boot_cmd, "nand erase 0 40000;nand write %08x 0 40000", PHYS_SDRAM_1 + 0x8000);
		magic[0] = 0;
		magic[1] = 0;
		printf("\nready for self-burning U-Boot image\n\n");
		setenv("bootdelay", "0");
		setenv("bootcmd", boot_cmd);
	}

	return 0;
}

  然后是互联网初始化,eth_initialize函数,在net\Eth.c中被定义,代码太长就不贴出来了,然后就是一个main_loop,这还没有涉及到u-boot的最终目标。下一节接着分析main_loop函数。

 

 

你可能感兴趣的:(u-boot,ARM11)