電子工程網(wǎng)
標題:
修改我們自己的uboot,實(shí)現快捷更新Linux系統(基于S3C6410,源文件+注釋?zhuān)?
[打印本頁(yè)]
作者:
yanhong
時(shí)間:
2011-8-20 13:37
標題:
修改我們自己的uboot,實(shí)現快捷更新Linux系統(基于S3C6410,源文件+注釋?zhuān)?br />很客觀(guān)的說(shuō),ok6410的硬件相比mini6410強大許多(同樣的價(jià)錢(qián)),但是ok6410的uboot制作用起來(lái)不太方便,需要輸入很多命令才可以燒寫(xiě)完一個(gè)系統。我還是比較懷念在2440上方便、靈活的燒寫(xiě)方式。
下面我們就來(lái)修改出一個(gè)簡(jiǎn)單的uboot,實(shí)現快速更新系統。
點(diǎn)擊此處下載
u-boot.rar
(79.19 KB)
2011-8-20 13:37 上傳
點(diǎn)擊文件名下載附件
下載積分: 積分 -1
點(diǎn)擊此處下載
main.rar
(9.87 KB)
2011-8-20 13:37 上傳
點(diǎn)擊文件名下載附件
下載積分: 積分 -1
點(diǎn)擊此處進(jìn)入飛凌官網(wǎng)下載:
http://www.witech.com.cn/
一、首先簡(jiǎn)單的說(shuō)明uboot的啟動(dòng)過(guò)程:
1)、從文件層面上看主要流程是在兩個(gè)文件中:cpu/xxxx/start.s,lib_arm/board.c。
Start.s
在flash中執行的引導代碼,也就是bootloader中的stage1,負責初始化硬件環(huán)境,把u-boot從flash加載到RAM中去,然后跳到lib_arm/board.c中的start_armboot中去執行。
1.1.6版本的start.s流程:
硬件環(huán)境初始化:
進(jìn)入svc模式-->關(guān)閉watch dog-->屏蔽所有IRQ掩碼-->設置時(shí)鐘頻率FCLK、HCLK、PCLK-->清I/D cache-->禁止MMU和CACHE-->配置memory control-->重定位:如果當前代碼不在連接指定的地址上(對smdk2410是0x3f000000)則需要把u-boot從當前位置拷貝到RAM指定位置中;-->建立堆棧,堆棧是進(jìn)入C函數前必須初始化的。-->清.bss區。-->跳到start_armboot函數中執行。(lib_arm/board.c)
2)、lib_arm/board.c:
start_armboot是U-Boot執行的第一個(gè)C語(yǔ)言函數,完成系統初始化工作,進(jìn)入主循環(huán),處理用戶(hù)輸入的命令。這里只簡(jiǎn)要列出了主要執行的函數流程:
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的長(cháng)度。
/* 順序執行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);
/* 重新定位環(huán)境變量, */
env_relocate ();
/* 從環(huán)境變量中獲取IP地址 */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* 以太網(wǎng)接口MAC 地址 */
……
devices_init (); /* 設備初始化 */
jumptable_init (); //跳轉表初始化
console_init_r (); /* 完整地初始化控制臺設備 */
enable_interrupts (); /* 使能中斷處理 */
/* 通過(guò)環(huán)境變量初始化 */
if ((s = getenv ("loadaddr")) != NULL)
load_addr = simple_strtoul (s, NULL, 16);
/* main_loop()循環(huán)不斷執行 */
for (;;)
main_loop (); /* 主循環(huán)函數處理執行用戶(hù)命令 -- common/main.c */
}
其中,初始化函數序列init_sequence[]
init_sequence[]數組保存著(zhù)基本的初始化函數指針。這些函數名稱(chēng)和實(shí)現的程序文件在下列注釋中。
init_fnc_t *init_sequence[] = {
cpu_init, /* 基本的處理器相關(guān)配置 -- cpu/arm920t/cpu.c */
board_init, /* 基本的板級相關(guān)配置 -- board/smdk2410/smdk2410.c */
interrupt_init, /* 初始化例外處理 -- cpu/arm920t/s3c24x0/interrupt.c */
env_init, /* 初始化環(huán)境變量 -- 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,
};
整個(gè)u-boot的執行就進(jìn)入等待用戶(hù)輸入命令,解析并執行命令的死循環(huán)中。
二、修改main_loop()函數
我們期望此時(shí)能進(jìn)入一個(gè)菜單,通過(guò)輸入一些簡(jiǎn)單的指令來(lái)更新uboot、kernel、fs等。
1)、分析/common/main.c的main_loop函數:系統進(jìn)入到main_loop
后首先判斷在3秒內是否有輸入。如果有輸入就進(jìn)入命令行模式,我們可以在此命令行下通過(guò)輸入指令來(lái)更新系統。如果沒(méi)有輸入則執行bootm 指令。
首先,我自己試過(guò)幾次,如果用run_command來(lái)保持環(huán)境變量“setenv bootcmd nand read 0xc0008000 0x100000 0x300000\;bootm 0xc0008000 ”,系統會(huì )直接重啟。比較郁悶,想了變通的方法就是在/include/configs/smdk6410.h文件里直接修改CONFIG_BOOTCOMMAND 為nand read c0008000 100000 300000;bootm c0008000。據我分析系統啟動(dòng)后會(huì )從這個(gè)宏里讀取bootcmd參數。(如果有不對的,請高手指出) 那么我們后面就不用再設定這個(gè)參數了。
void main_loop (void)
{
…….
s = getenv ("bootcmd"); //獲取bootcmd指令
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "
");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
// abortboot()主要是判斷bootdelay的時(shí)間內,是否有按鍵輸入。
……
run_command (s, 0); //如果沒(méi)有輸入就執行bootcmd指令
}
//進(jìn)入一個(gè)命令行模式,循環(huán)接受用戶(hù)指令。
//我們就在這里加入一個(gè)我們自己的函數MainMenu()用來(lái)執行菜單。
MainMenu();
/*
* Main Loop for Monitor Command Processing
*/
……
}
2)、在該文件的開(kāi)頭申明一個(gè)函數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': //燒寫(xiě)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': //燒寫(xiě)kernel
//先設定環(huán)境變量
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': //燒寫(xiě)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': //更改環(huán)境參數
param_menu_shell(); 這部分函數需要自己寫(xiě) :)
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,跟新系統時(shí)用
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,燒寫(xiě)進(jìn)入nand
第一次燒寫(xiě)需要按照手冊上的要求來(lái)做。燒寫(xiě)完后,從nand啟動(dòng),在讀秒時(shí)按空格就進(jìn)入我們上面設定的菜單了?梢院芊奖愕倪M(jìn)行系統的更新。
作者:
hairui01234567
時(shí)間:
2012-2-25 11:28
不錯
作者:
yl_bean
時(shí)間:
2012-5-23 13:02
試一試
作者:
james_138139
時(shí)間:
2012-8-9 21:40
學(xué)習了
歡迎光臨 電子工程網(wǎng) (http://selenalain.com/)
Powered by Discuz! X3.4
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页