在STEP1的最后,代码通过调用void start_armboot (void)进入了u-boot启动的第二阶段
1. void start_armboot (void)主要是对硬件的初始化,代码详解
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
/* Pointer is writable since we allocated a register for it */
// 初始化gd,使其指向global data区的基地址
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
//1. __asm__用于指示编译器在此插入汇编语句
//2. __volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
//3. memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。
// cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。
//4. "":::表示这是个空指令。
__asm__ __volatile__("": : :"memory");
//清零global data区
memset ((void*)gd, 0, sizeof (gd_t));
//初始化gd->bd,使其指向bd_t的基地址
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
//清零bd_t区
memset (gd->bd, 0, sizeof (bd_t));
// u-boot代码的大小。根据u-boot.lds可知,monitor_flash_len是.text + .rodata + .data + .got + .u_boot_cmd 的总长度。
monitor_flash_len = _bss_start - _armboot_start;
//init_sequence是初始化函数数组的起始地址,在这个循环中,会依次去执行初始化函数,若出现故障,则进入死循环。初始化函数包括
//1. cpu_init, /* basic cpu dependent setup, 分配IRQ, FIQ的栈地址 */
//2. board_init, /* basic board dependent setup, 初始化IO口 */
//3. interrupt_init, /* set up exceptions, 初始化时钟 */
//4. env_init, /* initialize environment, 初始化环境变量 */
//5. init_baudrate, /* initialze baudrate settings, 初始化波特率 */
//6. serial_init, /* serial communications setup , 初始化串口*/
//7. console_init_f, /* stage 1 init of console, 初始化终端 */
//8. display_banner, /* say that we are here, 打印一些信息到终端 */
//9. dram_init, /* configure available RAM banks, 初始化SDRAM的内存起始地址和大小。 */
//10. display_dram_config, 打印SDRAM的大小。
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* configure available FLASH banks */
// 初始化NOR FLASH,配置每个sector的size等。
size = flash_init ();
// 打印出NOR FLASH 的整个SIZE信息
display_flash_config (size);
/* armboot_start is defined in the board-specific linker script */
// 初始化malloc区,并全部清零
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
//初始化NAND FLASH相关的寄存器。
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
/* initialize environment */
//初始化环境变量
env_relocate ();
/* IP Address */
// 获取配置的IP地址
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
// 获取配置的MAC值,并将其存储到gd->bd->bi_enetaddr中。
{
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. */
// 初始化gd中的jump table中的函数,如get_version,malloc,getenv
jumptable_init ();
// 查找是否有可用的输入输出设备,若有,将其作为标准的输入输出设备:
// 输入: getc, tstc
// 输出: putc,puts,printf
console_init_r (); /* fully init console as a device */
// 初始化ARM的IO口。
Port_Init();
// PreLoadedONRAM这个变量在start.S中定义的。
//.globl PreLoadedONRAM
//PreLoadedONRAM:
//.word 0
if (!PreLoadedONRAM) {
/* enable exceptions */
enable_interrupts ();
/* add by www.100ask.net */
// 初始化usb口
usb_init();
}
/* main_loop() can return to retry autoboot, if so just run it again. */
// 经过一系列初始化后,进入主循环。
for (;;) {
main_loop ();
}
}
2. void main_loop (void)用于对FLASH进行分区、调用kernel,执行u-boot中输入的命令,其被void start_armboot (void)调用。
void main_loop (void)
{
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
//初始化bootdelay相关的变量
char *s;
int bootdelay;
#endif
#ifdef CONFIG_JFFS2_CMDLINE
// 初始化分区表,对FLASH进行分区
//mtdparts=mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)
extern int mtdparts_init(void);
if (!getenv("mtdparts"))
{
run_command("mtdparts default", 0);
}
else
{
mtdparts_init();
}
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
// 获取 bootdelay的值: bootdelay=2
s = getenv ("bootdelay");
// 转换成整数
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
// 获取bootcmd的参数: bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
s = getenv ("bootcmd");
// 倒计时开始,若倒计时结束,没有按下任何按键,则该条件成立
if (bootdelay >= 0 && s && !abortboot (bootdelay))
{
// 打印Booting Linux ...
printf("Booting Linux ...\n");
// 执行bootcmd的参数,nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
run_command (s, 0);
}
#endif /* CONFIG_BOOTDELAY */
// 执行 menu 命令
run_command("menu", 0);
// 进入死循环,读取命令并执行之。
for (;;)
{
len = readline (CFG_PROMPT);
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
if (len == -1)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
}