uboot第二阶段启动过程

void start_armboot (void)
{
 init_fnc_t **init_fnc_ptr;
 char *s;
 int mmc_exist = 0;
 
 /*全局数据结构初始化*/
 ulong gd_base;
 gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);//全局变量地址
 
 gd = (gd_t*)gd_base;


  typedef struct global_data {
  bd_t  *bd;//板子数据指针
  unsigned long flags;//指示标志,如设备已经初始化标志等
  unsigned long baudrate;//串口波特率
  unsigned long have_console; /* serial_init() was called,串口初始化标志 */
  unsigned long reloc_off; /* Relocation Offset,重定位偏移,就是实际定向的位置与编译连接时指定的位置之差,一般为0 */
  unsigned long env_addr; /* Address  of Environment struct,环境参数地址 */
  unsigned long env_valid; /* Checksum of Environment valid? 环境参数CRC检验有效标志*/
  unsigned long fb_base; /* base address of frame buffer,base address of frame buffe */
  void  **jt;  /* jump table,跳转表 */
 } 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));//板子数据变量地址
  typedef struct bd_info {
  int   bi_baudrate; /* serial console baudrate,串口波特率 */
  unsigned long bi_ip_addr; /* IP Address,IP地址 */
  unsigned char bi_enetaddr[6]; /* Ethernet adress,MAC地址 */
  struct environment_s        *bi_env;/*环境变量开始地址*/
  ulong         bi_arch_number; /* unique id for this board,板子唯一ID */
  ulong         bi_boot_params; /* where this board expects params,启动参数 */
  struct    /* RAM configuration,RAM配置 */
  {
  ulong start;
  ulong size;
  }   bi_dram[CONFIG_NR_DRAM_BANKS];
 } bd_t;

 typedef struct environment_s

    {
     
        unsigned long crc;                      
             #ifdef CFG_REDUNDAND_ENVIRONMENT
        
           unsigned char flags;             
            #endif
            unsigned char data[ENV_SIZE];          
       } env_t;


 memset (gd->bd, 0, sizeof (bd_t));//板子数据清零

 monitor_flash_len = _bss_start - _armboot_start;//取boot长度

 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   hang ();
  }
 }


  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, 打印u-boot信息 */
 #if defined(CONFIG_DISPLAY_CPUINFO)
  print_cpuinfo,  /* display cpu info (and speed) */
 #endif
 #if defined(CONFIG_DISPLAY_BOARDINFO)
  checkboard,  /* display board info,显示板子信息 */
 #endif
 #endif
 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
  init_func_i2c,
 #endif
  dram_init,  /* configure available RAM banks,配置可用的RAM */
  display_dram_config,//显示RAM的配置大小
  NULL,
 };


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

size = flash_init (); //配置可用flash

typedef struct {
 ulong size;   /* total bank size in bytes  */
 ushort sector_count;  /* number of erase units  */
 ulong flash_id;  /* combined device & manufacturer code */
 ulong start[CFG_MAX_FLASH_SECT];   /* physical sector start addresses */
 uchar protect[CFG_MAX_FLASH_SECT]; /* sector protection status */
#ifdef CFG_FLASH_CFI
 uchar portwidth;  /* the width of the port  */
 uchar chipwidth;  /* the width of the chip  */
 ushort buffer_size;  /* # of bytes in write buffer  */
 ulong erase_blk_tout;  /* maximum block erase timeout  */
 ulong write_tout;  /* maximum write timeout  */
 ulong buffer_write_tout; /* maximum buffer write timeout  */
 ushort vendor;   /* the primary vendor id  */
 ushort cmd_reset;  /* vendor specific reset command */
 ushort interface;  /* used for x8/x16 adjustments  */
 ushort legacy_unlock;  /* support Intel legacy (un)locking */
 uchar manufacturer_id; /* manufacturer id   */
 ushort device_id;  /* device id    */
 ushort device_id2;  /* extended device id   */
 ushort ext_addr;  /* extended query table address  */
 ushort cfi_version;  /* cfi version    */
 ushort cfi_offset;  /* offset for cfi query   */
 ulong   addr_unlock1;  /* unlock address 1 for AMD flash roms  */
 ulong   addr_unlock2;  /* unlock address 2 for AMD flash roms  */
 const char *name;  /* human-readable name                 */
#endif
} flash_info_t; //flash信息结构体

ulong flash_init (void)
{
 int i, j;
 ulong size = 0;

 for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
 ulong flashbase = 0;

 flash_info[i].flash_id =   (MX_MANUFACT & FLASH_VENDMASK) | (MX_ID_LV640EB & FLASH_TYPEMASK);//flash_info[0].flash_id =0;
 flash_info[i].size = FLASH_BANK_SIZE; //flash_info[0].size = 8M;
 flash_info[i].sector_count = CFG_MAX_FLASH_SECT; //flash_info[i].sector_count =135;

 memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); //清零
 if (i == 0)
 flashbase = CFG_FLASH_BASE; //flash基地址0x80000000
 else
      panic ("configured too many flash banks!\n");
 for (j = 0; j < flash_info[i].sector_count; j++) {
#if
defined(CONFIG_MX_LV640EB)
       if (j <=7) { /* 1st ~ 8th sect size : 8 kb */
       flash_info[i].start[j] =  flashbase + j * BOOT_SECT_SIZE;
    } else { /* 9th ~ 135th sect size : 64 kb */
       flash_info[i].start[j] = flashbase + (j - 7) * MAIN_SECT_SIZE;
    }
 }
  size += flash_info[i].size; //总大小
}

 flash_protect (FLAG_PROTECT_SET,
         CFG_FLASH_BASE,
         CFG_FLASH_BASE + monitor_flash_len - 1,
         &flash_info[0]);

 flash_protect (FLAG_PROTECT_SET,
         CFG_ENV_ADDR,
         CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);

 return size;
}


mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);//初始化堆空间
mmc_exist = mmc_initialize(gd->bd); //SD、MMC初始化
if (mmc_exist != 0);
nand_init();
//nand初始化

void nand_init(void)
{
 nand_probe(CFG_NAND_BASE);
        if (nand_dev_desc[0].ChipID != NAND_ChipID_UNKNOWN) {
                print_size(nand_dev_desc[0].totlen, "\n");
        }
}


/* initialize environment , 重新定位环境变量*/
 env_relocate ();

void env_relocate (void)
{
 DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
  gd->reloc_off);

#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);
#endif

if (gd->env_valid == 0) {
  set_default_env();
 } else {
  env_relocate_spec ();
 }
 gd->env_addr = (ulong)&(env_ptr->data);

}
 
 serial_initialize(); //串口初始化
 

/*主要是从环境中读IP、MAC,然后赋给gd->bd对应域就OK*/
 /* IP Address , 从环境变量中获取地址*/
 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

 /* MAC Address,从环境变量中获取IP地址 */
 {
  int i;
  ulong reg;
  char *s, *e;
  char 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(),创建了devlist,但是只有一个串口设备注册在内。显然,devlist中的设备都是可以做为console的。*/

 devices_init (); /* get the devices list going.设备初始化 */

int devices_init (void)
{
#ifndef CONFIG_ARM     /* already relocated for current ARM implementation */
 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)
 i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);//初始化i2c接口,i2c没有注册到devlist中去
#endif
 return (0);
}

 
 jumptable_init (); //跳转初始化表
 
/*查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称,再按照环境指定的名称搜索devlist,将搜到的设备指针赋给标准IO数组stdio_devices[]。置gd->flag标志

GD_FLG_DEVINIT。这个标志影响putc,getc函数的实现,未定义此标志时直接由串口serial_getc和serial_putc实现,定义以后通过标准设备数组stdio_devices[]中的putc和getc来实现IO
为什么要使用devlist,std_device[]?
为了更灵活地实现标准IO重定向,任何可以作为标准IO的设备,如USB键盘,LCD屏,串口等都可以对应一个device_t的结构体变量,只需要实现getc和putc等函数,就能加入到devlist列表中去,也就可
以被assign为标准IO设备std_device中去。如函数
int console_assign (int file, char *devname); /* Assign the console 重定向标准输入输出*/
这个函数功能就是把名为devname的设备重定向为标准IO文件file(stdin,stdout,stderr)。其执行过程是在devlist中查找devname的设备,返回这个设备的device_t指针,并把指针值赋给std_device[file]。
*/

 console_init_r (); /* fully init console as a device, 完整地初始化控制台设备*/


/* enable exceptions ,使能外部中断,由于CONFIG_USE_IRQ没有定义,空实现*/
 enable_interrupts ();

 cs8900_get_enetaddr (gd->bd->bi_enetaddr); /*设置CS8900的MAC地址。*/


 /* 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 ();

 puts ("Net:   ");

/*初始化以太网*/
 eth_initialize(gd->bd);


 debug ("Reset Ethernet PHY\n");
 reset_phy();


 puts("IDE:   ");
 ide_init();

 /* main_loop() can return to retry autoboot, if so just run it again. */
 for (;;) {
  main_loop ();
 }

你可能感兴趣的:(arm)