uboot分析之uboot指令實作
// md.w 0 指令列印0位址的内容
OpenJTAG> md.w 0
00000000: 00ff ea00 f014 e59f f014 e59f f014 e59f ................
00000010: f014 e59f f014 e59f f014 e59f f014 e59f ................
00000020: 0160 33f8 01c0 33f8 0220 33f8 0280 33f8 `..3...3 ..3...3
00000030: 02e0 33f8 0400 33f8 0420 33f8 beef dead ...3...3 ..3....
00000040: 0000 33f8 0000 33f8 06ac 33fb 7904 33fb ...3...3...3.y.3
00000050: c0de 0bad c0de 0bad 0000 0000 c0de 0bad ................
00000060: c0de 0bad 0000 e10f 001f e3c0 00d3 e380 ................
00000070: f000 e129 0453 e3a0 1000 e3a0 1000 e580 ..).S...........
u-boot的指令:
1. 序列槽輸入指令
2. 處理指令, 輸出結果
處理的時候肯定是根據指令名字找到對應的處理函數, 然後調用處理函數
看看run_command實作:
int run_command (const char *cmd, int flag)
{
char cmdbuf[CFG_CBSIZE];
...
strcpy (cmdbuf, cmd);
while (*str) {
process_macros (token, finaltoken);
if ((argc = parse_line (finaltoken, argv)) == 0) {
rc = -1;
continue;
}
if ((cmdtp = find_cmd(argv[0])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", argv[0]);
rc = -1;
continue;
}
if (argc > cmdtp->maxargs) {
printf ("Usage:\n%s\n", cmdtp->usage);
rc = -1;
continue;
}
#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
printf ("[%s]\n", finaltoken);
#endif
if (flag & CMD_FLAG_BOOTD) {
puts ("'bootd' recursion detected\n");
rc = -1;
continue;
} else {
flag |= CMD_FLAG_BOOTD;
}
}
#endif
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
rc = -1;
}
repeatable &= cmdtp->repeatable;
if (had_ctrlc ())
return 0;
}
}
指令結構:
struct cmd_tbl_s {
char *name;
int maxargs;
int repeatable;
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage;
#ifdef CFG_LONGHELP
char *help;
#endif
#ifdef CONFIG_AUTO_COMPLETE
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
根據指令名字找到對應的指令結構體:
cmd_tbl_t *find_cmd (const char *cmd)
{
cmd_tbl_t *cmdtp;
cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;
const char *p;
int len;
int n_found = 0;
len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);
for (cmdtp = &__u_boot_cmd_start; // __u_boot_cmd_start從uboot.lds檔案中傳進來
cmdtp != &__u_boot_cmd_end; // __u_boot_cmd_end從uboot.lds檔案中傳進來
cmdtp++) {
if (strncmp (cmd, cmdtp->name, len) == 0) { //從__u_boot_cmd_start到__u_boot_cmd_end逐個比對指令名
if (len == strlen (cmdtp->name))
return cmdtp;
cmdtp_temp = cmdtp;
n_found++;
}
}
if (n_found == 1) {
return cmdtp_temp;
}
return NULL;
}
bootm指令分析:
我們輸入bootm 0x30007FC0指令之後就确定核心, 看看bootm指令是調用哪個函數執行
在cmd_bootm.c定義了一個宏:
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
#ifdef CONFIG_OF_FLAT_TREE
"\tWhen booting a Linux kernel which requires a flat device-tree\n"
"\ta third argument is required which is the address of the of the\n"
"\tdevice-tree blob. To boot that kernel without an initrd image,\n"
"\tuse a '-' for the second argument. If you do not pass a third\n"
"\ta bd_info struct will be passed instead\n"
#endif
);
在command.h中定義了一個U_BOOT_CMD宏:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
name = bootm
maxargs = CFG_MAXARGS
rep = 1
cmd = do_bootm
usage = "bootm - boot application image from memory\n"
help = "[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
command.h中定義宏
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
将以上值代入宏
cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) = {
bootm,
CFG_MAXARGS,
1,
do_bootm,
"boo...memory\n",
"[add..image\n"
}
可以看出以上定義了名為__u_boot_cmd_bootm的cmd_tbl_t類型的結構體, 結構體的屬性section(段屬性)強制設定為.u_boot_cmd
__attribute__ ((unused,section (".u_boot_cmd")))是強制把section段屬性設定為.u_boot_cmd
可以看出所有用U_BOOT_CMD定義的東西都會相當定義了一個cmd_tbl_t類型的結構,
這個結構體的特别之處就是它的段屬性被強制設定為.u_boot_cmd, 是以所有的指令都被集中在__u_boot_cmd_start到__u_boot_cmd_end之間
實作簡單的hello指令
建立cmd_hello.c
#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>
int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i = 0;
for (i = 0; i < argc; i++)
printf("%s\r\n", argv[i]);
printf("hello world\r\n");
return 0;
}
U_BOOT_CMD(
hello, CFG_MAXARGS, 1, do_hello,
"hello - hello\n",
"hello - long hello.........\n"
);
存放在common目錄, 修改common目錄下的Makefile檔案, 加入cmd_hello.o
編譯, 燒寫就可以執行hello指令了