diff --git a/README.md b/README.md index 5601543..ec3bb43 100644 --- a/README.md +++ b/README.md @@ -113,34 +113,24 @@ apt install build-essential flex swig bison meson device-tree-compiler libyaml-d ``` $ ./build/src/culvert -h -culvert: v0.4.0-10-gb30b8364b75a +culvert: v0.4.0-196-g34001fbe828a Usage: -culvert probe [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert ilpc read ADDRESS -culvert ilpc write ADDRESS VALUE -culvert p2a vga read ADDRESS -culvert p2a vga write ADDRESS VALUE -culvert debug read ADDRESS INTERFACE [IP PORT USERNAME PASSWORD] -culvert debug write ADDRESS VALUE INTERFACE [IP PORT USERNAME PASSWORD] -culvert devmem read ADDRESS -culvert devmem write ADDRESS VALUE -culvert console HOST_UART BMC_UART BAUD USER PASSWORD -culvert read firmware [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert read ram [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert write firmware [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert replace ram MATCH REPLACE -culvert reset TYPE WDT [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert jtag TARGET [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert sfc fmc read ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert sfc fmc erase ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert sfc fmc write ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert otp read conf [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert otp read strap [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert otp write strap BIT VALUE [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert otp write conf WORD BIT [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert trace ADDRESS WIDTH MODE [INTERFACE [IP PORT USERNAME PASSWORD]] -culvert coprocessor run ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert console HOST_UART BMC_UART BAUD USER PASSWORD + culvert coprocessor [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert debug INTERFACE [IP PORT USERNAME PASSWORD] + culvert devmem + culvert ilpc |write > [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert p2a vga + culvert probe [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert read [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert replace ram MATCH REPLACE + culvert reset TYPE WDT [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert sfc fmc ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert trace ADDRESS WIDTH MODE [INTERFACE [IP PORT USERNAME PASSWORD]] + culvert write [INTERFACE [IP PORT USERNAME PASSWORD]] ``` ``` diff --git a/src/cmd.h b/src/cmd.h new file mode 100644 index 0000000..c1d597e --- /dev/null +++ b/src/cmd.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright (C) 2024 Andrew Jeffery */ + +#ifndef CULVERT_CMD_H +#define CULVERT_CMD_H + +#include "ccan/autodata/autodata.h" +#include + +struct cmd { + const char *name; + const char *help; + int (*fn)(const char *, int, char *[]); +}; + +AUTODATA_TYPE(cmds, struct cmd); +#define REGISTER_CMD(cmd) AUTODATA_SYM(cmds, cmd); + +static inline int cmd_cmp(const void *a, const void *b) +{ + const struct cmd * const *acmd = a; + const struct cmd * const *bcmd = b; + + return strcmp((*acmd)->name, (*bcmd)->name); +} + +#endif diff --git a/src/cmd/console.c b/src/cmd/console.c index 93b7015..c77b130 100644 --- a/src/cmd/console.c +++ b/src/cmd/console.c @@ -3,6 +3,7 @@ #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "host.h" #include "log.h" @@ -16,7 +17,7 @@ #include #include -int cmd_console(const char *name __unused, int argc, char *argv[]) +static int do_console(const char *name __unused, int argc, char *argv[]) { struct suart _suart, *suart = &_suart; struct host _host, *host = &_host; @@ -179,3 +180,9 @@ int cmd_console(const char *name __unused, int argc, char *argv[]) return rc; } +static const struct cmd console_cmd = { + "console", + "HOST_UART BMC_UART BAUD USER PASSWORD", + do_console +}; +REGISTER_CMD(console_cmd); diff --git a/src/cmd/coprocessor.c b/src/cmd/coprocessor.c index 27a03c5..ca8507a 100644 --- a/src/cmd/coprocessor.c +++ b/src/cmd/coprocessor.c @@ -2,6 +2,7 @@ // Copyright (C) 2024 Code Construct #include "bits.h" +#include "cmd.h" #include "compiler.h" #include "host.h" #include "log.h" @@ -274,7 +275,7 @@ static int cmd_coprocessor_stop(const char *name __unused, int argc, char *argv[ return rc; } -int cmd_coprocessor(const char *name __unused, int argc, char *argv[]) +static int do_coprocessor(const char *name __unused, int argc, char *argv[]) { const char *arg_subcmd; @@ -295,3 +296,10 @@ int cmd_coprocessor(const char *name __unused, int argc, char *argv[]) return EXIT_FAILURE; } + +static const struct cmd coprocessor_cmd = { + "coprocessor", + " [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_coprocessor +}; +REGISTER_CMD(coprocessor_cmd); diff --git a/src/cmd/debug.c b/src/cmd/debug.c index 636261a..2268f61 100644 --- a/src/cmd/debug.c +++ b/src/cmd/debug.c @@ -6,9 +6,10 @@ #include "ahb.h" #include "ast.h" #include "bridge/debug.h" +#include "cmd.h" #include "log.h" -int cmd_debug(const char *name, int argc, char *argv[]) +static int do_debug(const char *name, int argc, char *argv[]) { struct debug _debug, *debug = &_debug; struct ahb *ahb; @@ -73,3 +74,10 @@ int cmd_debug(const char *name, int argc, char *argv[]) return rc; } + +static const struct cmd debug_cmd = { + "debug", + " INTERFACE [IP PORT USERNAME PASSWORD]", + do_debug +}; +REGISTER_CMD(debug_cmd); diff --git a/src/cmd/devmem.c b/src/cmd/devmem.c index 30d6970..ebea719 100644 --- a/src/cmd/devmem.c +++ b/src/cmd/devmem.c @@ -7,9 +7,10 @@ #include "ahb.h" #include "ast.h" #include "bridge/devmem.h" +#include "cmd.h" #include "priv.h" -int cmd_devmem(const char *name, int argc, char *argv[]) +static int do_devmem(const char *name, int argc, char *argv[]) { struct devmem _devmem, *devmem = &_devmem; struct ahb *ahb; @@ -46,3 +47,9 @@ int cmd_devmem(const char *name, int argc, char *argv[]) return 0; } +static const struct cmd devmem_cmd = { + "devmem", + "", + do_devmem, +}; +REGISTER_CMD(devmem_cmd); diff --git a/src/cmd/ilpc.c b/src/cmd/ilpc.c index 148f41e..59f4658 100644 --- a/src/cmd/ilpc.c +++ b/src/cmd/ilpc.c @@ -6,9 +6,10 @@ #include "ahb.h" #include "ast.h" #include "bridge/ilpc.h" +#include "cmd.h" #include "priv.h" -int cmd_ilpc(const char *name, int argc, char *argv[]) +static int do_ilpc(const char *name, int argc, char *argv[]) { struct ilpcb _ilpcb, *ilpcb = &_ilpcb; struct ahb *ahb; @@ -44,3 +45,10 @@ int cmd_ilpc(const char *name, int argc, char *argv[]) return 0; } + +static const struct cmd ilpc_cmd = { + "ilpc", + " #include -int cmd_otp(const char *name __unused, int argc, char *argv[]) +static int do_otp(const char *name __unused, int argc, char *argv[]) { enum otp_region reg = otp_region_conf; struct host _host, *host = &_host; @@ -104,3 +105,10 @@ int cmd_otp(const char *name __unused, int argc, char *argv[]) return rc; } + +static const struct cmd otp_cmd = { + "otp", + "|write > [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_otp, +}; +REGISTER_CMD(otp_cmd); diff --git a/src/cmd/p2a.c b/src/cmd/p2a.c index 0291c47..207ef40 100644 --- a/src/cmd/p2a.c +++ b/src/cmd/p2a.c @@ -8,10 +8,11 @@ #include "ahb.h" #include "ast.h" #include "bridge/p2a.h" +#include "cmd.h" #include "log.h" #include "priv.h" -int cmd_p2a(const char *name, int argc, char *argv[]) +static int do_p2a(const char *name, int argc, char *argv[]) { struct p2ab _p2ab, *p2ab = &_p2ab; struct ahb *ahb; @@ -55,3 +56,10 @@ int cmd_p2a(const char *name, int argc, char *argv[]) return 0; } + +static const struct cmd p2a_cmd = { + "p2a", + "vga ", + do_p2a, +}; +REGISTER_CMD(p2a_cmd); diff --git a/src/cmd/probe.c b/src/cmd/probe.c index cf0256b..ae07636 100644 --- a/src/cmd/probe.c +++ b/src/cmd/probe.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2018,2021 IBM Corp. +#include "cmd.h" #include "compiler.h" - #include "host.h" #include "log.h" #include "soc.h" @@ -24,7 +24,7 @@ cmd_probe_help(const char *name, int argc __unused, char *argv[] __unused) printf(probe_help, name, name, name, name); } -int cmd_probe(const char *name, int argc, char *argv[]) +static int do_probe(const char *name, int argc, char *argv[]) { enum bridge_mode required = bm_permissive; struct host _host, *host = &_host; @@ -123,3 +123,10 @@ int cmd_probe(const char *name, int argc, char *argv[]) done: exit(rc); } + +static const struct cmd probe_cmd = { + "probe", + "[INTERFACE [IP PORT USERNAME PASSWORD]]", + do_probe, +}; +REGISTER_CMD(probe_cmd); diff --git a/src/cmd/read.c b/src/cmd/read.c index da82c42..70bfd2f 100644 --- a/src/cmd/read.c +++ b/src/cmd/read.c @@ -3,6 +3,7 @@ #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "flash.h" #include "host.h" @@ -194,7 +195,7 @@ static int cmd_read_ram(int argc, char *argv[]) return rc; } -int cmd_read(const char *name __unused, int argc, char *argv[]) +static int do_read(const char *name __unused, int argc, char *argv[]) { int rc; @@ -214,3 +215,10 @@ int cmd_read(const char *name __unused, int argc, char *argv[]) return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } + +static const struct cmd read_cmd = { + "read", + " [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_read, +}; +REGISTER_CMD(read_cmd); diff --git a/src/cmd/replace.c b/src/cmd/replace.c index 188940a..acd3556 100644 --- a/src/cmd/replace.c +++ b/src/cmd/replace.c @@ -4,6 +4,7 @@ #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "host.h" #include "log.h" @@ -18,7 +19,7 @@ #define DUMP_RAM_WIN (8 << 20) -int cmd_replace(const char *name __unused, int argc, char *argv[]) +static int do_replace(const char *name __unused, int argc, char *argv[]) { struct host _host, *host = &_host; struct soc _soc, *soc = &_soc; @@ -128,3 +129,10 @@ int cmd_replace(const char *name __unused, int argc, char *argv[]) return rc; } + +static const struct cmd replace_cmd = { + "replace", + "ram MATCH REPLACE", + do_replace, +}; +REGISTER_CMD(replace_cmd); diff --git a/src/cmd/reset.c b/src/cmd/reset.c index 5ed914b..dbbe106 100644 --- a/src/cmd/reset.c +++ b/src/cmd/reset.c @@ -2,6 +2,7 @@ // Copyright (C) 2018,2021 IBM Corp. #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "host.h" #include "log.h" @@ -16,7 +17,7 @@ #include #include -int cmd_reset(const char *name __unused, int argc, char *argv[]) +static int do_reset(const char *name __unused, int argc, char *argv[]) { struct host _host, *host = &_host; struct soc _soc, *soc = &_soc; @@ -99,3 +100,10 @@ int cmd_reset(const char *name __unused, int argc, char *argv[]) return rc; } + +static const struct cmd reset_cmd = { + "reset", + "TYPE WDT [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_reset, +}; +REGISTER_CMD(reset_cmd); diff --git a/src/cmd/sfc.c b/src/cmd/sfc.c index d71e2d3..b0fdd60 100644 --- a/src/cmd/sfc.c +++ b/src/cmd/sfc.c @@ -2,6 +2,7 @@ // Copyright (C) 2018,2021 IBM Corp. #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "flash.h" #include "host.h" @@ -19,7 +20,7 @@ enum flash_op { flash_op_read, flash_op_write, flash_op_erase }; -int cmd_sfc(const char *name __unused, int argc, char *argv[]) +static int do_sfc(const char *name __unused, int argc, char *argv[]) { struct host _host, *host = &_host; struct soc _soc, *soc = &_soc; @@ -132,3 +133,10 @@ int cmd_sfc(const char *name __unused, int argc, char *argv[]) return rc; } + +static const struct cmd sfc_cmd = { + "sfc", + "fmc ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_sfc, +}; +REGISTER_CMD(sfc_cmd); diff --git a/src/cmd/trace.c b/src/cmd/trace.c index 01bfffe..9be9ac4 100644 --- a/src/cmd/trace.c +++ b/src/cmd/trace.c @@ -4,6 +4,7 @@ #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "host.h" #include "log.h" @@ -23,7 +24,7 @@ //culvert trace 0x1e788000 1:0 read //culvert trace 0x1e788000 2:2 read //culvert trace 0x1e788000 4:0 write -int cmd_trace(const char *name __unused, int argc, char *argv[]) +static int do_trace(const char *name __unused, int argc, char *argv[]) { struct host _host, *host = &_host; struct soc _soc, *soc = &_soc; @@ -139,3 +140,10 @@ int cmd_trace(const char *name __unused, int argc, char *argv[]) return rc; } + +static const struct cmd trace_cmd = { + "trace", + "ADDRESS WIDTH MODE [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_trace, +}; +REGISTER_CMD(trace_cmd); diff --git a/src/cmd/write.c b/src/cmd/write.c index 6533c8e..a38737a 100644 --- a/src/cmd/write.c +++ b/src/cmd/write.c @@ -2,6 +2,7 @@ // Copyright (C) 2018,2021 IBM Corp. #include "ahb.h" #include "ast.h" +#include "cmd.h" #include "compiler.h" #include "flash.h" #include "host.h" @@ -289,7 +290,7 @@ static int cmd_write_ram(int argc, char *argv[]) return rc; } -int cmd_write(const char *name __unused, int argc, char *argv[]) +static int do_write(const char *name __unused, int argc, char *argv[]) { int rc; @@ -333,3 +334,9 @@ int cmd_write(const char *name __unused, int argc, char *argv[]) return rc; } +static const struct cmd write_cmd = { + "write", + " [INTERFACE [IP PORT USERNAME PASSWORD]]", + do_write, +}; +REGISTER_CMD(write_cmd); diff --git a/src/culvert.c b/src/culvert.c index 86fb99f..e7e98e5 100644 --- a/src/culvert.c +++ b/src/culvert.c @@ -12,6 +12,7 @@ #include #include +#include "cmd.h" #include "config.h" #include "compiler.h" #include "log.h" @@ -19,90 +20,32 @@ #include "ahb.h" #include "host.h" -int cmd_ilpc(const char *name, int argc, char *argv[]); -int cmd_p2a(const char *name, int argc, char *argv[]); -int cmd_debug(const char *name, int argc, char *argv[]); -int cmd_devmem(const char *name, int argc, char *argv[]); -int cmd_console(const char *name, int argc, char *argv[]); -int cmd_read(const char *name, int argc, char *argv[]); -int cmd_write(const char *name, int argc, char *argv[]); -int cmd_replace(const char *name, int argc, char *argv[]); -int cmd_probe(const char *name, int argc, char *argv[]); -int cmd_reset(const char *name, int argc, char *argv[]); -int cmd_jtag(const char *name, int argc, char *argv[]); -int cmd_sfc(const char *name, int argc, char *argv[]); -int cmd_otp(const char *name, int argc, char *argv[]); -int cmd_trace(const char *name, int argc, char *argv[]); -int cmd_coprocessor(const char *name, int argc, char *argv[]); +#include "ccan/autodata/autodata.h" static void print_version(const char *name) { printf("%s: " CULVERT_VERSION "\n", name); } -static void print_help(const char *name) +static void print_help(const char *name, struct cmd **cmds, size_t n_cmds) { print_version(name); printf("Usage:\n"); printf("\n"); - printf("%s probe [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s ilpc read ADDRESS\n", name); - printf("%s ilpc write ADDRESS VALUE\n", name); - printf("%s p2a vga read ADDRESS\n", name); - printf("%s p2a vga write ADDRESS VALUE\n", name); - printf("%s debug read ADDRESS INTERFACE [IP PORT USERNAME PASSWORD]\n", name); - printf("%s debug write ADDRESS VALUE INTERFACE [IP PORT USERNAME PASSWORD]\n", name); - printf("%s devmem read ADDRESS\n", name); - printf("%s devmem write ADDRESS VALUE\n", name); - printf("%s console HOST_UART BMC_UART BAUD USER PASSWORD\n", name); - printf("%s read firmware [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s read ram ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s write firmware [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s write ram ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s replace ram MATCH REPLACE\n", name); - printf("%s reset TYPE WDT [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s jtag [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s sfc fmc read ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s sfc fmc erase ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s sfc fmc write ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s otp read conf [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s otp read strap [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s otp write strap BIT VALUE [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s otp write conf WORD BIT [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s trace ADDRESS WIDTH MODE [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); - printf("%s coprocessor run ADDRESS LENGTH [INTERFACE [IP PORT USERNAME PASSWORD]]\n", name); -} -struct command { - const char *name; - int (*fn)(const char *, int, char *[]); -}; - -static const struct command cmds[] = { - { "ilpc", cmd_ilpc }, - { "p2a", cmd_p2a }, - { "console", cmd_console }, - { "read", cmd_read }, - { "write", cmd_write }, - { "replace", cmd_replace }, - { "probe", cmd_probe }, - { "debug", cmd_debug }, - { "reset", cmd_reset }, - { "jtag", cmd_jtag }, - { "devmem", cmd_devmem }, - { "sfc", cmd_sfc }, - { "otp", cmd_otp }, - { "trace", cmd_trace }, - { "coprocessor", cmd_coprocessor}, - { }, -}; + for (size_t i = 0; i < n_cmds; i++) { + printf("\t%s %s %s\n", name, cmds[i]->name, cmds[i]->help); + } +} int main(int argc, char *argv[]) { - const struct command *cmd = &cmds[0]; bool show_help = false; bool quiet = false; + struct cmd **cmds; + size_t n_cmds = 0; int verbose = 0; + int rc; while (1) { static struct option long_options[] = { @@ -151,11 +94,18 @@ int main(int argc, char *argv[]) } } + cmds = autodata_get(cmds, &n_cmds); + qsort(cmds, n_cmds, sizeof(void *), cmd_cmp); + if (optind == argc) { - if (!show_help) + if (show_help) { + rc = 0; + } else { fprintf(stderr, "Error: not enough arguments\n"); - print_help(program_invocation_short_name); - exit(EXIT_FAILURE); + rc = -EINVAL; + } + print_help(program_invocation_short_name, cmds, n_cmds); + goto cleanup_cmds; } if (quiet) { @@ -166,24 +116,33 @@ int main(int argc, char *argv[]) log_set_level(level_trace); } - while (cmd->fn) { - if (!strcmp(cmd->name, argv[optind])) { - int offset = optind; - int rc; + rc = -EINVAL; + for (size_t i = 0; i < n_cmds; i++) { + struct cmd *cmd = cmds[i]; + int offset; - /* probe uses getopt, but for subcommands not using getopt */ - if (!(!strcmp("probe", argv[optind]) || !strcmp("write", argv[optind]))) { - offset += 1; - } - optind = 1; + if (strcmp(cmd->name, argv[optind])) { + continue; + } + + offset = optind; - rc = cmd->fn(program_invocation_short_name, argc - offset, argv + offset); - exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); + /* probe uses getopt, but for subcommands not using getopt */ + if (!(!strcmp("probe", argv[optind]) || !strcmp("write", argv[optind]))) { + offset += 1; } + optind = 1; + + rc = cmd->fn(program_invocation_short_name, argc - offset, argv + offset); + break; + } - cmd++; + if (rc == -EINVAL) { + fprintf(stderr, "Unrecognised command\n\n"); + print_help(program_invocation_short_name, cmds, n_cmds); } - fprintf(stderr, "Error: unknown command: %s\n", argv[1]); - exit(EXIT_FAILURE); +cleanup_cmds: + autodata_free(cmds); + exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); }