/*
* All attempts to come up with a "common" initialization sequence
* that works for all boards and architectures failed: some of the
* requirements are just _too_ different.
* To get rid of the resulting mess of board dependent
* #ifdef'ed co
* initialization sequence configurable to the user.
*
* The requirements for any new initalization function is simple: it
* 新的初始化函数的要求很简单:它接收到一个指向"global"数据结构的指针,
* 作为它为其的参数,并返回一个整型码,这里0表示"继续",!0表示严重错误,系统挂起
* receives a pointer to the "global da
* argument, and returns an integer return co
* "continue" and != 0 means "fatal error, hang the system".
*/
typedef int (init_fnc_t) (void); //???
//这里init_sequence[]实际上是一个函数数组,每一个数组成员就是一个函数
//这里的初始化实际上是在汇编代码的基础上进一步的操作
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup 基本处理器相关配置 --cpu/arm920t/cpu.c */
board_init, /* basic board dependent setup 基本的板级相关配置--board/smdk2410/smdk2410.c */
interrupt_init, /* set up exceptions 初始化例外处理 --cpu/arm920t/s3c24x0/interrupt.c */
env_init, /* initialize environment 初始化环境变量 --common/env_flash.c */
init_baudrate, /* initialze baudrate settings 初始化波特率设置 --lib_arm/board.c */
serial_init, /* serial communications setup 串口通讯设置 --cpu/arm920t/s3c24x0/serial.c */
console_init_f, /* stage 1 init of console 控制台初始化阶段1 --common/console.c */
display_banner, /* say that we are here 打印uboot信息 --lib_arm/board.c */
dram_init, /* configure available RAM banks 配置可用的RAM --board/smdk2410/smdk2410.c */
display_dram_config, //显示RAM配置的大小 --lib_arm/board.c
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
checkboard,
#endif
NULL,
};
//start_armboot是uboot执行的第一个C语言函数,进一步完成系统初始化工作,进入主循环,处理用户输入的命令。下面是对start_armboot的简要分析
void start_armboot (void)
{
DECLARE_GLOBAL_DA
ulong size;
init_fnc_t **init_fnc_ptr; /* init sequence */
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it 指针的可写的,因为我们分配了一个寄存器给它 */ //—— gd为gd_t类型指针,存储在寄存器r8中
//这一行的作用就是获得指针到底从哪里开始,这里的_armboot_start指向的是_TEXT_BASE
//这里可以参看工作日志里的那张图
//给全局数据变量gd安排空间
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); /* global da
/* compiler optimization barrier needed for GCC >= 3.4 */
/* 内联汇编语句__asm__("":::"memory")向GCC声明,在此内联汇编语句出现的位置内存内容可能改变了,
所以GCC在编译的时候,会将此因素考虑进去,而不会对代码进行优化及重新排序等操作,这样GCC会老老实实的生成汇编代码 */
__asm__ __volatile__("": : :"memory");
//下面这句将会把gd所指的内存区域的(gd_t)大小的空间用"0"来填入
memset ((void*)gd, 0, sizeof (gd_t)); //地址的清零,因为现在还没有做任何操作
//给板子数据变量gd->bd安排空间
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); /* board info 地址*/
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start; /* .text段和.da
//假如我们要实现很多函数的调用,并且每个函数都有独立的功能,并且我们要按一定顺序去执行它的话,那么我们可以把函数可以看做为一个数组的成员,
//这样的话,我们就可以做一个循环,按顺序调用这些函数
//这个循环的结束条件是当init_fnc_ptr为空的时候
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { /* 按照initialization sequence进行初始化 */
if ((*init_fnc_ptr)() != 0) { /* where 0 means "continue" and != 0 means "fatal error, hang the system". */
hang (); //????????
}
}
puts("Init flash...\n");
/* configure available FLASH banks */
//配置可用的flash
size = flash_init (); /* init nor flash */
display_flash_config (size);
#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, defined in start.S */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); /* round up to nearest full page */
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 */
//初始化堆空间
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND */
#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 */
//从环境变量中获取ip地址
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* MAC Address */
//以太网接口MAC地址
{
int i;
ulong reg;
char *s, *e;
uchar 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. *///设备初始化
#ifdef CONFIG_CMC_PU2
load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
jumptable_init (); /* init jump table 跳转表初始化*/
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 */
#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); /* load address */
}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile)); /* net boot file */
}
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT
board_late_init (); /* init your board */
#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. */
//等待用户输入命令的时候,就会走到这块。
//循环不断执行
//主循环函数处理执行用户命令--common/main.c
//此时,整个uboot的执行就进入等待用户输入命令,解析并执行命令的死循环中
for (;;) {
main_loop (); //main_loop函数可以接收用户输入的参数然后对其进行解析,解析完之后就会去执行相应的一些命令
}
/* NOTREACHED - no way out of command loop except booting */
}