这里主要对start_armboot函数执行流程进行分析
首先是定义一个指针变量DECLARE_GLOBAL_DATA_PTR,这是一个宏定义,原型在
u-boot-1.1.3\include\asm-arm\global_data.h文件中
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
其实就是定义一个指向结构体gd_t的寄存器变量,
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* 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));
这段代码是为结构体指针变量分配内存
_armboot_start=0x33f80000,
CFG_MALLOC_LEN=0x30000,
sizeof(gd_t)=0x24,
sizeof(bd_t)=0x24
接下来是一个for循环,作一系列的初始化工作
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
init_fnc_ptr这个变量的定义如下
init_fnc_t **init_fnc_ptr;
它是指向指针的指针变量,变量的类型为init_fnc_t,这是一个使用typedef定义的函数类型,
typedef int (init_fnc_t) (void);
全局变量init_sequence的定义如下
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup u-boot-1.1.3\cpu\arm920t\cpu.c*/
board_init, /* basic board dependent setup u-boot-1.1.3\board\te2410\te2410.c*/
interrupt_init,/* set up exceptions u-boot-1.1.3\cpu\arm920t\s3c24x0\interrupts.c*/
env_init, /* initialize environment u-boot-1.1.3\common\env_nand.c*/
init_baudrate, /* initialze baudrate settings u-boot-1.1.3\lib_arm\board.c*/
serial_init, /* serial communications setup u-boot-1.1.3\cpu\arm920t\s3c24x0\serial.c*/
console_init_f, /* stage 1 init of console u-boot-1.1.3\common\console.c*/
display_banner, /* say that we are here u-boot-1.1.3\lib_arm\board.c*/
dram_init, /* configure available RAM banks u-boot-1.1.3\board\te2410\te2410.c*/
display_dram_config,
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
checkboard,
#endif
NULL,
};
可以看出这里定义了一个指针数组,它的每一个元素都是指针变量,这些指针变量指向的类型为init_fnc_t,在C语言中函数的入口地址就是函数名,所以这里使用一系列函数名来初始化这个数组
现在来看看到底做了哪些初始化工作
int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;
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;
}
其实这个函数没有做任何工作,因为CONFIG_USE_IRQ这个宏没有定义,那么怎么知道这个宏是否被定义了呢,在使用SourceInsight的搜索功能时,发现有些宏会在很多头文件被定义,而我们又很难判断这些头文件是否被当前的c文件包含了,我使用一个简便的方法,利用编译器的预处理功能,
#ifdef CONFIG_USE_IRQ
#error CONFIG_USE_IRQ_xxxxxx
DECLARE_GLOBAL_DATA_PTR;
IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
这样如果这个宏被定义了,那么编译时就会报错输出#error CONFIG_USE_IRQ_xxxxxx,并终止编译.
board_init主要完成了与硬件相关的寄存器的初始化:时钟、GPIO、使能ICache和DCache,
interrupt_init中断初始化
env_init环境变量相关的初始化
init_baudrate波特率初始化
serial_init串口初始化
console_init_f控制台初始化
display_banner从串口输出u-boot相关的信息
dram_init初始化DRAM
display_dram_config从串口输出DRAM的配置信息
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
#ifdef CONFIG_VFD//宏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//宏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 */
/*_armboot_start=0x33f80000,CFG_MALLOC_LEN=0x30000,mem_malloc_init对*/
/*(0x33f80000-0x30000)~(0x33f80000)这段存储区清零*/
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* go init the NAND 探测NAND flash并根据NAND flash的类型*/
/*填充相应的数据结构,全局结构体变量nand_dev_desc[0](类型struct nand_chip)*/
#endif
#ifdef CONFIG_HAS_DATAFLASH//宏CONFIG_HAS_DATAFLASH没有定义
AT91F_DataflashInit();
dataflash_print_info();
#endif
env_relocate ();
这个函数在u-boot-1.1.3\common\env_common.c中
void env_relocate (void)
{
DECLARE_GLOBAL_DATA_PTR;
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);//为环境变量分配内存,env_ptr是全局变量,在下面的
//env_relocate_spec ()函数中将环境变量读取到env_ptr指向的内存中
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;
/*在env_init函数中gd->env_valid被初始化为1*/
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 ();/*该函数实现真正的重定位功能,先从NAND flash中读取环境变量,如果读取成*/
/*功,并且crc校验正确的话,就使用NAND flash中读取出来的环境变量,否则使用默认的环境变量*/
}
gd->env_addr = (ulong)&(env_ptr->data);//填充结构体变量
#ifdef CONFIG_AMIGAONEG3SE//没有定义
disable_nvram();
#endif
}
现在进入函数env_relocate_spec ()
void env_relocate_spec (void)//u-boot-1.1.3\common\env_nand.c
{
#if !defined(ENV_IS_EMBEDDED)
int ret, total;
//从nand flash 中读取环境变量到全局变量env_ptr指向的内存中,这里需要注意的是CFG_ENV_OFFSET、//CFG_ENV_SIZE这两个宏定义,它们表示从NAND flash中偏移为CFG_ENV_OFFSET处读取大小为CFG_ENV_SIZE字节//的数据,注意这两个宏定义决定了环境变量在nand flash中保存的位置和大小,不能和nand flash 中的其他分区(kernel分区、rootfs分区)相冲突,不然在执行saveenv命令时可能会覆盖其他分区的内容,导致系统无法启动.
ret = nand_rw(nand_dev_desc + 0,
NANDRW_READ | NANDRW_JFFS2, CFG_ENV_OFFSET,CFG_ENV_SIZE,
&total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)//ret=0,total==CFG_ENV_SIZE=65536
return use_default();//使用默认的环境变量
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc){
puts(" CRC ERROR!!!!!!!!!! \r\n");
return use_default();
}
#endif /* ! ENV_IS_EMBEDDED */
}
到此env_relocate ()结束.
#ifdef CONFIG_VFD//宏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");//从环境变量获取ip地址并填充gd结构体变量
/* MAC Address */
{
int i;
ulong reg;
char *s, *e;
uchar tmp[64];
/*从环境变量获取网卡的MAC地址并填充gd结构体变量 */
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. *///注册串口设备
devices_init ()在u-boot-1.1.3\common\devices.c文件中.
int devices_init (void)
{
#ifndef CONFIG_ARM /* already relocated for current ARM implementation *///CONFIG_ARM已定义
DECLARE_GLOBAL_DATA_PTR;
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)//not defined
i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);
#endif
#ifdef CONFIG_LCD//not defined
drv_lcd_init ();
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)//not defined
drv_video_init ();
#endif
#ifdef CONFIG_KEYBOARD//not defined
drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER//not defined
drv_logbuff_init ();
#endif
drv_system_init ();
#ifdef CONFIG_SERIAL_MULTI//not defined
serial_devices_init ();
#endif
#ifdef CONFIG_USB_TTY//not defined
drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE//not defined
drv_nc_init ();
#endif
return (0);
}
drv_system_init ()这个函数对串口设备初始化,然后注册串口设备.
继续往下
/*跳转表初始化,函数在u-boot-1.1.3\common\exports.c文件中*/
jumptable_init ();
/*console_init_r函数在u-boot-1.1.3\common\console.c文件中*/
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);//获取网卡的MAC地址
#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);//读取环境变量loadaddr到全局变量load_addr中
}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));//读取环境变量bootfile到
//全局变量BootFile中
}
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT//没有定义
board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)//没有定义
puts ("Net: ");
eth_initialize(gd->bd);
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();//进入主循环
}
SDRAM 内存分配图