代码改变世界

6410 u-boot stage 2(start_armboot)

2012-06-06 20:21  至上  阅读(746)  评论(0编辑  收藏  举报

start_armboot()函数位于lib_arm/board.c文件中。主要完成的任务有

  1. 硬件初始化(UART Timer 网络等)
  2. 将kernel映像和根文件系统ramdisk映像从FLASH 上载到RAM 空间
  3. 命令交互(main_loop)
  4. 传递参数(tag链表)
  5. 加载linux内核镜像并跳转

多处地址的运算用到这张图。

先介绍下gd_t数据结构,该数据结构保存了u-boot需要的配置信息,注释简单明了:

  • typedef    struct    global_data {
  •     bd_t        *bd;     与板子相关
  •     unsigned long    flags;       
  •     unsigned long    baudrate;   波特率
  •     unsigned long    cpu_clk;    /* CPU clock in Hz!        */
  •     unsigned long    have_console;    /* serial_init() was called */
  •     unsigned long    ram_size;    /* RAM size */
  •     unsigned long    reloc_off;    /* Relocation Offset */
  •     unsigned long    env_addr;    /* Address  of Environment struct */
  •     unsigned long    env_valid;    /* Checksum of Environment valid */
  • #if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
  •     unsigned long    post_log_word;    /* Record POST activities */
  •     unsigned long    post_init_f_time; /* When post_init_f started */
  • #endif
  •     void        **jt;        /* Standalone app jump table */
  • } gd_t;
  • /* flags */
  • #define    GD_FLG_RELOC    0x00001        /* Code was relocated to RAM        */
  • #define    GD_FLG_DEVINIT    0x00002        /* Devices have been initialized    */
  • #define    GD_FLG_SILENT    0x00004        /* Silent mode                */

介绍下bd_t结构体,保存于板子相关的配置参数:

  • typedef struct bd_info {
  •     unsigned int   bi_tag;        /* Should be 0x42444944 "BDID" */
  •     unsigned int   bi_size;       /* Size of this structure */
  •     unsigned int   bi_revision;   /* revision of this structure */
  •     unsigned int   bi_bdate;      /* bootstrap date, i.e. 0x19971106 */
  •     unsigned int   bi_memstart;   /* Memory start address */
  •     unsigned int   bi_memsize;    /* Memory (end) size in bytes */
  •     unsigned int   bi_intfreq;    /* Internal Freq, in Hz */
  •     unsigned int   bi_busfreq;    /* Bus Freq, in Hz */
  •     unsigned int   bi_cpmfreq;    /* CPM Freq, in Hz */
  •     unsigned int   bi_brgfreq;    /* BRG Freq, in Hz */
  •     unsigned int   bi_vco;        /* VCO Out from PLL */
  •     unsigned int   bi_pci_freq;   /* PCI Freq, in Hz */
  •     unsigned int   bi_baudrate;   /* Default console baud rate */
  •     unsigned int   bi_immr;       /* IMMR when called from boot rom */
  •     unsigned char  bi_enetaddr[6];
  •     unsigned int   bi_flashbase;  /* Physical address of FLASH memory */
  •     unsigned int   bi_flashsize;  /* Length of FLASH memory */
  •     int            bi_flashwidth; /* Width (8,16,32,64) */
  •     unsigned char *bi_cmdline;    /* Pointer to command line */
  •     unsigned char  bi_esa[3][6];  /* Ethernet station addresses */
  •     unsigned int   bi_ramdisk_begin, bi_ramdisk_end;
  •     struct {                      /* Information about [main] video screen */
  •         short x_res;              /*   Horizontal resolution in pixels */
  •         short y_res;              /*   Vertical resolution in pixels */
  •         short bpp;                /*   Bits/pixel */
  •         short mode;               /*   Type of pixels (packed, indexed) */
  •         unsigned long fb;         /*   Pointer to frame buffer (pixel) memory */
  •     } bi_video;
  •     void         (*bi_cputc)(char);   /* Write a character to the RedBoot console */
  •     char         (*bi_cgetc)(void);   /* Read a character from the RedBoot console */
  •     int          (*bi_ctstc)(void);   /* Test for input on the RedBoot console */
  • } bd_t;

start_armboot()源码:

  1. void start_armboot (void)
  2. {
  3. //typedef int (init_fnc_t)(void);
  4.     init_fnc_t **init_fnc_ptr;   //初始化硬件时使用,这是函数指针的一种巧妙用法
  5.  //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 */
                           //     display_banner,
                           //     dram_init,        /* configure available RAM banks */
                           //     display_dram_config,
                           //     NULL,
                           //     };
  6.     char *s;
  7. #ifndef CFG_NO_FLASH
  8.     ulong size;
  9. #endif
  10. #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
  11.     unsigned long addr;
  12. #endif
  13. #if defined(CONFIG_BOOT_MOVINAND)    //SDcard
  14.     uint *magic = (uint *) (PHYS_SDRAM_1);
  15. #endif
  16.     /* Pointer is writable since we allocated a register for it */
  17. #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
  18.     ulong gd_base;
  19.     gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);  //由图可知。不过+CFG_UBOOT_SIZE有点奇怪啊?
  20. #ifdef CONFIG_USE_IRQ
  21.     gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);  //如图: 因为IRQ与FIQ在下面有独立堆栈空间。
  22. #endif
  23.     gd = (gd_t*)gd_base;
  24. #else
  25.     gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));  //_armboot_start又是什么地址呢?不是镜像在SFRAM中的起始地址吧?
  26. #endif
  27. //从上面可知,是在动态分配全局变量区的首地址,为什么呢?而堆栈大小的变化都会影响到其起始地址的变化。
  28.     /* compiler optimization barrier needed for GCC >= 3.4 */
  29.     __asm__ __volatile__("": : :"memory");   
  30. //“memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作 废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了//cpu又将registers,cache中的数据用于去优化指令,而避免去访问内 存。”
  31. //__asm__用于指示编译器在此插入汇编语句
  32. //__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
  33. //:::表示这是个空指令
  34.     memset ((void*)gd, 0, sizeof (gd_t));
  35.     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //又吃掉了用户空间的一段内存。
  36.     memset (gd->bd, 0, sizeof (bd_t));  //仅仅是为2个数据结构初始化为0?
  37. // gd_tbd_t中存放着随后会用到的相关信息如环境变量,跳转表等


  38.     monitor_flash_len = _bss_start - _armboot_start;  //stage2代码所占的空间大小
  39.     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  40.         if ((*init_fnc_ptr)() != 0) {
  41.             hang ();   // 各个模块的硬件初始化  初始化成功返回的是一个整数0。如果不等于0,则会打印一段出错的提示。
  42. //void hang (void)
    //{
  43. //  puts ("### ERROR ### Please RESET the board ###\n");
    //   for (;;);
    //}
  44.         }
  45.     }
  46. #ifndef CFG_NO_FLASH
  47.     /* configure available FLASH banks */
  48.     size = flash_init ();  //这是有选择的硬件初始化,不是必须得。都属于选择性编译。
  49.     display_flash_config (size);//打印flash配置信息
  50. #endif /* CFG_NO_FLASH */
  51. //如果启用CONFIG_VFD,则在RAMbss_end之后的整页处为VFD留下相应memory
  52. #ifdef CONFIG_VFD
  53. #    ifndef PAGE_SIZE
  54. #      define PAGE_SIZE 4096
  55. #    endif
  56.     /*
  57.      * reserve memory for VFD display (always full pages)
  58.      */
  59.     /* bss_end is defined in the board-specific linker script */  
  60.     addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
  61.     size = vfd_setmem (addr);
  62.     gd->fb_base = addr;
  63. #endif /* CONFIG_VFD */
  64. //如果启用CONFIG_LCD,则在RAMbss_end之后的整页处为LCD留下相应memory  那么VFD与LCD可以一起定义么?
  65. #ifdef CONFIG_LCD
  66. #    ifndef PAGE_SIZE
  67. #      define PAGE_SIZE 4096
  68. #    endif
  69.     /*
  70.      * reserve memory for LCD display (always full pages)
  71.      */
  72.     /* bss_end is defined in the board-specific linker script */
  73.     addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
  74.     size = lcd_setmem (addr);
  75.     gd->fb_base = addr;
  76. #endif /* CONFIG_LCD */
  77.     /* armboot_start is defined in the board-specific linker script */
  78. #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
  79.     mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);
  80. #else
  81.     mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
  82. #endif
  83. #if defined(CONFIG_SMDK6400) || defined(CONFIG_SMDK6410) || defined(CONFIG_SMDK6430) || defined(CONFIG_SMDK2450) || defined(CONFIG_SMDK2416)
  84. #if defined(CONFIG_NAND)
  85.     puts ("NAND:    ");
  86.     nand_init();        /* go init the NAND */   //初始化nand
  87. #endif
  88. #if defined(CONFIG_ONENAND)
  89.     puts ("OneNAND: ");
  90.     onenand_init();        /* go init the One-NAND */  //初始化onenand
  91. #endif
  92. #if defined(CONFIG_BOOT_MOVINAND)
  93.     puts ("MMC:     ");
  94.     if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
  95.         printf("Boot up for burning\n");
  96.     } else {
  97.         movi_set_capacity();
  98.         movi_set_ofs(MOVI_TOTAL_BLKCNT);
  99.         movi_init();          //初始化sdcard
  100.     }
  101. #endif
  102. #else
  103. #if (CONFIG_COMMANDS & CFG_CMD_NAND)
  104.     puts ("NAND:    ");
  105.     nand_init();        /* go init the NAND */  //这也是初始化nand
  106. #endif
  107. #endif
  108. #ifdef CONFIG_HAS_DATAFLASH
  109.     AT91F_DataflashInit();
  110.     dataflash_print_info();
  111. #endif
  112.     /* initialize environment */
  113.     env_relocate ();
  114. #ifdef CONFIG_VFD
  115.     /* must do this after the framebuffer is allocated */
  116.     drv_vfd_init();
  117. #endif /* CONFIG_VFD */
  118.     /* IP Address */
  119.     gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");  //读取IP地址,保存到bd_t数据结构中
  120.     /* MAC Address *///MAC地址的初始化
  121.     {
  122.         int i;
  123.         ulong reg;
  124.         char *s, *e;
  125.         char tmp[64];
  126.         i = getenv_r ("ethaddr", tmp, sizeof (tmp));
  127.         s = (i > 0) ? tmp : NULL;
  128.         for (reg = 0; reg < 6; ++reg) {
  129.             gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
  130.             if (s)
  131.                 s = (*e) ? e + 1 : e;
  132.         }
  133. #ifdef CONFIG_HAS_ETH1
  134.         i = getenv_r ("eth1addr", tmp, sizeof (tmp));
  135.         s = (i > 0) ? tmp : NULL;
  136.         for (reg = 0; reg < 6; ++reg) {
  137.             gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
  138.             if (s)
  139.                 s = (*e) ? e + 1 : e;
  140.         }
  141. #endif
  142.     }
  143.     devices_init ();    /* get the devices list going. *///获得设备列表
  144. #ifdef CONFIG_CMC_PU2
  145.     load_sernum_ethaddr ();
  146. #endif /* CONFIG_CMC_PU2 */
  147.     jumptable_init ();//跳转表
  148.     console_init_r ();    /* fully init console as a device *///控制台
  149. #if defined(CONFIG_MISC_INIT_R)
  150.     /* miscellaneous platform dependent initialisations */
  151.     misc_init_r ();
  152. #endif
  153.     /* enable exceptions */
  154.     enable_interrupts ();//打开中断,在stage1阶段是关掉的,在这里打开
  155.     /* Perform network card initialisation if necessary */
  156. #ifdef CONFIG_DRIVER_CS8900//网卡初始化
  157.     cs8900_get_enetaddr (gd->bd->bi_enetaddr);
  158. #endif
  159. #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
  160.     if (getenv ("ethaddr")) {
  161.         smc_set_mac_addr(gd->bd->bi_enetaddr);
  162.     }
  163. #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
  164.     /* Initialize from environment */
  165.     if ((s = getenv ("loadaddr")) != NULL) {
  166.         load_addr = simple_strtoul (s, NULL, 16);
  167.     }
  168. #if (CONFIG_COMMANDS & CFG_CMD_NET)//获取启动文件   
  169.     if ((s = getenv ("bootfile")) != NULL) {
  170.         copy_filename (BootFile, s, sizeof (BootFile));
  171.     }
  172. #endif    /* CFG_CMD_NET */
  173. #ifdef BOARD_LATE_INIT
  174.     board_late_init ();
  175. #endif
  176. #if (CONFIG_COMMANDS & CFG_CMD_NET)
  177. #if defined(CONFIG_NET_MULTI)
  178.     puts ("Net:     ");
  179. #endif
  180.     eth_initialize(gd->bd);
  181. #endif
  182.     /* main_loop() can return to retry autoboot, if so just run it again. */  //这边怎么是死循环呢?不是有延迟3秒的吗,那么传递参数,跳转到内核在哪儿呢?都在do_bootm_linux函数中。
  183.     for (;;) {
  184.         main_loop ();
  185.     }
  186.     /* NOTREACHED - no way out of command loop except booting */ //就是说boot命令是可以打断循环的,可以开始内核的启动,而bootm是带参数的打断,