[PATCH v4 06/14] command: Replace the cmd_rep pointer with a CMDF_REPEATABLE flag
Simon Glass
sjg at chromium.org
Wed Jul 1 13:42:26 CEST 2026
Each struct cmd_tbl entry carries a ->cmd_rep function pointer used to
report whether a command may be repeated by pressing Enter at an empty
prompt. For all but one command it points at cmd_always_repeatable() or
cmd_never_repeatable(), trampolines that just set the repeatable flag
and call cmd_invoke() - so a whole pointer per command encodes a single
bit, on every board.
Replace it with a CMDF_REPEATABLE flag in the existing cmd_flags byte.
The _rep argument of the U_BOOT_CMD*() macros now sets this bit, and
cmd_call() reads it directly before invoking ->cmd, dropping the
trampolines entirely.
Sub-command dispatchers (U_BOOT_CMD_WITH_SUBCMDS, and the x86 zboot
command) still need to report the repeatability of the sub-command they
pick, which they do through the extended (..., int *repeatable)
signature. Keep that ability with a CMDF_SUBCMD_REP flag: such a command
stores its dispatcher in ->cmd and is tagged CMDF_SUBCMD_REP, and
cmd_call() calls it with the repeatable pointer. The dispatcher refines
*repeatable from the chosen sub-command's CMDF_REPEATABLE bit.
This removes a pointer from every struct cmd_tbl entry: the struct
shrinks from 56 to 48 bytes on 64-bit and by 4 bytes per entry on
32-bit, with no change in behaviour and no new config option. On
turris_1x_nor (ppc32, ~100 commands) this recovers about 670 bytes,
enough to keep the board within its NOR section after the getopt
conversion.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
Changes in v4:
- Add new patch to replace the ->cmd_rep pointer with a
CMDF_REPEATABLE flag, dropping a pointer from every command entry
cmd/help.c | 2 +-
cmd/test.c | 2 +-
cmd/x86/zboot.c | 2 +-
common/command.c | 44 +++++++-------------
include/command.h | 104 ++++++++++++++++++++++------------------------
5 files changed, 67 insertions(+), 87 deletions(-)
diff --git a/cmd/help.c b/cmd/help.c
index b87c19003d4..ab6f9c95739 100644
--- a/cmd/help.c
+++ b/cmd/help.c
@@ -28,7 +28,7 @@ U_BOOT_CMD(
* nor can we rely on the CONFIG_SYS_LONGHELP helper macro
*/
ll_entry_declare(struct cmd_tbl, question_mark, cmd) = {
- "?", CONFIG_SYS_MAXARGS, 0, cmd_always_repeatable, do_help,
+ "?", CONFIG_SYS_MAXARGS, CMDF_REPEATABLE, do_help,
"alias for 'help'",
#ifdef CONFIG_SYS_LONGHELP
""
diff --git a/cmd/test.c b/cmd/test.c
index f0b89aa0af0..32c5238972d 100644
--- a/cmd/test.c
+++ b/cmd/test.c
@@ -244,7 +244,7 @@ U_BOOT_CMD(
* This does not use the U_BOOT_CMD macro as [ can't be used in symbol names
*/
ll_entry_declare(struct cmd_tbl, lbracket, cmd) = {
- "[", CONFIG_SYS_MAXARGS, 0, cmd_always_repeatable, do_test,
+ "[", CONFIG_SYS_MAXARGS, CMDF_REPEATABLE, do_test,
"alias for 'test'",
#ifdef CONFIG_SYS_LONGHELP
" <test expression> ]"
diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c
index 3876d163236..ef3e27e622d 100644
--- a/cmd/x86/zboot.c
+++ b/cmd/x86/zboot.c
@@ -165,7 +165,7 @@ int do_zboot_parent(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
-U_BOOT_CMDREP_COMPLETE(
+U_BOOT_SUBCMD_DECL(
zboot, 8, do_zboot_parent, "Boot bzImage",
"[addr] [size] [initrd addr] [initrd size] [setup] [cmdline]\n"
" addr - The optional starting address of the bzimage.\n"
diff --git a/common/command.c b/common/command.c
index c747bef7883..4204c6e2df2 100644
--- a/common/command.c
+++ b/common/command.c
@@ -508,11 +508,6 @@ void fixup_cmdtable(struct cmd_tbl *cmdtp, int size)
for (i = 0; i < size; i++) {
ulong addr;
- addr = (ulong)(cmdtp->cmd_rep) + gd->reloc_off;
- cmdtp->cmd_rep =
- (int (*)(struct cmd_tbl *, int, int,
- char * const [], int *))addr;
-
addr = (ulong)(cmdtp->cmd) + gd->reloc_off;
#ifdef DEBUG_COMMANDS
printf("Command \"%s\": 0x%08lx => 0x%08lx\n",
@@ -558,30 +553,6 @@ int cmd_invoke(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
return cmdtp->cmd(cmdtp, flag, argc, argv);
}
-int cmd_always_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[], int *repeatable)
-{
- *repeatable = 1;
-
- return cmd_invoke(cmdtp, flag, argc, argv);
-}
-
-int cmd_never_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[], int *repeatable)
-{
- *repeatable = 0;
-
- return cmd_invoke(cmdtp, flag, argc, argv);
-}
-
-int cmd_discard_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[])
-{
- int repeatable;
-
- return cmdtp->cmd_rep(cmdtp, flag, argc, argv, &repeatable);
-}
-
/**
* Call a command function. This should be the only route in U-Boot to call
* a command, so that we can track whether we are waiting for input or
@@ -599,7 +570,20 @@ static int cmd_call(struct cmd_tbl *cmdtp, int flag, int argc,
{
int result;
- result = cmdtp->cmd_rep(cmdtp, flag, argc, argv, repeatable);
+ *repeatable = !!(cmdtp->cmd_flags & CMDF_REPEATABLE);
+
+ if (cmdtp->cmd_flags & CMDF_SUBCMD_REP) {
+ /*
+ * A sub-command dispatcher refines *repeatable for the
+ * sub-command it picks, so call it with the extended signature.
+ */
+ cmd_rep_func_t func = (cmd_rep_func_t)cmdtp->cmd;
+
+ result = func(cmdtp, flag, argc, argv, repeatable);
+ } else {
+ result = cmd_invoke(cmdtp, flag, argc, argv);
+ }
+
if (result)
debug("Command failed, result=%d\n", result);
return result;
diff --git a/include/command.h b/include/command.h
index 495d6a07d75..b201100870a 100644
--- a/include/command.h
+++ b/include/command.h
@@ -39,16 +39,6 @@ struct cmd_tbl {
char *name; /* Command Name */
short maxargs; /* maximum number of arguments */
u8 cmd_flags; /* CMDF_... flags */
- /*
- * Same as ->cmd() except the command
- * tells us if it can be repeated.
- * Replaces the old ->repeatable field
- * which was not able to make
- * repeatable property different for
- * the main command and sub-commands.
- */
- int (*cmd_rep)(struct cmd_tbl *cmd, int flags, int argc,
- char *const argv[], int *repeatable);
/* Implementation function */
int (*cmd)(struct cmd_tbl *cmd, int flags, int argc,
char *const argv[]);
@@ -76,8 +66,24 @@ enum {
* (int (*)(struct getopt_state *)) instead of the classic one
*/
CMDF_GETOPT = BIT(0),
+ /* the command may be repeated by pressing Enter at an empty prompt */
+ CMDF_REPEATABLE = BIT(1),
+ /*
+ * ->cmd holds a sub-command dispatcher with the extended signature
+ * (..., int *repeatable), so it can report the repeatable property of
+ * the sub-command it dispatched to. cmd_call() calls it accordingly.
+ */
+ CMDF_SUBCMD_REP = BIT(2),
};
+/*
+ * Type of a sub-command dispatcher (a CMDF_SUBCMD_REP command's ->cmd). It has
+ * the classic command arguments plus a @repeatable output which it sets from
+ * the sub-command it dispatches to.
+ */
+typedef int (*cmd_rep_func_t)(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[], int *repeatable);
+
/**
* cmd_arg_get() - Get a particular argument
*
@@ -142,17 +148,9 @@ int cmd_usage(const struct cmd_tbl *cmdtp);
*/
int cmd_invoke(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
-/* Dummy ->cmd and ->cmd_rep wrappers. */
-int cmd_always_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[], int *repeatable);
-int cmd_never_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[], int *repeatable);
-int cmd_discard_repeatable(struct cmd_tbl *cmdtp, int flag, int argc,
- char *const argv[]);
-
static inline bool cmd_is_repeatable(struct cmd_tbl *cmdtp)
{
- return cmdtp->cmd_rep == cmd_always_repeatable;
+ return cmdtp->cmd_flags & CMDF_REPEATABLE;
}
#ifdef CONFIG_AUTO_COMPLETE
@@ -416,8 +414,9 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
!cmd_is_repeatable(subcmd)) \
return CMD_RET_SUCCESS; \
\
- return subcmd->cmd_rep(subcmd, flag, argc - 1, \
- argv + 1, repeatable); \
+ *repeatable &= cmd_is_repeatable(subcmd); \
+ \
+ return cmd_invoke(subcmd, flag, argc - 1, argv + 1); \
}
#ifdef CONFIG_AUTO_COMPLETE
@@ -441,21 +440,17 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
U_BOOT_SUBCMDS_COMPLETE(_cmdname)
#if CONFIG_IS_ENABLED(CMDLINE)
-#define U_BOOT_CMDREP_MKENT_COMPLETE(_name, _maxargs, _cmd_rep, \
- _usage, _help, _comp) \
- { #_name, _maxargs, 0, _cmd_rep, cmd_discard_repeatable, \
- _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
+/* Encode the _rep argument as the CMDF_REPEATABLE flag bit */
+#define _CMD_REP_FLAG(_rep) ((_rep) ? CMDF_REPEATABLE : 0)
#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, _comp) \
- { #_name, _maxargs, 0, \
- _rep ? cmd_always_repeatable : cmd_never_repeatable, \
+ { #_name, _maxargs, _CMD_REP_FLAG(_rep), \
_cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
#define U_BOOT_CMD_MKENT_GETOPT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, _comp) \
- { #_name, _maxargs, CMDF_GETOPT, \
- _rep ? cmd_always_repeatable : cmd_never_repeatable, \
+ { #_name, _maxargs, CMDF_GETOPT | _CMD_REP_FLAG(_rep), \
(int (*)(struct cmd_tbl *, int, int, \
char *const []))(_cmd), \
_usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
@@ -480,11 +475,18 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
U_BOOT_CMD_MKENT_GETOPT_COMPLETE(_name, _maxargs, _rep, \
_cmd, _usage, _help, _comp)
-#define U_BOOT_CMDREP_COMPLETE(_name, _maxargs, _cmd_rep, _usage, \
- _help, _comp) \
- ll_entry_declare(struct cmd_tbl, _name, cmd) = \
- U_BOOT_CMDREP_MKENT_COMPLETE(_name, _maxargs, _cmd_rep, \
- _usage, _help, _comp)
+/*
+ * Declare a top-level command whose ->cmd is a sub-command dispatcher with
+ * the extended (..., int *repeatable) signature (see CMDF_SUBCMD_REP). The
+ * dispatcher is stored in ->cmd and tagged so cmd_call() invokes it with the
+ * repeatable pointer.
+ */
+#define U_BOOT_SUBCMD_DECL(_name, _maxargs, _do_cmd, _usage, _help, _comp) \
+ ll_entry_declare(struct cmd_tbl, _name, cmd) = { \
+ #_name, _maxargs, CMDF_SUBCMD_REP | CMDF_REPEATABLE, \
+ (int (*)(struct cmd_tbl *, int, int, \
+ char *const []))(_do_cmd), \
+ _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
#else
#define U_BOOT_SUBCMD_START(name) static struct cmd_tbl name[] = {};
@@ -498,14 +500,6 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
return 0; \
}
-#define _CMD_REMOVE_REP(_name, _cmd) \
- int __remove_ ## _name(void) \
- { \
- if (0) \
- _cmd(NULL, 0, 0, NULL, NULL); \
- return 0; \
- }
-
#define _CMD_REMOVE_GETOPT(_name, _cmd) \
int __remove_ ## _name(void) \
{ \
@@ -514,19 +508,14 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
return 0; \
}
-#define U_BOOT_CMDREP_MKENT_COMPLETE(_name, _maxargs, _cmd_rep, \
- _usage, _help, _comp) \
- { #_name, _maxargs, 0, 0 ? _cmd_rep : NULL, NULL, _usage, \
- _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
-
#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, \
_help, _comp) \
- { #_name, _maxargs, 0, NULL, 0 ? _cmd : NULL, _usage, \
+ { #_name, _maxargs, 0, 0 ? _cmd : NULL, _usage, \
_CMD_HELP(_help) _CMD_COMPLETE(_comp) }
#define U_BOOT_CMD_MKENT_GETOPT_COMPLETE(_name, _maxargs, _rep, _cmd, \
_usage, _help, _comp) \
- { #_name, _maxargs, CMDF_GETOPT, NULL, \
+ { #_name, _maxargs, CMDF_GETOPT, \
0 ? (int (*)(struct cmd_tbl *, int, int, \
char *const []))(_cmd) : NULL, _usage, \
_CMD_HELP(_help) _CMD_COMPLETE(_comp) }
@@ -547,9 +536,16 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
_help, _comp) \
_CMD_REMOVE_GETOPT(sub_ ## _name, _cmd)
-#define U_BOOT_CMDREP_COMPLETE(_name, _maxargs, _cmd_rep, _usage, \
- _help, _comp) \
- _CMD_REMOVE_REP(sub_ ## _name, _cmd_rep)
+#define _CMD_REMOVE_REP(_name, _cmd) \
+ int __remove_ ## _name(void) \
+ { \
+ if (0) \
+ _cmd(NULL, 0, 0, NULL, NULL); \
+ return 0; \
+ }
+
+#define U_BOOT_SUBCMD_DECL(_name, _maxargs, _do_cmd, _usage, _help, _comp) \
+ _CMD_REMOVE_REP(sub_ ## _name, _do_cmd)
#endif /* CONFIG_CMDLINE */
@@ -571,7 +567,7 @@ int cmd_source_script(ulong addr, const char *fit_uname, const char *confname);
#define U_BOOT_CMD_WITH_SUBCMDS(_name, _usage, _help, ...) \
U_BOOT_SUBCMDS(_name, __VA_ARGS__) \
- U_BOOT_CMDREP_COMPLETE(_name, CONFIG_SYS_MAXARGS, do_##_name, \
- _usage, _help, complete_##_name)
+ U_BOOT_SUBCMD_DECL(_name, CONFIG_SYS_MAXARGS, do_##_name, \
+ _usage, _help, complete_##_name)
#endif /* __COMMAND_H */
--
2.43.0
More information about the U-Boot
mailing list