1. 原理
U-Boot 的命令系统基于一个称为 U_BOOT_CMD 或 U_BOOT_CMD_COMPLETE 的宏,该宏将每个命令的信息(名称、最大参数个数、帮助信息等)和对应的处理函数注册到一个特定的段(section)中。
核心工作原理:
- 命令结构体 :每个命令都通过一个
cmd_tbl_t结构体来描述。 - 链接脚本 :在链接阶段,所有通过
U_BOOT_CMD宏定义的命令结构体会被收集到名为__u_boot_list_2_cmds_*的特定内存区域。 - 命令查找:当用户在 U-Boot 命令行输入一个字符串时,U-Boot 会在这个内存区域中遍历查找匹配的命令结构体。
- 函数执行:找到匹配的命令后,调用其对应的处理函数,并传入解析好的参数。
2. 操作和执行流程
步骤一:确定代码位置
U-Boot 的命令代码通常位于:
cmd/目录下,按功能分文件存放(如cmd/bootm.c,cmd/echo.c)。- 对于板级特定的命令,有时也会放在
board/<vendor>/<board_name>/目录下,但推荐放在cmd/中以便于维护。
建议 :如果命令是通用的,可以放在 cmd/ 下;如果是非常特定的功能,可以放在 board/... 下或创建一个新的 cmd/ 文件。
步骤二:编写命令代码
我们以创建一个名为 mycmd 的命令为例,它接受一个字符串参数并将其打印出来,同时带有一个可选的重复次数参数。
步骤三:配置 Kconfig 和 Makefile
确保新命令能被编译进 U-Boot 镜像。
步骤四:编译和测试
3. 完善的代码实现
我们将创建一个新的命令文件,并实现一个功能相对完善的 mycmd 命令。
3.1 创建命令文件
在 cmd/ 目录下创建新文件 mycmd.c:
c
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2023, Your Name
*
* A custom U-Boot command to demonstrate command implementation.
*/
#include <common.h>
#include <command.h>
#include <console.h>
/**
* do_mycmd() - The function that is called when 'mycmd' is entered
* at the U-Boot console.
*
* This function handles the 'mycmd' command.
* Usage:
* mycmd <message> [count]
* - message: The string to be printed.
* - count: Optional. Number of times to repeat the message (default: 1).
*
* @cmdtp: Pointer to the command table entry
* @flag: Flags indicating the state of the command (CMD_FLAG_*)
* @argc: Number of arguments
* @argv: Array of arguments
* Return: CMD_RET_SUCCESS on success, CMD_RET_FAILURE on failure
*/
static int do_mycmd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *message;
unsigned long count = 1;
unsigned long i;
/* Check the minimum number of arguments */
if (argc < 2) {
printf("Usage: %s <message> [count]\n", argv[0]);
return CMD_RET_USAGE;
}
/* Get the message from the first argument */
message = argv[1];
/* Parse the optional count argument if provided */
if (argc > 2) {
count = simple_strtoul(argv[2], NULL, 10);
if (count == 0) {
printf("Error: count must be a positive integer\n");
return CMD_RET_FAILURE;
}
/* Set a reasonable upper limit to prevent abuse */
if (count > 100) {
printf("Error: count too large (max: 100)\n");
return CMD_RET_FAILURE;
}
}
/* Print the message 'count' times */
for (i = 0; i < count; i++) {
printf("[%3lu] %s\n", i + 1, message);
/* Check for Ctrl+C to allow interruption */
if (ctrlc()) {
printf("Command interrupted by user\n");
return CMD_RET_FAILURE;
}
}
printf("Command executed successfully! Printed %lu times.\n", count);
return CMD_RET_SUCCESS;
}
/**
* Command description and usage information
*
* U_BOOT_CMD_COMPLETE macro parameters:
* _name: Command name (what user types)
* _maxargs: Maximum number of arguments
* _rep: Whether the command is repeatable (1) or not (0)
* _cmd: Function pointer to the command handler
* _usage: Short usage string
* _help: Detailed help text
* _comp: Auto-completion function (can be NULL)
*/
U_BOOT_CMD_COMPLETE(
mycmd, /* Command name */
3, /* Maximum arguments: "mycmd" + message + count */
0, /* Not repeatable */
do_mycmd, /* Command handler function */
"Print a message multiple times", /* Short usage */
"<message> [count]\n" /* Detailed help line 1 */
" - Print a message to console.\n"
" - <message>: The string to be printed (use quotes for spaces).\n"
" - [count]: Optional number of times to repeat (default: 1, max: 100).",
NULL /* No auto-completion */
);
3.2 修改 Kconfig 文件
在 cmd/ 目录下的 Kconfig 文件中添加新命令的配置选项:
kconfig
# cmd/Kconfig
# ... existing content ...
config CMD_MYCMD
bool "Enable 'mycmd' command"
default n
help
This enables the 'mycmd' command which can print a message
multiple times. This is useful for testing command implementation
and as a template for new commands.
# ... existing content ...
3.3 修改 Makefile
在 cmd/ 目录下的 Makefile 中添加编译规则:
makefile
# cmd/Makefile
# ... existing content ...
obj-$(CONFIG_CMD_MYCMD) += mycmd.o
# ... existing content ...
3.4 (可选)为特定板级启用命令
如果你希望这个命令默认在你的开发板上启用,可以在你的板级配置文件(通常是 configs/<board_name>_defconfig)中添加:
bash
# 在 defconfig 文件中添加:
CONFIG_CMD_MYCMD=y
或者通过 make menuconfig 手动配置:
- 运行
make <board_name>_defconfig - 运行
make menuconfig - 导航到
Command line interface→ 找到并启用Enable 'mycmd' command - 保存并退出
4. 编译和测试
4.1 编译 U-Boot
bash
# 清理并重新配置
make mrproper
make <your_board>_defconfig # 如:make rpi_4_defconfig
# 编译
make -j$(nproc)
4.2 测试命令
将新编译的 U-Boot 烧写到目标板或使用 QEMU 测试:
bash
# 基本用法
u-boot=> mycmd "Hello World"
[ 1] Hello World
Command executed successfully! Printed 1 times.
# 带重复次数
u-boot=> mycmd "Test" 3
[ 1] Test
[ 2] Test
[ 3] Test
Command executed successfully! Printed 3 times.
# 测试错误情况
u-boot=> mycmd
Usage: mycmd <message> [count]
u-boot=> mycmd "Test" 0
Error: count must be a positive integer
u-boot=> mycmd "Test" 150
Error: count too large (max: 100)
# 测试帮助信息
u-boot=> help mycmd
mycmd - Print a message multiple times
Usage:
mycmd <message> [count]
- Print a message to console.
- <message>: The string to be printed (use quotes for spaces).
- [count]: Optional number of times to repeat (default: 1, max: 100).
5. 高级特性
5.1 添加命令别名
如果你想为命令创建别名(如 mc 作为 mycmd 的别名),可以这样添加:
c
U_BOOT_CMD_ALIAS(
mc, /* Alias name */
mycmd /* Original command name */
);
5.2 环境变量支持
让命令支持环境变量:
c
static int do_mycmd_advanced(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
char *message;
char buf[128];
if (argc < 2) {
printf("Usage: %s <message|env_var>\n", argv[0]);
return CMD_RET_USAGE;
}
/* Check if the argument is an environment variable */
message = env_get(argv[1]);
if (message) {
/* It's an environment variable */
printf("Message from env '%s': %s\n", argv[1], message);
} else {
/* It's a direct message */
printf("Direct message: %s\n", argv[1]);
}
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
mycmd_adv, 2, 0, do_mycmd_advanced,
"Advanced mycmd with env support",
"<message|env_var>\n"
" - If env_var exists, print its value\n"
" - Otherwise, print the string directly"
);
5.3 命令返回值
U-Boot 命令应该返回适当的返回值:
CMD_RET_SUCCESS(0): 成功CMD_RET_FAILURE(1): 失败CMD_RET_USAGE(2): 参数使用错误
6. 总结
关键要点:
- 命令处理函数签名 :必须遵循
int func(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) - 参数解析 :使用
simple_strtoul()等函数安全地转换参数 - 错误处理:提供清晰的错误信息和适当的返回值
- 用户交互 :考虑支持
ctrlc()检查以允许用户中断 - 资源配置:通过 Kconfig 和 Makefile 正确集成到构建系统
代码结构回顾:
- 包含必要的头文件 (
common.h,command.h) - 实现命令处理函数
- 使用
U_BOOT_CMD或U_BOOT_CMD_COMPLETE注册命令 - 更新 Kconfig 和 Makefile
- 配置并编译测试
这个完整的示例为你提供了一个坚实的基础,你可以基于此模板创建更复杂的 U-Boot 命令来满足特定的硬件初始化、测试或调试需求。。