uboot中C語言代碼入口函數(start_armboot)的注釋

來源:互聯網
上載者:User

網上找了一篇文章,認為分析start_armboot很詳細,雖然是2440,但和6410應該改差不多

//------------start_armboot--------------------

//                功能: 完成uboot第二階級的一系列的
//                硬體初始化工作, 然後轉入main函數.
//                備忘: 該函數是C程式的入口函數,從組合語言跳轉到此 .
//---------------------------------------------
void start_armboot (void)
{
    init_fnc_t **init_fnc_ptr; //init_fnc_t 是各初始化函數的數組
    char *s;
#ifndef CFG_NO_FLASH
    ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
    unsigned long addr;
#endif
  /* Pointer is writable since we allocated a register for it

   gd_t: 定義在 /include/asm-arm/Global_data.h中,包含一些全域通用的變數.

   _armboot_start: 代碼的起始地址,它定義在start.S中的前幾行中,定義為 _start

   當系統第一次加電時,指令是從0x0地址開始執行的,所以此時的 _start值應為0x0;

   而當uboot經過代碼重定位後,指令會從 _TEXT_BASE 處開始執行,此時的 _start值就成了 _TEXT_BASE的值.

   CFG_MALLOC_LEN: 在/include/configs/smdk2440.h中有定義,

   該變數表示供malloc函數使用的記憶體池空間,代碼中定義值為:0x10000+128*1024

 |-------|<--- _armboot_start基址
 |  4    | 
 |-------|<--- malloc函數池基址
 |  3    |
 |-------|<--- (gd_t)gd(全域變數表)基址
 |  2    |
 |-------|<--- (bt_t)bd(板卡資訊表)基址
 |  1    |
  -------
   4 就是為malloc函數預留的資料空間
   3 是全資訊表gd的資料區
   2 是板卡資訊表bd的資料區
   網上找了個圖片,更能反應這個空間的分配關係:
該圖在我上一篇文章中有
 */
    //分配區域 3 給 gd ,gd是一個全域靜態變數
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");
    //把gd變數的內容填充為0 ,填充 3 區的資料為0 ,即初始化gd表.注意:這裡並沒有
    //初始化bd表,在gd表中的bd成員只是一個指標,因為對初始化的是個指標地址
    memset ((void*)gd, 0, sizeof (gd_t));
 /*
    bd_t 結構體在/include/asm-arm/U-boot.h中定義, 定義板子的一些資訊,包括:
    傳輸速率,IP地址, 乙太網路地址, 架構編碼,啟動參數 ,BANK的起始地址和大小等
 */
    //分配區域 2 給bd, bd的基址 = gd的基址 - bd的尺寸
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
 
    //把區域 2 填充為 0 ,即初始化 bd 表
    memset (gd->bd, 0, sizeof (bd_t));
 /*monitor_falsh_len定義在 /lib_arm/Board.c
 
    在bin檔案中 BSS 段和 TEXT 段和 DATA 段存放的順序同前向後依次是:
    TEXT(程式碼片段 RO)    DATA(已初始化資料區段 RW)   BSS(未初始化資料區段 ZI)
    所以 _bss_start 的基址等於 TEXT的長度加上DATA的長度.
    即: _bss_start(BSS段基址) = 程式碼片段長度+資料區段長度
 
    BSS(Block Started by Symbol)段是未被初始化的資料區段,是存放程式中
    未被初始化的全域變數的一塊記憶體地區,初始化時應清零;該段只有
    名稱和大小卻沒有值;該段不包含任何資料,只是簡單的維護開始和
    結束的地址,以便記憶體區能在運行時被有效地清零,它在應用程式的
    映像檔案(ARM中也即bin檔案)中並不存在.
    text :程式碼片段,是包含程式碼的段
    dat  :已經初始化的資料區段,儲存已經初始化的全域變數.
 
    在嵌入式系統中,bin檔案(又稱Image檔案)中只包含text和data段,
    而bss段不在其中,它是由系統初始化為零.
  */
    //_armboot_start 在start.S中定義為_start,而_start為代碼的起始地址
    //只包含 RO(TEXT) 和 RW(DATA) 段.重定位前的值為0x0,此時指向flash,
    //重定位後則指向RAM中的某一地址
    //由此可以知道:  _bss_start - _armboot_start 的值即是在第一階段從
    //flash中重定位到RAM中的那部分代碼的長度,也即可TEXT和DATA資料區段,
    //這個值與start.S中的重定位那部分代碼所計算的值是相等的
    //所以,monitor_flash_len表示從flash中搬來的代碼的長度
    monitor_flash_len = _bss_start - _armboot_start;  //_bss_start 在u-boot.lds中定位
 
    //各設定的初始化.當傳回值不為0時表示初始化失敗 ,此時會調用 hang()函數
    //列印一錯誤提示資訊,然後進入死迴圈
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }
    //CFG_NO_FLASH 表示沒有flash,如果沒定義該常量則表示板子上有flash,此時調用flash_init()對其進行初始化.
#ifndef CFG_NO_FLASH
    /* configure available FLASH banks */
    size = flash_init ();
    display_flash_config (size); //列印flash的資訊,這裡僅輸出它的大小
#endif /* CFG_NO_FLASH */
#ifdef 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
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif
     /*
      * reserve memory for LCD display (always full pages)
      *///為LCD分配RAM(記憶體)空間
     /* 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 */
 //malloc函數使用緩衝區的初始化
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); 
//如果定義了命令和NAND命令,則初始化nand
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
    puts ("NAND:  ");
    nand_init();  /* go init the NAND */
#endif
#ifdef CONFIG_HAS_DATAFLASH
    AT91F_DataflashInit();
    dataflash_print_info();
#endif
     /* initialize environment 環境的初始化,代碼在common/env_common.c中 */
    env_relocate ();
#ifdef CONFIG_VFD
     /* must do this after the framebuffer is allocated */
    drv_vfd_init();
#endif /* CONFIG_VFD */
     /* IP Address 為全域變數的成員賦值:IP地址*/
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");//ipaddr在smdk2440.h中的CONFIG_IPADDR中出現,應該是該常量
 /* MAC Address *///高處MAC地址 ,並賦給gd的成員變數
 {
    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;
}
#ifdef CONFIG_HAS_ETH1
  i = getenv_r ("eth1addr", tmp, sizeof (tmp));
  s = (i > 0) ? tmp : NULL;
  for (reg = 0; reg < 6; ++reg) {
   gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
   if (s)
    s = (*e) ? e + 1 : e;
  }
#endif
 }
 //這個函數涉及好多,我沒深入分析,若哪位分析了希望能分享一下:cczy_english@163.com,將不勝感激
 devices_init (); /* get the devices list going. */
#ifdef CONFIG_CMC_PU2
 load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
//初始化跳轉表,對gd中的jt(函數跳轉表)數組進行初始化,其中儲存著一些函數的入口地址

jumptable_init ();
 
 console_init_r (); /* fully init console as a device 我沒具體分析內部實現*/
#if defined(CONFIG_MISC_INIT_R)
 /* miscellaneous platform dependent initialisations, miscellaneous:各色各樣混在一起, 混雜的*/
 misc_init_r ();
#endif
 /* enable exceptions 設定cpsr的I和F位以充許中斷*/
 enable_interrupts ();
 /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#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);
 }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
 if ((s = getenv ("bootfile")) != NULL) {
  copy_filename (BootFile, s, sizeof (BootFile));
 }
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT
 board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
 puts ("Net:   ");
#endif
 eth_initialize(gd->bd);
#endif
 /* main_loop() can return to retry autoboot, if so just run it again. */
 //直接進入main_loop 該函數在common/main.c中
 //!!!!!!!!至此,硬體初始化完成
 for (;;) {
  main_loop ();
 }
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/qianrushiyingyong/20081120/13848_3.html

網上找了一篇文章,認為分析start_armboot很詳細,雖然是2440,但和6410應該改差不多

//------------start_armboot--------------------

//                功能: 完成uboot第二階級的一系列的
//                硬體初始化工作, 然後轉入main函數.
//                備忘: 該函數是C程式的入口函數,從組合語言跳轉到此 .
//---------------------------------------------
void start_armboot (void)
{
    init_fnc_t **init_fnc_ptr; //init_fnc_t 是各初始化函數的數組
    char *s;
#ifndef CFG_NO_FLASH
    ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
    unsigned long addr;
#endif
  /* Pointer is writable since we allocated a register for it

   gd_t: 定義在 /include/asm-arm/Global_data.h中,包含一些全域通用的變數.

   _armboot_start: 代碼的起始地址,它定義在start.S中的前幾行中,定義為 _start

   當系統第一次加電時,指令是從0x0地址開始執行的,所以此時的 _start值應為0x0;

   而當uboot經過代碼重定位後,指令會從 _TEXT_BASE 處開始執行,此時的 _start值就成了 _TEXT_BASE的值.

   CFG_MALLOC_LEN: 在/include/configs/smdk2440.h中有定義,

   該變數表示供malloc函數使用的記憶體池空間,代碼中定義值為:0x10000+128*1024

 |-------|<--- _armboot_start基址
 |  4    | 
 |-------|<--- malloc函數池基址
 |  3    |
 |-------|<--- (gd_t)gd(全域變數表)基址
 |  2    |
 |-------|<--- (bt_t)bd(板卡資訊表)基址
 |  1    |
  -------
   4 就是為malloc函數預留的資料空間
   3 是全資訊表gd的資料區
   2 是板卡資訊表bd的資料區
   網上找了個圖片,更能反應這個空間的分配關係:
該圖在我上一篇文章中有
 */
    //分配區域 3 給 gd ,gd是一個全域靜態變數
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");
    //把gd變數的內容填充為0 ,填充 3 區的資料為0 ,即初始化gd表.注意:這裡並沒有
    //初始化bd表,在gd表中的bd成員只是一個指標,因為對初始化的是個指標地址
    memset ((void*)gd, 0, sizeof (gd_t));
 /*
    bd_t 結構體在/include/asm-arm/U-boot.h中定義, 定義板子的一些資訊,包括:
    傳輸速率,IP地址, 乙太網路地址, 架構編碼,啟動參數 ,BANK的起始地址和大小等
 */
    //分配區域 2 給bd, bd的基址 = gd的基址 - bd的尺寸
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
 
    //把區域 2 填充為 0 ,即初始化 bd 表
    memset (gd->bd, 0, sizeof (bd_t));
 /*monitor_falsh_len定義在 /lib_arm/Board.c
 
    在bin檔案中 BSS 段和 TEXT 段和 DATA 段存放的順序同前向後依次是:
    TEXT(程式碼片段 RO)    DATA(已初始化資料區段 RW)   BSS(未初始化資料區段 ZI)
    所以 _bss_start 的基址等於 TEXT的長度加上DATA的長度.
    即: _bss_start(BSS段基址) = 程式碼片段長度+資料區段長度
 
    BSS(Block Started by Symbol)段是未被初始化的資料區段,是存放程式中
    未被初始化的全域變數的一塊記憶體地區,初始化時應清零;該段只有
    名稱和大小卻沒有值;該段不包含任何資料,只是簡單的維護開始和
    結束的地址,以便記憶體區能在運行時被有效地清零,它在應用程式的
    映像檔案(ARM中也即bin檔案)中並不存在.
    text :程式碼片段,是包含程式碼的段
    dat  :已經初始化的資料區段,儲存已經初始化的全域變數.
 
    在嵌入式系統中,bin檔案(又稱Image檔案)中只包含text和data段,
    而bss段不在其中,它是由系統初始化為零.
  */
    //_armboot_start 在start.S中定義為_start,而_start為代碼的起始地址
    //只包含 RO(TEXT) 和 RW(DATA) 段.重定位前的值為0x0,此時指向flash,
    //重定位後則指向RAM中的某一地址
    //由此可以知道:  _bss_start - _armboot_start 的值即是在第一階段從
    //flash中重定位到RAM中的那部分代碼的長度,也即可TEXT和DATA資料區段,
    //這個值與start.S中的重定位那部分代碼所計算的值是相等的
    //所以,monitor_flash_len表示從flash中搬來的代碼的長度
    monitor_flash_len = _bss_start - _armboot_start;  //_bss_start 在u-boot.lds中定位
 
    //各設定的初始化.當傳回值不為0時表示初始化失敗 ,此時會調用 hang()函數
    //列印一錯誤提示資訊,然後進入死迴圈
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }
    //CFG_NO_FLASH 表示沒有flash,如果沒定義該常量則表示板子上有flash,此時調用flash_init()對其進行初始化.
#ifndef CFG_NO_FLASH
    /* configure available FLASH banks */
    size = flash_init ();
    display_flash_config (size); //列印flash的資訊,這裡僅輸出它的大小
#endif /* CFG_NO_FLASH */
#ifdef 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
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif
     /*
      * reserve memory for LCD display (always full pages)
      *///為LCD分配RAM(記憶體)空間
     /* 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 */
 //malloc函數使用緩衝區的初始化
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); 
//如果定義了命令和NAND命令,則初始化nand
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
    puts ("NAND:  ");
    nand_init();  /* go init the NAND */
#endif
#ifdef CONFIG_HAS_DATAFLASH
    AT91F_DataflashInit();
    dataflash_print_info();
#endif
     /* initialize environment 環境的初始化,代碼在common/env_common.c中 */
    env_relocate ();
#ifdef CONFIG_VFD
     /* must do this after the framebuffer is allocated */
    drv_vfd_init();
#endif /* CONFIG_VFD */
     /* IP Address 為全域變數的成員賦值:IP地址*/
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");//ipaddr在smdk2440.h中的CONFIG_IPADDR中出現,應該是該常量
 /* MAC Address *///高處MAC地址 ,並賦給gd的成員變數
 {
    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;
}
#ifdef CONFIG_HAS_ETH1
  i = getenv_r ("eth1addr", tmp, sizeof (tmp));
  s = (i > 0) ? tmp : NULL;
  for (reg = 0; reg < 6; ++reg) {
   gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
   if (s)
    s = (*e) ? e + 1 : e;
  }
#endif
 }
 //這個函數涉及好多,我沒深入分析,若哪位分析了希望能分享一下:cczy_english@163.com,將不勝感激
 devices_init (); /* get the devices list going. */
#ifdef CONFIG_CMC_PU2
 load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */
//初始化跳轉表,對gd中的jt(函數跳轉表)數組進行初始化,其中儲存著一些函數的入口地址

jumptable_init ();
 
 console_init_r (); /* fully init console as a device 我沒具體分析內部實現*/
#if defined(CONFIG_MISC_INIT_R)
 /* miscellaneous platform dependent initialisations, miscellaneous:各色各樣混在一起, 混雜的*/
 misc_init_r ();
#endif
 /* enable exceptions 設定cpsr的I和F位以充許中斷*/
 enable_interrupts ();
 /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#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);
 }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
 if ((s = getenv ("bootfile")) != NULL) {
  copy_filename (BootFile, s, sizeof (BootFile));
 }
#endif /* CFG_CMD_NET */
#ifdef BOARD_LATE_INIT
 board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
 puts ("Net:   ");
#endif
 eth_initialize(gd->bd);
#endif
 /* main_loop() can return to retry autoboot, if so just run it again. */
 //直接進入main_loop 該函數在common/main.c中
 //!!!!!!!!至此,硬體初始化完成
 for (;;) {
  main_loop ();
 }
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/qianrushiyingyong/20081120/13848_3.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.