在第一部分说过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函数。