<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x
    查看: 4059|回復: 3
    打印 上一主題 下一主題

    修改我們自己的uboot,實現快捷更新Linux系統(基于S3C6410,源文件+注釋)

    [復制鏈接]
    跳轉到指定樓層
    樓主
    發表于 2011-8-20 13:37:46 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
    關鍵詞: uboot
    很客觀的說,ok6410的硬件相比mini6410強大許多(同樣的價錢),但是ok6410的uboot制作用起來不太方便,需要輸入很多命令才可以燒寫完一個系統。我還是比較懷念在2440上方便、靈活的燒寫方式。
          
    下面我們就來修改出一個簡單的uboot,實現快速更新系統。

    點擊此處下載 u-boot.rar (79.19 KB)
    點擊此處下載   main.rar (9.87 KB)

    點擊此處進入飛凌官網下載:http://www.witech.com.cn/

    一、首先簡單的說明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參數。(如果有不對的,請高手指出) 那么我們后面就不用再設定這個參數了。  

    void main_loop (void)
    {
            …….
    s = getenv ("bootcmd");         //獲取bootcmd指令
    debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
    if (bootdelay >= 0 && s && !abortboot (bootdelay)) {  
    // abortboot()主要是判斷bootdelay的時間內,是否有按鍵輸入。
    ……
    run_command (s, 0); //如果沒有輸入就執行bootcmd指令
          }
    //進入一個命令行模式,循環接受用戶指令。
    //我們就在這里加入一個我們自己的函數MainMenu()用來執行菜單。
    MainMenu();
    /*
    * Main Loop for Monitor Command Processing
    */
    ……
    }

    2)、在該文件的開頭申明一個函數MainMenu():void MainMenu()

    3)、定義我們的MainMenu()  

    void main_menu_usage(void)
    {
        printf("\r\n##### ok6410 Bootloader #####\r\n");
        printf("[ u] Download u-boot\r\n");
        printf("[k] Download Linux kernel\r\n");
        //printf("[y] Download YAFFS image\r\n");
        printf("[c] Download cramfs image\r\n");
        //printf("[d] Download to SDRAM & Run\r\n");
        printf("[ b] Boot the system\r\n");
        printf("[f] Format the Nand Flash\r\n");
        printf(" Set the boot parameters\r\n");
        printf("[r] Reboot u-boot\r\n");
        printf("[q] Quit from menu\r\n");
        printf("Enter your selection: ");
    }
    void MainMenu()
    {
            char c;
        char cmd_buf[256];
        char name_buf[20];
        char val_buf[256];
             while (1)
        {
            main_menu_usage();        //輸出菜單的函數
            c = getc();                                //獲取輸入的字符
            printf("%c\n", c);
            switch (c)
            {
    case 'u':                                         //燒寫uboot
        printf("nand erase nand and write uboot \n");
        strcpy(cmd_buf, "dnw c0008000 ; nand erase 0 100000 ; nand write 0xc0008000 0 100000");
        printf("%s \n",cmd_buf);
        run_command(cmd_buf, 0);
        break;
    case 'k':                                        //燒寫kernel
    //先設定環境變量
        strcpy(cmd_buf,"setenv bootargs \"root=/dev/mtdblock2 console=ttySAC0,115200\"“);
        run_command(cmd_buf,0);
        run_command("saveenv",0);
        strcpy(cmd_buf, "dnw c0008000; nand erase 100000 300000 ; nand write.e 0xc0008000 100000 300000");
        printf("%s \n",cmd_buf);
        run_command(cmd_buf, 0);
        break;
    case 'c':                //燒寫cramfs文件系統
        strcpy(cmd_buf, "dnw 0xc0008000; nand erase 400000 5000000 ; nand write.e 0xc0008000 400000 5000000");
            printf("%s \n",cmd_buf);
        run_command(cmd_buf, 0);
            strcpy(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 rootfstype=cramfs console=ttySAC0,115200\"");
            printf("%s \n",cmd_buf);
        run_command(cmd_buf, 0);
            strcpy(cmd_buf, "saveenv");
            printf("%s \n",cmd_buf);
        run_command(cmd_buf, 0);
        break;
    case 'b':                //bootm 重啟
        printf("Booting Linux ...\n");
        strcpy(cmd_buf, "nand read 0xc0008000 0x100000 0x300000;bootm 0xc0008000");
            printf("%s\n",cmd_buf);
        run_command(cmd_buf, 0);
        break;
    case 'f':                //format flash
        strcpy(cmd_buf, "nand scrub");
            printf("%s\n",cmd_buf);
        run_command(cmd_buf, 0);
        break;
    case 's':                //更改環境參數
        param_menu_shell();  這部分函數需要自己寫 :)
        break;
    case 'q':                //退出菜單
        return;     
        break;
            }               
        }
    }

    4)、加入參數修改的菜單函數  

    void param_menu_usage()
    {
        printf("\r\n##### Parameter Menu #####\r\n");
        printf("[v] View the parameters\r\n");
        printf(" Set parameter \r\n");
        printf("[d] Delete parameter \r\n");
        printf("[w] Write the parameters to flash memeory \r\n");
        printf("[q] Quit \r\n");
        printf("[l] load env 1 \r\n");        //設置參數1,跟新系統時用
        printf("[m] load env 2 \r\n");        //設置參數2,更新完系統后恢復的參數
        printf("Enter your selection: ");
    }
    void param_menu_shell(void)
    {
        char c;
        char cmd_buf[256];
        char name_buf[20];
        char val_buf[256];
        while (1)
        {
            param_menu_usage();
            c = getc();
            printf("%c\n", c);
            switch (c)
            {
                case 'v':
                strcpy(cmd_buf, "printenv ");
                run_command(cmd_buf, 0);
                break;
                
                case 's':
                sprintf(cmd_buf, "setenv ");
            printf("Name: ");
                readline(NULL);
                strcat(cmd_buf, console_buffer);
                run_command(cmd_buf, 0);
                 break;
                
                case 'd':
                    sprintf(cmd_buf, "setenv ");
                    printf("Name: ");
                    readline(NULL);
                    strcat(cmd_buf, console_buffer);
                    run_command(cmd_buf, 0);
                    break;
                case 'w':
                sprintf(cmd_buf, "saveenv");
                run_command(cmd_buf, 0);
                break;
            
            case 'l':
            sprintf(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 console=ttySAC0,115200\"");
            printf("%s\n",cmd_buf);
            run_command(cmd_buf, 0);
    //保存參數
            run_command("saveenv", 0);
            break;
                case 'm':
            sprintf(cmd_buf, "setenv bootargs \"root=/dev/mtdblock2 rootfstype=cramfs console=ttySAC0,115200\"");
            printf("%s\n",cmd_buf);
            run_command(cmd_buf, 0);
            run_command("saveenv", 0);
            break;
                case 'q':
                    return;
                    break;
            }
        }
    }

    三、重新編譯uboot,燒寫進入nand

    第一次燒寫需要按照手冊上的要求來做。燒寫完后,從nand啟動,在讀秒時按空格就進入我們上面設定的菜單了?梢院芊奖愕倪M行系統的更新。
    沙發
    發表于 2012-2-25 11:28:28 | 只看該作者
    不錯
    板凳
    發表于 2012-5-23 13:02:21 | 只看該作者
    試一試
    地板
    發表于 2012-8-9 21:40:32 | 只看該作者
    學習了
    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規則

    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷