u-boot 燒寫菜單

  
本帖最後由 whzdh331 於 2010-11-22 17:54 編輯

Ok6410的硬件相比mini6410強大許多(同樣的價錢),但是ok6410的uboot製作用起來不方便,需要輸入很多命令纔可以燒寫完一個系統。我還是比較懷念在2440上方便、靈活的燒寫方式。
      下面我們就來修改出一個簡單的uboot,實現快速更新系統。
一、首先簡單的說明uboot的啓動過程:
1)、從文件層面上看主要流程是在兩個文件中:cpu/xxxx/start.s,lib_arm/board.c。
Start.s
flash中執行的引導代碼,也就是bootloader中的stage1,負責初始化硬件環境,把u-boot從flash加載到RAM中去,然後跳到lib_arm/board.c中的start_armboot中去執行。
1.1.6版本的start.s流程:
硬件環境初始化:
進入svc模式-->關閉watch dog-->屏蔽所有IRQ掩碼-->設置時鐘頻率FCLK、HCLK、PCLK-->清I/D cache-->禁止MMU和CACHE-->配置memory control-->重定位:如果當前代碼不在連接指定的地址上(對smdk2410是0x3f000000)則需要把u-boot從當前位置拷貝到RAM指定位置中;-->建立堆棧,堆棧是進入C函數前必須初始化的。-->清.bss區。-->跳到start_armboot函數中執行。(lib_arm/board.c)
2)、lib_arm/board.c:
start_armboot是U-Boot執行的第一個C語言函數,完成系統初始化工作,進入主循環,處理用戶輸入的命令。這裏只簡要列出了主要執行的函數流程:
void start_armboot (void)
   {
       //全局數據變量指針gd佔用r8。
DECLARE_GLOBAL_DATA_PTR;
          /* 給全局數據變量gd安排空間*/
          gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
          memset ((void*)gd, 0, sizeof (gd_t));
          /* 給板子數據變量gd->bd安排空間*/
          gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
          memset (gd->bd, 0, sizeof (bd_t));
          monitor_flash_len = _bss_start - _armboot_start;//取u-boot的長度。
          /* 順序執行init_sequence數組中的初始化函數 */
          for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
if ((*init_fnc_ptr)() != 0) { hang ();}
/*配置可用的Flash */
  size = flash_init ();
        ……
          /* 初始化堆空間 */
          mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
          /* 重新定位環境變量, */
          env_relocate ();
          /* 從環境變量中獲取IP地址 */
          gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
          /* 以太網接口MAC 地址 */
          ……
          devices_init ();      /* 設備初始化 */
          jumptable_init ();  //跳轉表初始化
          console_init_r ();    /* 完整地初始化控制檯設備 */
          enable_interrupts (); /* 使能中斷處理 */
          /* 通過環境變量初始化 */
          if ((s = getenv ("loadaddr")) != NULL)
                  load_addr = simple_strtoul (s, NULL, 16);
         /* main_loop()循環不斷執行 */
          for (;;)
          main_loop (); /* 主循環函數處理執行用戶命令 -- common/main.c */
   }
其中,初始化函數序列init_sequence[]
  init_sequence[]數組保存着基本的初始化函數指針。這些函數名稱和實現的程序文件在下列註釋中。
init_fnc_t *init_sequence[] = {
   cpu_init,     /* 基本的處理器相關配置 -- cpu/arm920t/cpu.c */
   board_init,   /* 基本的板級相關配置 -- board/smdk2410/smdk2410.c */
   interrupt_init,  /* 初始化例外處理 -- cpu/arm920t/s3c24x0/interrupt.c */
   env_init,             /* 初始化環境變量 -- common/env_flash.c */
   init_baudrate,        /* 初始化波特率設置 -- lib_arm/board.c */
   serial_init,          /* 串口通訊設置 -- cpu/arm920t/s3c24x0/serial.c */
   console_init_f,       /* 控制檯初始化階段1 -- common/console.c */
   display_banner,       /* 打印u-boot信息 -- lib_arm/board.c */
   dram_init,            /* 配置可用的RAM -- board/smdk2410/smdk2410.c */
    display_dram_config,  /* 顯示RAM的配置大小 -- lib_arm/board.c */
    NULL,
};
整個u-boot的執行就進入等待用戶輸入命令,解析並執行命令的死循環中。
二、修改main_loop()函數
我們期望此時能進入一個菜單,通過輸入一些簡單的指令來更新uboot、kernel、fs等。
1)、分析/common/main.c的main_loop函數:系統進入到main_loop
後首先判斷在3秒內是否有輸入。如果有輸入就進入命令行模式,我們可以在此命令行下通過輸入指令來更新系統。如果沒有輸入則執行bootm 指令。
首先,我自己試過幾次,如果用run_command來保持環境變量“setenv bootcmd nand read 0xc0008000 0x100000 0x300000\;bootm 0xc0008000 ”,系統會直接重啓。比較鬱悶,想了變通的方法就是在/include/configs/smdk6410.h文件裏直接修改CONFIG_BOOTCOMMAND 爲nand read c0008000 100000 300000;bootm c0008000。據我分析系統啓動後會從這個宏裏讀取bootcmd參數。(如果有不對的,請高手指出) 那麼我們後面就不用再設定這個參數了。
  1. void main_loop (void)
  2. {
  3.         …….
  4. s = getenv ("bootcmd");         //獲取bootcmd指令
  5. debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
  6. if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
  7. // abortboot()主要是判斷bootdelay的時間內,是否有按鍵輸入。
  8. ……
  9. run_command (s, 0); //如果沒有輸入就執行bootcmd指令
  10.       }
  11. //進入一個命令行模式,循環接受用戶指令。
  12. //我們就在這裏加入一個我們自己的函數MainMenu()用來執行菜單。
  13. MainMenu();
  14. /*
  15. * Main Loop for Monitor Command Processing
  16. */
  17. ……
  18. }
複製代碼
2)、在該文件的開頭申明一個函數MainMenu():void MainMenu()
3)、定義我們的MainMenu()
  1. void main_menu_usage(void)
  2. {
  3.     printf("\r\n##### ok6410 Bootloader #####\r\n");
  4.     printf("[u] Download u-boot\r\n");
  5.     printf("[k] Download Linux kernel\r\n");
  6.     //printf("[y] Download YAFFS image\r\n");
  7.     printf("[c] Download cramfs image\r\n");
  8.     //printf("[d] Download to SDRAM & Run\r\n");
  9.     printf("[b] Boot the system\r\n");
  10.     printf("[f] Format the Nand Flash\r\n");
  11.     printf("[s] Set the boot parameters\r\n");
  12.     printf("[r] Reboot u-boot\r\n");
  13.     printf("[q] Quit from menu\r\n");
  14.     printf("Enter your selection: ");
  15. }
  16. void MainMenu()
  17. {
  18.         char c;
  19.     char cmd_buf[256];
  20.     char name_buf[20];
  21.     char val_buf[256];
  22.          while (1)
  23.     {
  24.         main_menu_usage();        //輸出菜單的函數
  25.         c = getc();                                //獲取輸入的字符
  26.         printf("%c\n", c);
  27.         switch (c)
  28.         {
  29. case 'u':                                         //燒寫uboot
  30.     printf("nand erase nand and write uboot \n");
  31.     strcpy(cmd_buf, "dnw c0008000 ; nand erase 0 100000 ; nand write 0xc0008000 0 100000");
  32.     printf("%s \n",cmd_buf);
  33.     run_command(cmd_buf, 0);
  34.     break;
  35. case 'k':                                        //燒寫kernel
  36. //先設定環境變量
  37.     strcpy(cmd_buf,"setenv bootargs \"root=/dev/mtdblock2 console=ttySAC0,115200\"“);
  38.     run_command(cmd_buf,0);
  39.     run_command("saveenv",0);
  40.     strcpy(cmd_buf, "dnw c0008000; nand erase 100000 300000 ; nand write.e 0xc0008000 100000 300000");
  41.     printf("%s \n",cmd_buf);
  42.     run_command(cmd_buf, 0);
  43.     break;
  44. case 'c':                //燒寫cramfs文件系統
  45.     strcpy(cmd_buf, "dnw 0xc0008000; nand erase 400000 5000000 ; nand write.e 0xc0008000 400000 5000000");
  46.         printf("%s \n",cmd_buf);
  47.     run_command(cmd_buf, 0);
  48.         strcpy(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 rootfstype=cramfs console=ttySAC0,115200\"");
  49.         printf("%s \n",cmd_buf);
  50.     run_command(cmd_buf, 0);
  51.         strcpy(cmd_buf, "saveenv");
  52.         printf("%s \n",cmd_buf);
  53.     run_command(cmd_buf, 0);
  54.     break;
  55. case 'b':                //bootm 重啓
  56.     printf("Booting Linux ...\n");
  57.     strcpy(cmd_buf, "nand read 0xc0008000 0x100000 0x300000;bootm 0xc0008000");
  58.         printf("%s\n",cmd_buf);
  59.     run_command(cmd_buf, 0);
  60.     break;
  61. case 'f':                //format flash
  62.     strcpy(cmd_buf, "nand scrub");
  63.         printf("%s\n",cmd_buf);
  64.     run_command(cmd_buf, 0);
  65.     break;
  66. case 's':                //更改環境參數
  67.     param_menu_shell();  這部分函數需要自己寫 :)
  68.     break;
  69. case 'q':                //退出菜單
  70.     return;   
  71.     break;
  72.         }              
  73.     }
  74. }
複製代碼
4)、加入參數修改的菜單函數
  1. void param_menu_usage()
  2. {
  3.     printf("\r\n##### Parameter Menu #####\r\n");
  4.     printf("[v] View the parameters\r\n");
  5.     printf("[s] Set parameter \r\n");
  6.     printf("[d] Delete parameter \r\n");
  7.     printf("[w] Write the parameters to flash memeory \r\n");
  8.     printf("[q] Quit \r\n");
  9.     printf("[l] load env 1 \r\n");        //設置參數1,跟新系統時用
  10.     printf("[m] load env 2 \r\n");        //設置參數2,更新完系統後恢復的參數
  11.     printf("Enter your selection: ");
  12. }

  13. void param_menu_shell(void)
  14. {
  15.     char c;
  16.     char cmd_buf[256];
  17.     char name_buf[20];
  18.     char val_buf[256];
  19.     while (1)
  20.     {
  21.         param_menu_usage();
  22.         c = getc();
  23.         printf("%c\n", c);
  24.         switch (c)
  25.         {
  26.             case 'v':
  27.             strcpy(cmd_buf, "printenv ");
  28.             run_command(cmd_buf, 0);
  29.             break;
  30.             
  31.             case 's':
  32.             sprintf(cmd_buf, "setenv ");
  33.         printf("Name: ");
  34.             readline(NULL);
  35.             strcat(cmd_buf, console_buffer);
  36.             run_command(cmd_buf, 0);
  37.              break;
  38.             
  39.             case 'd':
  40.                 sprintf(cmd_buf, "setenv ");
  41.                 printf("Name: ");
  42.                 readline(NULL);
  43.                 strcat(cmd_buf, console_buffer);
  44.                 run_command(cmd_buf, 0);
  45.                 break;

  46.             case 'w':
  47.             sprintf(cmd_buf, "saveenv");
  48.             run_command(cmd_buf, 0);
  49.             break;
  50.       
  51.         case 'l':
  52.         sprintf(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 console=ttySAC0,115200\"");
  53.         printf("%s\n",cmd_buf);
  54.         run_command(cmd_buf, 0);
  55. //保存參數
  56.         run_command("saveenv", 0);
  57.         break;
  58.             case 'm':
  59.         sprintf(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 rootfstype=cramfs console=ttySAC0,115200\"");
  60.         printf("%s\n",cmd_buf);
  61.         run_command(cmd_buf, 0);
  62.         run_command("saveenv", 0);
  63.         break;
  64.             case 'q':
  65.                 return;
  66.                 break;
  67.         }
  68.     }
  69. }
複製代碼
三、重新編譯uboot,燒寫進入nand
第一次燒寫需要按照手冊上的要求來做。燒寫完後,從nand啓動,在讀秒時按空格就進入我們上面設定的菜單了。可以很方便的進行系統的更新
收藏 分享

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章