一、uboot增加命令過程
在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命令解析
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 */
}