版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012351051/article/details/86601249
接上述(二)分析,start.S进行关键 外围初始化后, 主要包括SDAM、调试串口、堆栈,代码搬迁后,会 跳转到start_armboot函数中,简单的总结是:
(1)进行各种板级初始化。
(2)环境变量初始化。
(3)Nand Flash初始化,这里还是有点存疑的,因为采用Nand flash进行存储代码的话,CPU上电后,有一个内部RAM,不大,有的是4K,有的是更大,CPU会将内部RAM的地址映射为0,而且会自动的与Nand Flash进行通信,将4K或者更多的代码,先自动搬迁到内部RAM中执行,这是必然的,要不然程序如何去执行,从这一点来看,这部分的nand flash读驱动,是CPU自带的,但是我们目前只能理解为这个读驱动,厂家是没有对用户开放的,如果用户想要做nand flash的读写,是需要用户自己去编写nand flash初始化驱动的。
(4) 以太网接口初始化。
(5)其他硬件初始化。
(6)进入main_loop循环执行,这个main_loop是无法自己跳出的,除非boot,也是在这个步骤进行u-boot的
各种命令执行,当然也包括,引导 选项去kernel,
去掉编译条件后,分析如下:
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr; //初始化函数数组指针,包含了很多初始化函数
char *s;
//init_fnc_ptr指向init_sequence,包含板子初始化、环境变量、控制台等初始化
unsigned long addr;
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
//gd为u-boot中定义的全局变量,这个变量是一个结构体,用于程序间的同步
//主要包含板级参数指针,代码搬迁标志、波特率、重定位补偿值、环境变量地址等
//先初始化gd,即清空
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
//u-boot镜像大小
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 ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN);
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
/* board init may have inited fb_base */
if (!gd->fb_base) {
/*
* 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);
lcd_setmem (addr);
gd->fb_base = addr;
}
//NAND Flash初始化,会有对应的输出信息
puts ("NAND: ");
nand_init(); /* go init the NAND */
//onenand初始化
onenand_init();
AT91F_DataflashInit();
dataflash_print_info();
//mmc初始化
puts ("MMC: ");
mmc_initialize (gd->bd);
//初始化环境变量
env_relocate ();
/* must do this after the framebuffer is allocated */
drv_vfd_init();
serial_initialize();
//此处是致远电子自己修改增加的一个初始化函数,主要是为了自动识别
//sdram的大小,来区别他们的开发板型号,因为他们有283,还有287
getddr2_information();
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
stdio_init (); /* get the devices list going. */
jumptable_init ();
/* Initialize API */
api_init ();
console_init_r (); /* fully init console as a device */
//一些通用标准的外围初始化
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
/* miscellaneous platform dependent initialisations */
misc_init_r ();
//使能中断
/* enable exceptions */
enable_interrupts ();
//以太网初始化
/* Perform network card initialisation if necessary */
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
cs8900_get_enetaddr ();
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
extern void enc_set_mac_addr (void);
enc_set_mac_addr ();
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
//板子的一些最新的初始化
board_late_init ();
check_recovery_mode();
puts ("Net: ");
eth_initialize(gd->bd);
debug ("Reset Ethernet PHY\n");
reset_phy();
//进入main_loop循环,
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
//一旦进入main_loop函数后,是无法跳出的,除非重新boot
/* NOTREACHED - no way out of command loop except booting */
}