U-Boot简单流程
来源:互联网 发布:three.js pointlight 编辑:程序博客网 时间:2024/04/30 01:03
下面我们就来修改出一个简单的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 (;;)
[color=Red] main_loop (); [/color]/* 主循环函数处理执行用户命令 -- 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参数。(如果有不对的,请高手指出) 那么我们后面就不用再设定这个参数了。[code]void main_loop (void)
{
…….
s = getenv ("bootcmd"); //获取bootcmd指令
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
// abortboot()主要是判断bootdelay的时间内,是否有按键输入。
……
run_command (s, 0); //如果没有输入就执行bootcmd指令
}
//进入一个命令行模式,循环接受用户指令。
//我们就在这里加入一个我们自己的函数MainMenu()用来执行菜单。
MainMenu();
/*
* Main Loop for Monitor Command Processing
*/
……
}[/code]2)、在该文件的开头申明一个函数MainMenu():void MainMenu()
3)、定义我们的MainMenu()[code]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("[s] 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;
}
}
}[/code]4)、加入参数修改的菜单函数[code]void param_menu_usage()
{
printf("\r\n##### Parameter Menu #####\r\n");
printf("[v] View the parameters\r\n");
printf("[s] 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;
}
}
}[/code]三、重新编译uboot,烧写进入nand
第一次烧写需要按照手册上的要求来做。烧写完后,从nand启动,在读秒时按空格就进入我们上面设定的菜单了。可以很方便的进行系统的更新:D[/b][/b]
一、首先简单的说明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 (;;)
[color=Red] main_loop (); [/color]/* 主循环函数处理执行用户命令 -- 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参数。(如果有不对的,请高手指出) 那么我们后面就不用再设定这个参数了。[code]void main_loop (void)
{
…….
s = getenv ("bootcmd"); //获取bootcmd指令
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
// abortboot()主要是判断bootdelay的时间内,是否有按键输入。
……
run_command (s, 0); //如果没有输入就执行bootcmd指令
}
//进入一个命令行模式,循环接受用户指令。
//我们就在这里加入一个我们自己的函数MainMenu()用来执行菜单。
MainMenu();
/*
* Main Loop for Monitor Command Processing
*/
……
}[/code]2)、在该文件的开头申明一个函数MainMenu():void MainMenu()
3)、定义我们的MainMenu()[code]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("[s] 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;
}
}
}[/code]4)、加入参数修改的菜单函数[code]void param_menu_usage()
{
printf("\r\n##### Parameter Menu #####\r\n");
printf("[v] View the parameters\r\n");
printf("[s] 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;
}
}
}[/code]三、重新编译uboot,烧写进入nand
第一次烧写需要按照手册上的要求来做。烧写完后,从nand启动,在读秒时按空格就进入我们上面设定的菜单了。可以很方便的进行系统的更新:D[/b][/b]
0
上一篇:安装Ubuntu10.10的vm tools
下一篇:基于platform机制的驱动模型
相关热门文章
- 我怀着很明确的目的来到ChinaU...
- 一些简单的shell脚本实例...
- Hadoop初探之Hadoop生态圈...
- 教你多少招不花钱做网店推广的...
- GE照明安防及可移动房屋设施...
- linux守护进程的几个关键地方...
- stagefright与opencore对比
- 嵌入式Linux之我行——u-boot-...
- 嵌入式Linux之我行——内核、...
- CodeNavigator -- 程序员必备...
- ChinaUnix & ITPUB社区12周年...
- ssh连接出现以下提示,求解...
- 如何扩展MYSQL
- 准备做一个大型门户,用户什么...
- gbk or utf8
给主人留下些什么吧!~~
评论热议
- U-Boot简单流程
- u-boot启动流程
- u-boot启动流程
- u-boot系统启动流程
- u-boot启动流程
- u-boot启动流程
- u-boot系统启动流程
- u-boot系统启动流程
- u-boot系统启动流程
- u-boot启动流程
- U-boot引导流程
- u-boot移植流程
- Atmel SAMA5D3 U-Boot 启动流程简单分析
- u-boot总的启动流程
- u-boot启动流程一
- U-BOOT的启动流程
- u-boot启动流程分析
- U-boot的编译流程
- 工作队列work queue
- ALSA之PCM分析
- ALSA之codec分析
- 通过request.getHeader("referer")防止用户手动修改URL访问非权限页面
- 安装Ubuntu10.10的vm tools
- U-Boot简单流程
- Android 当修改一些代码时,使用什么编译命令可以最有效率
- 基于platform机制的驱动模型
- 推荐ALSA一个很好的网站
- android获取URLConnection和HttpClient网络请求响应码
- 驱动注册的probe函数
- input子系统学习笔记一 软件设计流程及相关API
- input子系统学习 按键驱动实例分析上
- input子系统学习笔记 按键驱动实例分析下
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
脚上有湿气怎么办
去除体内湿气的中成药
怎么去身上湿气
身上有湿气的表现
什么能去湿气
如何调理湿气
湿气重什么不能吃
湿气重吃什么药好得快
体内湿气是怎么回事
湿气引起的皮肤瘙痒
湿气重是什么症状
去湿气吃什么水果
手有湿气怎么办
艾灸能去湿气吗
怎么调理湿气
怎么样除湿气
身体里的湿气
寒湿重的表现
shiqi
湿热重吃什么中成药
体内寒湿重怎样祛除
如何去除体内湿热
去湿毒的食物
湿热重的症状
湿汽
如何去除体内湿毒
儿童湿热重有什么表现
体内寒气重
湿重的症状
女人湿热重的症状
体内湿热
体内湿毒重的表现症状
湿重
体内湿热重怎样祛除
痧气
痧气重怎么祛除
体内湿寒重怎样祛除
湿重的人怎样去湿
身体快速祛湿的方法
吃什么可以除湿气
怎样去除体内湿气