http://blog.youkuaiyun.com/sailor_8318/article/details/4332088
【摘要】:本文介绍了PPC-Boot中命令的组织结构及解析过程,接着介绍了添加自定义命令的基本框架,为Pbist项目中如何添加自定义测试功能奠定了基础。PPC-Boot命令的检测及解析机制可在PUC Boot中借鉴,其可扩展行裁剪性非常适合用嵌入式系统应用。
【关键字】:PPC-Boot;MPC8270;run_command ; parse_line;find_cmd
1、命令结构定义
2、命令解析过程
3、如何添加用户命令
1)、定义CACHE命令标志位
2)、配置系统当前支持的CMD
3)、实现CACHE命令的操作函数
4)、添加命令表项宏定义
5)、添加命令到系统搜索列表中
6)、更改Makefile
PPC-Boot的命令为用户提供了交互功能,并且已经实现了几十个常用的命令。如果开发板需要很特殊的操作,可以添加新的PPC-Boot命令.
1、命令结构定义
PPC-Boot的每一个命令都是通过MK_CMD_TBL_ENTRY宏定义的。这个宏在include/command.h头文件中定义,每一个命令定义一个cmd_tbl_t结构体。
#ifdef CFG_LONGHELP
#define MK_CMD_TBL_ENTRY(name,lmin,maxargs,rep,cmd,usage,help) /
{name, lmin, maxargs, rep, cmd, usage, help }
#else /* no helpinfo */
#define MK_CMD_TBL_ENTRY(name,lmin,maxargs,rep,cmd,usage,help) /
{name, lmin, maxargs, rep, cmd, usage }
#endif
struct cmd_tbl_s {
char *name; /* Command Name */
int lmin; /* minimum abbreviated length */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/*Implementation function */
int (*cmd)(struct cmd_tbl_s *,int, int, char *[]);
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
};
这样每一个PPC-Boot命令有一个结构体来描述。结构体包含的成员变量:命令名称、最大参数个数、是否允许重复执行上一个命令、命令执行函数、用法、帮助。
Name是匹配因子,大小写必须一致,否则无法识别。
2、命令解析过程
从控制台输入的命令是由common/main.c中的程序解释执行的。
main_loop为循环入口函数,其在指定的延时时间内检测是否有输入,若没有,则自动运行“bootcmd”所指定的命令;若有输入,则readline循环检测用户输入,用户输入Enter后,run_command执行输入命令,其解析由“;”所分割的每个命令,parse_line将命令及其参数重新组织,find_cmd进行命令匹配检测,命令匹配成功后,将其传给命令表中注册的执行函数
(cmdtp->cmd) (cmdtp,flag, argc, argv)
由具体的命令函数进一步检查相关参数。
涉及的相关函数列表如下:
/* common/main.c */
int readline (const char *const prompt)
int run_command (const char *cmd, int flag)
int parse_line (char *line, char *argv[])
/* common/command.c */
cmd_tbl_t *find_cmd(const char *cmd);
find_cmd()负责匹配输入的命令,从列表中找出对应的命令结构体。
3、如何添加用户命令
由上面命令解析的过程可知,添加一个新命令,只需要实现命令对应的函数即可,命令的输入及解析无需我们关心。
基于PPC-Boot命令的基本框架,来分析一下简单的icache操作命令,就可以知道添加新命令的方法。
1)、定义CACHE命令标志位
在include/cmd_confdefs.h中定义了所有PPC-Boot命令的标志位。
#defineCFG_CMD_CACHE 0x00000010 /* icache, dcache */
如果有更多的命令,也需要在这里添加定义,不能与其他命令的标志位冲突。
2)、配置系统当前支持的CMD
PPC-Boot的命令系统扩展性非常好,可以定制,添加删除,打开CONFIG_COMMANDS选项的命令标志位。这个程序文件开头 有#if语句需要预处理是否包含这个命令函数。CONFIG_COMMANDS选项在开发板的配置文件中定义当前支持的所有命令。例如:SMDK2410平台在 include/configs/smdk2410.h中有如下定义。
#define CONFIG_COMMANDS (CONFIG_CMD_DFL| /
CFG_CMD_I2C |/
CFG_CMD_CACHE |/
CFG_CMD_MII | /
CFG_CMD_EEPROM)
/* this must be included AFTER the definition ofCONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
3)、实现CACHE命令的操作函数
下面是common/cmd_cache.c文件中icache命令部分的代码。
为了便于裁剪代码,程序都是通过1和2两步所定义的宏开关来控制的。
#if (CONFIG_COMMANDS &CFG_CMD_CACHE)
static int on_off (const char *s)
{ //这个函数解析参数,判断是打开cache,还是关闭cache
if (strcmp(s,"on") == 0) { //参数为“on”
return(1);
} else if(strcmp(s, "off") == 0) { //参数为“off”
return(0);
}
return (-1);
}
int do_icache ( cmd_tbl_t *cmdtp, int flag, int argc, char*argv[])
{ //对指令cache的操作函数
switch (argc) {
case 2: /* 参数个数为1,则执行打开或者关闭指令cache操作 */
switch(on_off(argv[1])) {
case0: icache_disable(); //打开指令cache
break;
case1: icache_enable (); //关闭指令cache
break;
}
/* FALLTROUGH */
case 1: /* 参数个数为0,则获取指令cache状态*/
printf("Instruction Cache is %s/n",
icache_status() ? "ON" : "OFF");
return 0;
default: //其他缺省情况下,打印命令使用说明
printf ("Usage:/n%s/n",cmdtp->usage);
return 1;
}
return 0;
}
4)、添加命令表项宏定义
一般在相应命令的头文件中定义该命令表项宏,如/include/cmd_cache.h
#if (CONFIG_COMMANDS &CFG_CMD_CACHE)
#define CMD_TBL_ICACHE MK_CMD_TBL_ENTRY( /
"icache", 2, 2, 1, do_icache, /
"icache - enable or disable instructioncache/n", /
"[on,off]/n" /
" - enable or disable instructioncache/n" /
),
#define CMD_TBL_DCACHE MK_CMD_TBL_ENTRY( /
"dcache", 2, 2, 1, do_dcache, /
"dcache - enable or disable data cache/n", /
"[on,off]/n" /
" - enable or disable data (writethrough)cache/n" /
),
int do_icache (cmd_tbl_t *cmdtp, int flag, int argc, char*argv[]);
int do_dcache (cmd_tbl_t *cmdtp, int flag, int argc, char*argv[]);
#else
#define CMD_TBL_ICACHE
#define CMD_TBL_DCACHE
#endif /*CFG_CMD_CACHE */
当系统不支持某命令时,该宏自动实现为空,对系统不会有任何影响,尤其是下面的命令数组,其不需要再用宏来控制
5)、添加命令到系统搜索列表中
/common/command.c中包括了系统所有的命令
首先添加上面某命令的头文件,如#include<cmd_cache.h>
然后添加命令到搜索列表中,否则系统无法识别该命令。注意此数组的排列顺序是按照字母顺序组成的,便于搜索,因此新添加的命令一定要遵循此规则。
/*
* The commands inthis table are sorted alphabetically by the
* command name and in descending order by thecommand name string
* length. This is to prevent conflictsin command name parsing.
* Please ensure thatnew commands are added according to that rule.
* Please use$(TOPDIR)/doc/README.commands as a reference AND make
* sure it getsupdated.
*/
cmd_tbl_t cmd_tbl[] = {
CMD_TBL_ASKENV
CMD_TBL_ASM
CMD_TBL_AUTOSCRIPT
。。。。。
CMD_TBL_BSP
。。
CMD_TBL_DCACHE
。。
#if defined(CONFIG_PUC8250) || defined(CONFIG_PUC8260) ||defined(CONFIG_PUC8270)
#if defined(AXR)
CMD_TBL_TEST_ALL_AXR
#elif defined(ODU_LC)
CMD_TBL_TEST_ALL_MSH
#elif defined(XMP1)
CMD_TBL_TEST_ALL_XMP1
#endif
CMD_TBL_TEST_EEPROM
CMD_TBL_TEST_ETHERNET
CMD_TBL_TEST_FLASH
CMD_TBL_TEST_RS232
CMD_TBL_TEST_SDRAM
#if defined(L2C)
CMD_TBL_INV_L2C
#endif
#endif
CMD_TBL_QUES /* keep this("help") the last entry */
/*the following entry terminates this table */
MK_CMD_TBL_ENTRY(NULL, 0, 0, 0, NULL, NULL, NULL )
};
cmd_tbl数组的大小是由CONFIG_COMMANDS所定义支持的命令数来决定的,大小是动态的,因此需要一个表项来表示结束MK_CMD_TBL_ENTRY(NULL, 0, 0, 0, NULL, NULL, NULL )。
裁剪CONFIG_COMMANDS时,无需再更改此数组,因为由第四步可知,相关表现自动为空。
6)、更改Makefile
在common/Makefile中添加编译的目标文件,否则系统不会编译新添加的代码。
COBJS = main.oaltera.o bedbug.o /
cmd_autoscript.o cmd_bedbug.o cmd_boot.o /
cmd_bootm.o cmd_cache.ocmd_console.o cmd_date.o /
cmd_dcr.o cmd_diag.o cmd_doc.o cmd_dtt.o /
cmd_eeprom.o cmd_elf.o cmd_fdc.o cmd_flash.o/
cmd_fpga.o cmd_i2c.o cmd_ide.o cmd_immap.o /
cmd_jffs2.o cmd_mem.o cmd_mii.o cmd_misc.o /
cmd_net.o cmd_nvedit.o env_common.o /
env_flash.o env_eeprom.o env_nvram.oenv_nowhere.o /
cmd_pci.o cmd_pcmcia.o cmd_test.o/
cmd_reginfo.o cmd_scsi.o cmd_vfd.o cmd_usb.o/
command.o console.o devices.o dlmalloc.o /
docecc.o environment.o flash.o fpga.o /
hush.o kgdb.o lists.o miiphybb.o miiphyutil.o/
s_record.o soft_i2c.o soft_spi.o cmd_spi.ospartan2.o /
usb.o usb_kbd.o usb_storage.o /
virtex2.o xilinx.o