U-Boot 是一个主要用于嵌入式系统的引导加载程序,可以支持多种不同的计算机系统结构,包括PPC、ARM、AVR32、MIPS、x86、68k、Nios与MicroBlaze。这也是一套在GNU通用公共许可证之下发布的自由软件。
U-Boot本质是一个裸机程序,是一种普遍用于嵌入式系统中的开源的Bootloader,作用是用来引导操作系统,以及给开发人员提供测试调试工具。主要负责基本硬件初始化,导启动内核启动。
U-Boot命令众多,通过uboot命令可完成系统环境变量设置。U-Boot本质就是一份裸机程序,这样可以在U-Boot命令下调试一些硬件设备问题。U-Boot命令行也是可以实现自动补全功能。
uboot命令存放在uboot目录下的common目录下。
do_help命令功能实现如下:
extern cmd_tbl_t __u_boot_cmd_bdinfo;
extern cmd_tbl_t __u_boot_cmd_showvar;
int do_help(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
// return _do_help(&__u_boot_cmd_start,
// &__u_boot_cmd_end - &__u_boot_cmd_start,
// cmdtp, flag, argc, argv);
return _do_help(&__u_boot_cmd_bdinfo,
&__u_boot_cmd_showvar - &__u_boot_cmd_bdinfo + 1,
cmdtp, flag, argc, argv);
}
U_BOOT_CMD(
help, CONFIG_SYS_MAXARGS, 1, do_help,
"print command description/usage",
"\n"
" - print brief description of all commands\n"
"help command ...\n"
" - print detailed usage of 'command'"
);
/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
"?", CONFIG_SYS_MAXARGS, 1, do_help,
"alias for 'help'",
#ifdef CONFIG_SYS_LONGHELP
""
#endif /* CONFIG_SYS_LONGHELP */
};
U_BOOT_CMD为命令参数传递:
help 命令标志符;
CONFIG_SYS_MAXARGS命令传递的最大参数个数;
1命令重复执行次数;
do_help命令实现函数;
“alias for ‘help’”命令用法说明;
最后一个参数为命令用法详细说明;
int do_help(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])函数参数说明:
cmd_tbl_t * cmdtp结构体指针。
struct cmd_tbl_s {
char *name; /* 命令名字*/
int maxargs; /*命令传递的最大参数个数*/
int repeatable; /*命令重复执行次数*/
/*命令功能实现函数*/
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
char *usage; /*命令基本用法说明*/
#ifdef CONFIG_SYS_LONGHELP
char *help; /*命令详细用法说明*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
argc 命令传入的参数个数,和main函数argc相同;
argv 存放命令参数内容,和main函数argv相同;
配置寄存器:GPD0CON_ADDR = 0x1140_0000 + 0x00A0
数据寄存器:GPD0DAT_ADDR = 0x1140_0000 + 0x00A4
#include
#include
/*蜂鸣器*/
#define GPD0_CON *((volatile unsigned int *)0x114000A0)//控制寄存器
#define GPD0_DAT *((volatile unsigned int *)0x114000A4)//数据寄存器
int do_beep(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
/*蜂鸣器*/
GPD0_CON&=0xfffffff0;//清除当前GPD0_0的配置
GPD0_CON|=0x00000001;//设置为输出模式
//beep on 或者 beep off
if(argc!=2)
{
printf("格式:beep on/off\n");
return 0;
}
if(strcmp(argv[1],"on")==0)//开蜂鸣器
{
GPD0_DAT|=1<<0;//开蜂鸣器
}
else if(strcmp(argv[1],"off")==0)//关蜂鸣器
{
GPD0_DAT&=~(1<<0);//关蜂鸣器
}
return 0;
}
U_BOOT_CMD(
beep, CONFIG_SYS_MAXARGS, 1, do_beep,
"beep " ,
"\n"
"beep用法\n"
"开蜂鸣器:beep on\n"
"关蜂鸣器:beep_off"
);
1. 将cmd_beep.c拷贝到u_boot目录下的common目录下
[wbyq@wbyq common]$ cp /mnt/hgfs/ubuntu/cmd_beep.c ./
2. 修改common目录下的Makefile文件。
[wbyq@wbyq common]$ vim Makefile
[wbyq@wbyq uboot_tiny4412-sdk1506]$ make
4.烧写uboot
[wbyq@wbyq uboot_tiny4412-sdk1506]$ cd sd_fuse/
[wbyq@wbyq tiny4412]$ sudo ./sd_fusing.sh /dev/sdb
TINY4412 # beep
格式:beep on/off
TINY4412 # ? beep
flag=0
beep - beep <on/off>
Usage:
beep
beep用法
开蜂鸣器:beep on
关蜂鸣器:beep_off
TINY4412 # beep on
TINY4412 # beep off
在Linux操作系统启动前,uboot需要完成系统环境变量配置。在uboot目录下有tiny4412.h中保存的系统的默认环境变量参数。
1.当我们修改了系统环境变量,执行了saveenv命令后,则环境变量将写入到磁盘中,接下来我们将分析一下uboot源码中环境变量写入磁盘的扇区位置。
在uboot命令中,并没有直接脚cmd_save.c的函数,因此,我们可以根据saveenv命令执行后的提示信息来分析。在uboot命令行下执行saveenv命令时,会看到有输出提示信息,这样我们可以直接在uboot工程中搜索一下输出信息的位置。
TINY4412 # save
Saving Environment to SMDK bootable device...
done
当我们跳到定义处时会看到有多重位置,要想准确跳转到正确位置,我们可以再查找参考saveenv命令的后半段提示信息赋值位置。
3.经过查找参考我们发现,后半段提示信息的定义位置是在env_auto.c中,而我们saveenv函数右键跳到定义处时在env_auto.c中也有定义,说明我们要跳转的文件即为env_atuo.c文件。
在 saveenv函数中,并没有看到有关于mmc写扇区的函数,说明我们还需要进一步跳转到对应的子函数中去分析。
4.我们可以再次根据saveenv命令的打印提示,在最后还会打印“done”这个信息,这样我们就可以更新这个信息,对当前函数中的三个子函数进行分析,看下哪一个子函数中有这个字符串的打印。经过查看代码可知最终调用的函数即为saveenv_movinand()函数。
5.再次跳到movi_write_env()函数中查看一下写入到mmc中的地址。
6.在这个函数中即为实现环境变量写入作用,再次跳到movi_write()函数中查看一下这个函数参数作用。
可以看到,movi_write()函数参数作用分别为:mmc设备编号、写入mmc的起始扇区、写入的扇区个数、写入的环境变量内容。
我们可以在这个函数中加入printf函数打印一下写入的扇区地址和扇区数量。然后再重新编译uboot,烧写到SD卡中再次启动查看效果。
TINY4412 # save
Saving Environment to SMDK bootable device...
start=1025,blkcnt=32
done
TINY4412 #
重新执行save命令,可以看到环境变量写入的起始位置为第1025个扇区,连续写入了32个扇区。至此,环境变量的写入扇区位置分析完毕。
要清除已经写入的环境变量,我们只需要将mmc中第1025个扇区的数据破坏掉即可。
我们可以使用mmc命令,写入一段无效数据到第1025个扇区中即可。
TINY4412 # mmc write 0 40008000 401 32
MMC write: dev # 0, block # 1025, count 50 ... 50 blocks written: OK
将40008000地址中的内容写入到设备0的第1025个扇区,连续写32个扇区。
#include
#include
#include
int do_clenenv(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
mmc_init(find_mmc_device(0));/*mmc初始化*/
movi_write_env(virt_to_phys((ulong)0x40008000));/*写入环境变量*/
return 0;
}
U_BOOT_CMD(
cleanenv, CONFIG_SYS_MAXARGS, 1, do_clenenv,
"clean 清空系统环境变量",
"\n"
"clean用法:clean\n"
"清空环境变量"
);