zoukankan      html  css  js  c++  java
  • 6410 uboot stage 2(start_armboot)

    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是带参数的打断,
  • 相关阅读:
    ASP.net实现WEB站点的后台定时任务[转]
    個人所得稅計算
    當VS2005 遇上 LINQ[转]
    NBearV3中文教程总目录
    C#开源框架
    excel 不能使用对象链接和嵌入的错误
    PetShop 学习
    ADHelper类与扩展应用
    (javascript,treeview)treeview通过checkbox来进行全选单选
    (javascript)动态添加的控件如何设置其属性
  • 原文地址:https://www.cnblogs.com/autum/p/start_armboot.html
Copyright © 2011-2022 走看看