uboot學習之cp命令

一、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 */

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章