uboot 分析之二 start_armboot()函数

第一个c函数位于arch/arm/lib/board.c

 start_armboot会马上申请三块空间,一块用来分配给malloc管理,一份用来存储gd_t,一份用来存储bd_t。

他们在RAM中内存布局如上图所示。

void start_armboot (void)
{
 init_fnc_t **init_fnc_ptr;
 char *s;
 int delay = 100000;
 int  *p3_output_set, *p3_output_clr;


#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
 unsigned long addr;
#endif

 /* Pointer is writable since we allocated a register for it */
 gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));     //gd指向uboot之前的地址。
 /* 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));  //gd->bd指向gd之前。


 memset (gd->bd, 0, sizeof (bd_t));

 gd->flags |= GD_FLG_RELOC;

 monitor_flash_len = _bss_start - _armboot_start;

 
 /*循环调用init_sequence的初始化函数*/
 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,
   CONFIG_SYS_MALLOC_LEN);//初始化用作malloc的内存空间。

#ifndef CONFIG_SYS_NO_FLASH     //目前3250不支持nor flash.
 /* configure available FLASH banks */
 display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */

#ifdef CONFIG_VFD                //3250不支持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);
 vfd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD   //3250不支持LCD
 /* board init may have inited fb_base */
 if (!gd->fb_base) {
#  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);
  lcd_setmem (addr);
  gd->fb_base = addr;
 }
#endif /* CONFIG_LCD */

#if defined(CONFIG_CMD_NAND)
 puts ("NAND:  ");
 nand_init();  /* go init the NAND */调用driver/mtd/nand/nand.c.打印:NAND:  256 MiB
#endif
 //puts("NAND init end \n");
#if defined(CONFIG_CMD_ONENAND)  ////3250不支持
 onenand_init();
#endif

#ifdef CONFIG_HAS_DATAFLASH ////3250不支持
 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 */

#ifdef CONFIG_SERIAL_MULTI
 serial_initialize();
#endif

 /* IP Address */
 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //获取环境变量的ip地址填充gd->bd->bi_ip_addr

 stdio_init (); /* get the devices list going. */ //common/stdio.c 初始化stdio设备dev,将串口的接口注册进dev系统。

 jumptable_init ();//初始化gd->jt跳转表(common/export.c)。跳转表保存的是stdio的各个函数指针

#if defined(CONFIG_API)
 /* Initialize API */
 api_init ();
#endif

 console_init_r (); /* fully init console as a device *//(common/console.c)初始化stdin\stdout\和stderr,都指向stdio_init注册的stdio dev。gd->flags |= GD_FLG_DEVINIT;
/*输出信息:
In:    serial
Out:   serial
Err:   serial*/
#if defined(CONFIG_ARCH_MISC_INIT)
 /* miscellaneous arch dependent initialisations */
 arch_misc_init ();
#endif


#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_TI_EMAC
 /* 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);
 }
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
 /* 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);
 }
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

 /* Initialize from environment */
 if ((s = getenv ("loadaddr")) != NULL) {                       //3250目前不支持
  load_addr = simple_strtoul (s, NULL, 16);
 }
#if defined(CONFIG_CMD_NET)
 if ((s = getenv ("bootfile")) != NULL) {   //“uImage”内核镜像名
  copy_filename (BootFile, s, sizeof (BootFile));   //复制文件
 }
#endif

#ifdef BOARD_LATE_INIT
 board_late_init ();
#endif

#ifdef CONFIG_GENERIC_MMC
 puts ("MMC:   ");
 mmc_initialize (gd->bd);
#endif

#ifdef CONFIG_BITBANGMII
 bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
 puts ("Net:   ");
#endif


 eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
 debug ("Reset Ethernet PHY\n");
 reset_phy();
#endif
#endif
 
 /* main_loop() can return to retry autoboot, if so just run it again. */
 for (;;) {
  main_loop ();
 }

 /* NOTREACHED - no way out of command loop except booting */
 
}

void hang (void)
{
 puts ("### ERROR ### Please RESET the board ###\n");
 for (;;);
}

1.env_relocate ()   
void env_relocate (void)
{
。。。。。。。。。。
#ifdef ENV_IS_EMBEDDED
。。。。。。。。。。。。。。。。。。。
#else
 /*
  * We must allocate a buffer for the environment
  */
 env_ptr = (env_t *)malloc (CONFIG_ENV_SIZE);   //在内存的malloc区域申请一块内存存放环境变量。
 DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif

 if (gd->env_valid == 0) {
#if defined(CONFIG_GTH) || defined(CONFIG_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 (-60);
#endif
  set_default_env();
 }
 else {
  env_relocate_spec ();  init_sequence说到了,gd->env_valid 总为1,所以会执行这个路径。
 }
 gd->env_addr = (ulong)&(env_ptr->data);  //初始化gd->env_addr

#ifdef CONFIG_AMIGAONEG3SEs
 disable_nvram();
#endif
}
由于smartarm3250中定义了CONFIG_CMD_NAND,common/目录下的makefile会选择性的编译env_nand.c而不是其他的文件。

env_relocate_spec ();  就定义在env_nand.c。
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
 int ret;

 ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);  //CONFIG_ENV_OFFSET是在smartarm3250.h中定义的表示环境变量在flash中的偏移位置。,env_ptr是本文件内的一个全局指针。
 if (ret)
  return use_default();

 if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
  return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
#endif /* CONFIG_ENV_OFFSET_REDUND */

#if !defined(ENV_IS_EMBEDDED)
static void use_default()
{
 puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
 set_default_env();
}
#endif


readenv函数将从flash中读取环境变量到env_ptr。如果读取失败或者校验错误,则使用default_environment的内容填充env_ptr->data,并打印以下信息:*** Warning - bad CRC or NAND, using default environment\n\n
无论env_ptr->data指向的内容是从flash读出的,还是填充的default_environment,gd->env_addr = (ulong)&(env_ptr->data); 

default_environment是根据宏生成的环境变量,从flash中读出的是用户修改过的环境变量,两者可能不一样。

总结:init_sequence之后的函数基本没有涉及到硬件初始化,大多是进行环境变量和数据结构的初始化。虽然函数很长,但是大部分都没有执行。

对与两个全局结构体的初始化过程如下表所示:


arch/arm/include/asm/global_data.h    意义   赋值顺序    第一次赋值 第二次赋值 第一次赋值函数 第二次

typedef struct global_data {     uboot全局信息结构体           
                          bd_t  *bd; 指向板级信息结构体 <0> (bd_t*)((char*)gd - sizeof(bd_t));  arch/arm/lib/board.c/start_armboo  
                          unsigned long flags; 标志变量 <0><13> |= GD_FLG_RELOC |= GD_FLG_DEVINIT arch/arm/lib/board.c/start_armboo                common/console.c/console_init_r 
unsigned long baudrate; 终端波特率 <5> CONFIG_BAUDRATE(115200)  arch/arm/lib/board.c/init_baudrate  
unsigned long have_console; 是否已经调用了serial_init() <7> 1  common/console.c/console_init_f  
unsigned long env_addr; 环境变量结构体的地址 <3><10> (ulong)&default_environment[0]; (ulong)&(env_ptr->data) common/env_nand.c/env_init common/env_common.c/env_relocate  
unsigned long env_valid; 环境变量的校验码是否正确 <4> 1  common/env_nand.c/env_init  
unsigned long fb_base;  帧缓冲的基地址      
void**jt; stdio函数的指针跳转表 <12> malloc(XF_MAX * sizeof(void *))  common/export.c/jumptable_init  
} gd_t;             
       
       
       
typedef struct bd_info { 板级配置信息结构体           
int   bi_baudrate; 串口终端波特率 <6> CONFIG_BAUDRATE(115200)  arch/arm/lib/board.c/init_baudrate  
unsigned long bi_ip_addr; ip地址 <11>  getenv_IPaddr ("ipaddr")  arch/arm/lib/board.c/start_armboo  
struct environment_s        *bi_env; 环境变量结构体的地址      
 ulong         bi_arch_number;  板子编号 <1> MACH_TYPE_UBOOTSYS(MACH_TYPE_LPC3XXX)  board/zhiyuan/smartarm3250/smart3250.c/board_init  
ulong         bi_boot_params; 板子启动参数 <2> CFG_ENV_ADDR(0x80000100)  board/zhiyuan/smartarm3250/smart3251.c/board_init  
 struct { RAM描述结构体      
        ulong start; 开始地址 <8> PHYS_SDRAM_1;在smartarm3250.h中,起始地址  board/zhiyuan/smartarm3250/smart3250.c/dram_init  
        ulong size; RAM大小 <9>  0x04000000; /* 64M ,RAM大小*/  board/zhiyuan/smartarm3250/smart3250.c/dram_init  
}bi_dram[CONFIG_NR_DRAM_BANKS];       
} bd_t;            


分析,bd的bi_env因该指向env_ptr的,可是程序中没有给它赋值,也没有使用。

你可能感兴趣的:(Bootstrap和Uboot)