在uboot起来后,我们可以在它的shell界面输入各种命令,而U-Boot的每一个命令都是通过U_BOOT_CMD宏定义的,这个宏在include/command.h头文件中定义,每一个命令定义一个cmd_tbl_t结构体。
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage,_help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help,NULL)
每一个命令宏U_BOOT_CMD用cmd_tbl_t结构体描述一个命令:
#ifndef __ASSEMBLY__
/*
* Monitor CommandTable
*/
struct cmd_tbl_s {
char *name; /* Command Name这是命令名字,不需要用双引号括起来*/
int maxargs; /* maximum number of arguments最大参数个数 */
int repeatable; /* autorepeat allowed? 命令是否可重复,就是说下一次按回车时再执行 */
/*Implementation function */
int (*cmd)(structcmd_tbl_s *, int, int, char * const []);//对应的执行函数
char *usage; /* Usage message (short)字符串对尖的简短说明 */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* Help message (long) 帮助 */
#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
};
typedef struct cmd_tbl_s cmd_tbl_t;
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd,_usage, _help, _comp) \
ll_entry_declare(cmd_tbl_t,_name, cmd) = \
U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage,_help, _comp);
上面的宏函数是定义一个cmd_tbl_t的结构体,同时给它的每个成员给值,给值是通过U_BOOT_CMD_MKENT_COMPLETE这个宏来完成的。
#define ll_entry_declare(_type, _name, _list) \
_type_u_boot_list_2_##_list##_2_##_name __aligned(4) \
__attribute__((unused, \
section(".u_boot_list_2_"#_list"_2_"#_name)))
在这个宏中可以看出所定义的这个结构体是放在u_boot_list段中,同时是四个字节以齐。
所定义的结构体的名子是通过双#号来连接一些参数名来完成。凡是带有__attribute__((unused,section (".u_boot_list"))属性声明的变量都将被存放在".u_boot_list"段中,并且即使该变量没有在代码中显式的使用编译器也不产生警告信息。“##”与“#”都是预编译操作符,“##”有字符串连接的功能,“#”表示后面紧接着的是一个字符串.
#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep,_cmd, \
_usage,_help, _comp) \
{#_name, _maxargs, _rep, _cmd, _usage, \
_CMD_HELP(_help)_CMD_COMPLETE(_comp) }
上面的宏就是拆分各个参数。
编译完uboot后,就可以在uboot.lds和uboot.map中看到映射地址如下:
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*)));
}
. = .;
__start___ex_table =.;
__ex_table : {*(__ex_table) }
__stop___ex_table =.;
.u_boot_list 0x00000000efff886c 0x8ec
*(SORT(.u_boot_list*))
.u_boot_list_2_cmd_1
0x00000000efff886c 0x0common/libcommon.o
.u_boot_list_2_cmd_2_base
0x00000000efff886c 0x1ccommon/libcommon.o
0x00000000efff886c _u_boot_list_2_cmd_2_base
.u_boot_list_2_cmd_2_bdinfo
0x00000000efff8888 0x1ccommon/libcommon.o
0x00000000efff8888 _u_boot_list_2_cmd_2_bdinfo
.u_boot_list_2_cmd_2_boot
0x00000000efff88a4 0x1ccommon/libcommon.o
0x00000000efff88a4 _u_boot_list_2_cmd_2_boot
.u_boot_list_2_cmd_2_bootd
0x00000000efff88c0 0x1ccommon/libcommon.o
0x00000000efff88c0 _u_boot_list_2_cmd_2_bootd
.u_boot_list_2_cmd_2_bootelf
0x00000000efff88dc 0x1ccommon/libcommon.o
0x00000000efff88dc _u_boot_list_2_cmd_2_bootelf
.u_boot_list_2_cmd_2_bootm
0x00000000efff88f8 0x1ccommon/libcommon.o
0x00000000efff88f8 _u_boot_list_2_cmd_2_bootm
.u_boot_list_2_cmd_2_bootp
0x00000000efff8914 0x1ccommon/libcommon.o
0x00000000efff8914 _u_boot_list_2_cmd_2_bootp
.u_boot_list_2_cmd_2_bootvx
0x00000000efff8930 0x1ccommon/libcommon.o
0x00000000efff8930 _u_boot_list_2_cmd_2_bootvx
.u_boot_list_2_cmd_2_cmp
0x00000000efff894c 0x1ccommon/libcommon.o
0x00000000efff894c _u_boot_list_2_cmd_2_cmp
.u_boot_list_2_cmd_2_coninfo
0x00000000efff8968 0x1ccommon/libcommon.o
0x00000000efff8968 _u_boot_list_2_cmd_2_coninfo
.u_boot_list_2_cmd_2_cp
0x00000000efff8984 0x1ccommon/libcommon.o
0x00000000efff8984 _u_boot_list_2_cmd_2_cp
………..
我们在uboot的源代码里,一些命令是在cmd_XXX.c中去定义和实现的。
在这里我们以cp命令来说明命令的执行和增加过程.
Cp命令是在cmd_mem.c中定义。如下:
U_BOOT_CMD(
cp, 4, 1, do_mem_cp,
"memorycopy",
"[.b,.w, .l] source target count"
);
static int do_mem_cp(cmd_tbl_t *cmdtp, int flag, intargc, char * const argv[])
{
ulong addr, dest, count, bytes;
int size;
constvoid *src;
void*buf;
if(argc != 4)
returnCMD_RET_USAGE;
/*Check for size specification.
*/
if((size = cmd_get_data_size(argv[0], 4)) < 0)
return1;
addr= simple_strtoul(argv[1], NULL, 16);
addr+= base_address;
dest= simple_strtoul(argv[2], NULL, 16);
dest+= base_address;
count= simple_strtoul(argv[3], NULL, 16);
if(count == 0) {
puts("Zero length ???\n");
return1;
}
#ifndef CONFIG_SYS_NO_FLASH
/*check if we are copying to Flash */
if ((addr2info(dest) != NULL)
#ifdef CONFIG_HAS_DATAFLASH
&& (!addr_dataflash(dest))
#endif
) {
intrc;
puts("Copy to Flash... ");
rc= flash_write ((char *)addr, dest, count*size); //调用flash_write写入数据,这个函数是在common/flash.c中定义
if(rc != 0) {
flash_perror(rc);
return(1);
}
puts("done\n");
return0;
}
#endif
#ifdef CONFIG_HAS_DATAFLASH
/*Check if we are copying from RAM or Flash to DataFlash */
if(addr_dataflash(dest) && !addr_dataflash(addr)){
intrc;
puts("Copy to DataFlash... ");
rc= write_dataflash (dest, addr, count*size);
if(rc != 1) {
dataflash_perror(rc);
return(1);
}
puts("done\n");
return0;
}
/*Check if we are copying from DataFlash to RAM */
if(addr_dataflash(addr) && !addr_dataflash(dest)
#ifndef CONFIG_SYS_NO_FLASH
&& (addr2info(dest) == NULL)
#endif
){
intrc;
rc= read_dataflash(addr, count * size, (char *) dest);
if(rc != 1) {
dataflash_perror(rc);
return(1);
}
return0;
}
if(addr_dataflash(addr) && addr_dataflash(dest)){
puts("Unsupported combination of source/destination.\n\r");
return1;
}
#endif
#ifdef CONFIG_BLACKFIN
/*See if we‘re copying to/from L1 inst */
if(addr_bfin_on_chip_mem(dest) || addr_bfin_on_chip_mem(addr)) {
memcpy((void*)dest, (void *)addr, count * size);
return0;
}
#endif
bytes= size * count;
buf= map_sysmem(dest, bytes);
src= map_sysmem(addr, bytes);
while(count-- > 0) {
if(size == 4)
*((ulong*)buf) = *((ulong *)src);
elseif (size == 2)
*((ushort*)buf) = *((ushort *)src);
else
*((u_char*)buf) = *((u_char *)src);
src+= size;
buf+= size;
/*reset watchdog from time to time */
if((count % (64 << 10)) == 0)
WATCHDOG_RESET();
}
return0;
}
int
flash_write (char *src, ulong addr, ulong cnt)
{
#ifdef CONFIG_SPD823TS
return(ERR_TIMOUT); /* any other error codesare possible as well */
#else
inti;
ulong end = addr + cnt - 1;
flash_info_t*info_first = addr2info (addr);
flash_info_t*info_last = addr2info (end );
flash_info_t*info;
__maybe_unusedchar *src_orig = src;
__maybe_unusedchar *addr_orig = (char *)addr;
__maybe_unusedulong cnt_orig = cnt;
if(cnt == 0) {
return(ERR_OK);
}
if(!info_first || !info_last) {
return(ERR_INVAL);
}
for(info = info_first; info <= info_last; ++info) {
ulongb_end = info->start[0] + info->size; /*bank end addr */
shorts_end = info->sector_count - 1;
for(i=0; i<info->sector_count; ++i) {
ulonge_addr = (i == s_end) ? b_end : info->start[i + 1];
if((end >= info->start[i]) && (addr < e_addr) &&
(info->protect[i] != 0) ) {
return(ERR_PROTECTED);
}
}
}
/*finally write data to flash */
for(info = info_first; info <= info_last && cnt>0; ++info) {
ulonglen;
len= info->start[0] + info->size - addr;
if(len > cnt)
len= cnt;
if((i = write_buff(info, (uchar *)src, addr, len)) != 0) {//调用cfi_flash.c中的write_buff写入数据
return(i);
}
cnt -= len;
addr+= len;
src += len;
}
#if defined(CONFIG_FLASH_VERIFY)
if(memcmp(src_orig, addr_orig, cnt_orig)) {
printf("\nVerifyfailed!\n");
returnERR_PROG_ERROR;
}
#endif /* CONFIG_SYS_FLASH_VERIFY_AFTER_WRITE */
return(ERR_OK);
#endif /* CONFIG_SPD823TS */
}
原文:http://blog.csdn.net/jackyard/article/details/20221809