uboot的目标是启动内核,从flash读出内核然后启动。
在start.S中start_armboot开始:
ldr pc, _start_armboot
_start_armboot: .word start_armboot
在lib_arm/board.c中定义:
gd是结构体指针,申请得到部分内存,
void start_armboot (void)
{
...
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
...
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
...
}
init_sequence是函数指针数组的首地址,在lib_arm/board.c中,其中包含了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,
};
看board_init定义,在board/100ask24x0/100ask24x0.c中,设置管脚,gd指向那个128字节的内存,bi_arch_number叫机器id,bi_boot_params启动内核的时候传入的一些参数所存放的位置,
int board_init (void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
gpio->GPBCON = 0x00044555;
gpio->GPBUP = 0x000007FF;
gpio->GPCCON = 0xAAAAAAAA;
gpio->GPCUP = 0x0000FFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0x0000FFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FFBA;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x002AFAAA;
gpio->GPHUP = 0x000007FF;
/* support both of S3C2410 and S3C2440, by www.100ask.net */
if (isS3C2410)
{
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
}
else
{
/* arch number of SMDK2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
}
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
#if 0
icache_enable();
dcache_enable();
#endif
return 0;
}
既然要从flash中读数据,那么flash一定有读功能的实现,初始化flash
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
以下是对堆的一些初始化 192K空间,实现了堆的分配和释放,
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
nand_init
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
一些环境变量的初始化,上电后去flash中找有没有环境变量,没有就使用默认的,
/* initialize environment */
env_relocate ();
往下网卡,设备,usb,调试,如果用调试器下载PreLoadedONRAM将被置1
Port_Init();
if (!PreLoadedONRAM) {
/* enable exceptions */
enable_interrupts ();
/* add by www.100ask.net */
usb_init();
}
到此只是flash拥有了读写的功能,但是怎么读怎么启动内核还需要分析,这里是死循环,应该是uboot启动打印的那个循环信息,
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
在start_armboot中完成了nand nor的初始化。
main_loop在common/main.c中,环境变量通过getenv来获取得到,bootdelay,bootcmd。根据bootcmd run_command启动内核,
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
...
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "" );
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CFG_HUSH_PARSER
{
printf("Booting Linux ...\n");
run_command (s, 0);
}
bootcmd指定了从nand的kernel分区读取到SDRAM,然后从SDRAM启动,
在uboot倒计时结束前空格,进入menu,
eth_init(gd->bd);
run_command("menu", 0);
在这里readline读取串口交互的输入,根据输入的参数去启动系统run_command,
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
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;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif
if (len == -1)
puts ("\n" );
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
#endif /*CFG_HUSH_PARSER*/
}
在start.S中start_armboot开始,start_armboot在lib_arm/board.c中定义。
在start_armboot中,有各种初始化操作init_sequenceboard,其中的某些会调用/100ask24x0/100ask24x0.c的board_init等等。完成一些外设的初始化工作。
到这里uboot运行起来了,一些外设也运行起来了,马上就是串口交互界面,这个交互界面在main_loop函数中实现,main_loop在common/main.c中。
交互界面中主要通过getenv获取flash保存的环境变量,通过readline获取串口的输入,最终都是通过传递参数给run_command来启动内核的。