diff --git a/.gitignore b/.gitignore index 40a272d..879697e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ subprojects/* !subprojects/*.wrap +# LSP cache +.cache/ + # segfault core file */core diff --git a/src/bridge/debug.c b/src/bridge/debug.c index f37d0c1..0f5765b 100644 --- a/src/bridge/debug.c +++ b/src/bridge/debug.c @@ -550,7 +550,7 @@ static struct ahb *debug_driver_probe(struct connection_args *connection) struct debug *ctx; int rc; - ctx = malloc(sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx)); if (!ctx) { return NULL; } @@ -558,9 +558,12 @@ static struct ahb *debug_driver_probe(struct connection_args *connection) /* Early abort if no interface at all is defined */ if (connection->interface == NULL) { logd("No interface for debug provided, skipping...\n"); + free(ctx); return NULL; } + ctx->force_quit = connection->force_quit; + if (!connection->internet_args) { /* Local debug interface */ if ((rc = debug_init(ctx, connection->interface)) < 0) { diff --git a/src/bridge/devmem.c b/src/bridge/devmem.c index a9dce5e..6911683 100644 --- a/src/bridge/devmem.c +++ b/src/bridge/devmem.c @@ -245,7 +245,7 @@ devmem_driver_probe(struct connection_args *connection __unused) struct devmem *ctx; int rc; - ctx = malloc(sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx)); if (!ctx) { return NULL; } diff --git a/src/bridge/ilpc.c b/src/bridge/ilpc.c index 6276d58..85a98af 100644 --- a/src/bridge/ilpc.c +++ b/src/bridge/ilpc.c @@ -335,7 +335,7 @@ ilpcb_driver_probe(struct connection_args *connection __unused) struct ilpcb *ctx; int rc; - ctx = malloc(sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx)); if (!ctx) { return NULL; } diff --git a/src/bridge/l2a.c b/src/bridge/l2a.c index bc62987..259e0ee 100644 --- a/src/bridge/l2a.c +++ b/src/bridge/l2a.c @@ -240,7 +240,7 @@ l2ab_driver_probe(struct connection_args *connection __unused) struct l2ab *ctx; int rc; - ctx = malloc(sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx)); if (!ctx) { return NULL; } diff --git a/src/bridge/p2a.c b/src/bridge/p2a.c index 1e07f4f..206fd2e 100644 --- a/src/bridge/p2a.c +++ b/src/bridge/p2a.c @@ -280,7 +280,7 @@ p2ab_driver_probe(struct connection_args *connection __unused) struct p2ab *ctx; int rc; - ctx = malloc(sizeof(*ctx)); + ctx = calloc(1, sizeof(*ctx)); if (!ctx) { return NULL; } diff --git a/src/cmd/debug.c b/src/cmd/debug.c deleted file mode 100644 index fb6d1b8..0000000 --- a/src/cmd/debug.c +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (C) 2018,2021 IBM Corp. - -#include "ahb.h" -#include "ast.h" -#include "bridge/debug.h" -#include "cmd.h" -#include "connection.h" -#include "host.h" -#include "log.h" - -#include -#include -#include -#include - -static char cmd_debug_args_doc[] = - " via DRIVER INTERFACE [IP PORT USERNAME PASSWORD]"; -static char cmd_debug_doc[] = "\n" - "Debug command" - "\v" - "Supported commands:\n" - " read Read data via debug UART\n" - " write Write data via debug UART\n"; - -static struct argp_option cmd_debug_options[] = { - { "force-quit", 'F', 0, 0, "Blindly exit debug mode before entering", - 0 }, - { 0 }, -}; - -struct cmd_debug_args { - struct connection_args connection; - struct ast_ahb_args ahb_args; - bool force_quit; -}; - -static error_t cmd_debug_parse_opt(int key, char *arg, struct argp_state *state) -{ - struct cmd_debug_args *arguments = state->input; - int rc; - - switch (key) { - case 'F': - arguments->force_quit = 1; - break; - case ARGP_KEY_ARG: - if (!strcmp(arg, "via")) { - rc = cmd_parse_via(state->next - 1, state, - &arguments->connection); - if (rc != 0) - argp_error( - state, - "Failed to parse connection arguments. Returned code %d", - rc); - break; - } - - switch (state->arg_num) { - case 0: - if (strcmp("read", arg) && strcmp("write", arg)) - argp_error(state, "Invalid command '%s'", arg); - - if (!strcmp("read", arg)) - arguments->ahb_args.read = true; - break; - case 1: - arguments->ahb_args.address = strtoul(arg, NULL, 0); - break; - case 2: - if (!arguments->ahb_args.read) { - static uint32_t write_val; - write_val = strtoul(arg, NULL, 0); - arguments->ahb_args.write_value = &write_val; - } else { - logd("Found third argument in read mode, ignoring...\n"); - } - break; - } - break; - case ARGP_KEY_END: - if (state->arg_num < 2) - argp_error( - state, - "Not enough arguments provided. Need at least an address."); - - if (!arguments->ahb_args.read && state->arg_num < 3) - argp_error( - state, - "Write mode detected but either no address or value detected"); - - if (arguments->connection.interface == NULL) - argp_error(state, - "Debug interface path must be defined"); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -static struct argp cmd_debug_argp = { - .options = cmd_debug_options, - .parser = cmd_debug_parse_opt, - .args_doc = cmd_debug_args_doc, - .doc = cmd_debug_doc, -}; - -static int do_debug(int argc, char **argv) -{ - struct debug _debug, *debug = &_debug; - struct ahb *ahb; - int rc, cleanup; - - /* ./culvert debug read 0x1e6e207c digi,portserver-ts-16 */ - struct cmd_debug_args arguments = { 0 }; - rc = argp_parse(&cmd_debug_argp, argc, argv, ARGP_IN_ORDER, 0, - &arguments); - if (rc != 0) - return rc; - - /* Ensure that force_quit is passed to debug ctx */ - debug->force_quit = arguments.force_quit; - - logi("Initialising debug interface\n"); - if (!arguments.connection.internet_args) { - /* Local debug interface */ - if ((rc = debug_init(debug, arguments.connection.interface)) < - 0) { - loge("Failed to initialise local debug interace on %s: %d\n", - arguments.connection.interface, rc); - return rc; - } - } else { - /* Remote debug interface */ - rc = debug_init(debug, arguments.connection.interface, - arguments.connection.ip, - arguments.connection.port, - arguments.connection.username, - arguments.connection.password); - if (rc < 0) { - loge("Failed to initialise remote debug interface: %d\n", - rc); - return rc; - } - } - - if (rc < 0) { - errno = -rc; - perror("debug_init"); - return rc; - } - - rc = debug_enter(debug); - if (rc < 0) { - errno = -rc; - perror("debug_enter"); - goto destroy_ctx; - } - - ahb = debug_as_ahb(debug); - rc = ast_ahb_access(&arguments.ahb_args, ahb); - if (rc) { - errno = -rc; - perror("ast_ahb_access"); - return rc; - } - - cleanup = debug_exit(debug); - if (cleanup < 0) { - errno = -cleanup; - perror("debug_exit"); - } - -destroy_ctx: - logi("Destroying debug interface\n"); - cleanup = debug_destroy(debug); - if (cleanup < 0) { - errno = -cleanup; - perror("debug_destroy"); - } - - return rc; -} - -static const struct cmd debug_cmd = { - .name = "debug", - .description = "Read or write 4 bytes of data via the AHB bridge", - .fn = do_debug, -}; -REGISTER_CMD(debug_cmd); diff --git a/src/cmd/devmem.c b/src/cmd/devmem.c deleted file mode 100644 index bc5df9b..0000000 --- a/src/cmd/devmem.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (C) 2018,2021 IBM Corp. - -#include "ahb.h" -#include "ast.h" -#include "bridge/devmem.h" -#include "cmd.h" -#include "priv.h" - -#include -#include -#include -#include - -static char cmd_devmem_args_doc[] = ""; -static char cmd_devmem_doc[] = "\n" - "Devmem command" - "\v" - "Supported commands:\n" - " read Read data from /dev/mem\n" - " write Write data to /dev/mem\n"; - -static struct argp_option cmd_devmem_options[] = { - { 0 }, -}; - -struct cmd_devmem_args { - struct ast_ahb_args ahb_args; -}; - -static error_t cmd_devmem_parse_opt(int key, char *arg, - struct argp_state *state) -{ - struct cmd_devmem_args *arguments = state->input; - - switch (key) { - case ARGP_KEY_ARG: - switch (state->arg_num) { - case 0: - if (strcmp("read", arg) && strcmp("write", arg)) - argp_error(state, "Invalid command '%s'", arg); - - if (!strcmp("read", arg)) - arguments->ahb_args.read = true; - break; - case 1: - arguments->ahb_args.address = strtoul(arg, NULL, 0); - break; - case 2: - if (!arguments->ahb_args.read) { - static uint32_t write_val; - write_val = strtoul(arg, NULL, 0); - arguments->ahb_args.write_value = &write_val; - } else - logd("Found third argument in read mode, ignoring...\n"); - break; - } - break; - case ARGP_KEY_END: - if (state->arg_num < 2) - argp_error( - state, - "Not enough arguments provided. Need at least an address."); - - if (!arguments->ahb_args.read && state->arg_num < 3) - argp_error( - state, - "Write mode detected but either no address or value detected"); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -static struct argp cmd_devmem_argp = { - .options = cmd_devmem_options, - .parser = cmd_devmem_parse_opt, - .args_doc = cmd_devmem_args_doc, - .doc = cmd_devmem_doc, -}; - -static int do_devmem(int argc, char **argv) -{ - struct devmem _devmem, *devmem = &_devmem; - struct ahb *ahb; - int cleanup, rc; - - struct cmd_devmem_args arguments = { 0 }; - rc = argp_parse(&cmd_devmem_argp, argc, argv, ARGP_IN_ORDER, 0, - &arguments); - if (rc != 0) - return rc; - - /* - * We do not use debug_drvier_probe here as we need data - * that's not being returned there. - */ - rc = devmem_init(devmem); - if (rc < 0) { - bool denied = (rc == -EACCES || rc == -EPERM); - if (denied && !priv_am_root()) { - priv_print_unprivileged(program_invocation_short_name); - } else { - errno = -rc; - perror("devmem_init"); - } - return rc; - } - - ahb = devmem_as_ahb(devmem); - rc = ast_ahb_access(&arguments.ahb_args, ahb); - if (rc) { - errno = -rc; - perror("ast_ahb_access"); - return rc; - } - - cleanup = devmem_destroy(devmem); - if (cleanup) { - errno = -cleanup; - perror("devmem_destroy"); - return cleanup; - } - - return 0; -} - -static const struct cmd devmem_cmd = { - .name = "devmem", - .description = "Read or write data to /dev/mem", - .fn = do_devmem, -}; -REGISTER_CMD(devmem_cmd); diff --git a/src/cmd/ilpc.c b/src/cmd/ilpc.c deleted file mode 100644 index a5e46eb..0000000 --- a/src/cmd/ilpc.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (C) 2018,2021 IBM Corp. - -#include "ahb.h" -#include "ast.h" -#include "bridge/ilpc.h" -#include "cmd.h" -#include "priv.h" - -#include -#include -#include -#include - -static char cmd_ilpc_args_doc[] = ""; -static char cmd_ilpc_doc[] = "\n" - "ilpc command" - "\v" - "Supported commands:\n" - " read Read data via iLPC\n" - " write Write data via iLPC\n"; - -static struct argp_option cmd_ilpc_options[] = { - { 0 }, -}; - -struct cmd_ilpc_args { - struct ast_ahb_args ahb_args; -}; - -static error_t cmd_ilpc_parse_opt(int key, char *arg, struct argp_state *state) -{ - struct cmd_ilpc_args *arguments = state->input; - - switch (key) { - case ARGP_KEY_ARG: - switch (state->arg_num) { - case 0: - if (strcmp("read", arg) && strcmp("write", arg)) - argp_error(state, "Invalid command '%s'", arg); - - if (!strcmp("read", arg)) - arguments->ahb_args.read = true; - break; - case 1: - arguments->ahb_args.address = strtoul(arg, NULL, 0); - break; - case 2: - if (!arguments->ahb_args.read) { - static uint32_t write_val; - write_val = strtoul(arg, NULL, 0); - arguments->ahb_args.write_value = &write_val; - } else { - logd("Found third argument in read mode, ignoring...\n"); - } - break; - } - break; - case ARGP_KEY_END: - if (state->arg_num < 2) - argp_error( - state, - "Not enough arguments provided. Need at least an address."); - - if (!arguments->ahb_args.read && state->arg_num < 3) - argp_error( - state, - "Write mode detected but either no address or value detected"); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -static struct argp cmd_ilpc_argp = { - .options = cmd_ilpc_options, - .parser = cmd_ilpc_parse_opt, - .args_doc = cmd_ilpc_args_doc, - .doc = cmd_ilpc_doc, -}; - -static int do_ilpc(int argc, char **argv) -{ - struct ilpcb _ilpcb, *ilpcb = &_ilpcb; - struct ahb *ahb; - int cleanup, rc; - - struct cmd_ilpc_args arguments = { 0 }; - rc = argp_parse(&cmd_ilpc_argp, argc, argv, ARGP_IN_ORDER, 0, - &arguments); - if (rc != 0) - return rc; - - /* - * We do not use debug_drvier_probe here as we need data - * that's not being returned there. - */ - rc = ilpcb_init(ilpcb); - if (rc < 0) { - bool denied = (rc == -EACCES || rc == -EPERM); - if (denied && !priv_am_root()) { - priv_print_unprivileged(program_invocation_short_name); - } else { - errno = -rc; - perror("ilpcb_init"); - } - return rc; - } - - ahb = ilpcb_as_ahb(ilpcb); - rc = ast_ahb_access(&arguments.ahb_args, ahb); - if (rc) { - errno = -rc; - perror("ast_ahb_access"); - return rc; - } - - cleanup = ilpcb_destroy(ilpcb); - if (cleanup) { - errno = -cleanup; - perror("ilpcb_destroy"); - return rc; - } - - return 0; -} - -static const struct cmd ilpc_cmd = { - .name = "ilpc", - .description = "Read or write via iLPC", - .fn = do_ilpc, -}; -REGISTER_CMD(ilpc_cmd); diff --git a/src/cmd/meson.build b/src/cmd/meson.build index a956d67..4ef4836 100644 --- a/src/cmd/meson.build +++ b/src/cmd/meson.build @@ -1,9 +1,6 @@ src += files( 'console.c', 'coprocessor.c', - 'debug.c', - 'devmem.c', - 'ilpc.c', 'jtag.c', 'otp.c', 'p2a.c', diff --git a/src/cmd/probe.c b/src/cmd/probe.c index f03df09..42c2a10 100644 --- a/src/cmd/probe.c +++ b/src/cmd/probe.c @@ -141,7 +141,7 @@ static int do_probe(int argc, char **argv) host_destroy(host); done: - exit(rc); + return rc; } static const struct cmd probe_cmd = { diff --git a/src/cmd/read.c b/src/cmd/read.c index 573ff89..928b97c 100644 --- a/src/cmd/read.c +++ b/src/cmd/read.c @@ -23,35 +23,42 @@ #include static char cmd_read_args_doc[] = - "--type= [
] " + "--type= [[
] ] " "[via DRIVER [INTERFACE [IP PORT USERNAME PASSWORD]]]"; static char cmd_read_doc[] = "\n" "Read command" "\v" - "NOTE: Only the 'ram' type can parse address and length!\n\n" + "NOTE: Only the 'ram' type can parse both address and length!\n" + "The 'reg' type only accepts an address!\n\n" "All data will be written to stdout.\n\n" "Supported types:\n" " firmware Read the content from the FMC\n" + " reg Read the content of a specific register " + "(requires the use of the via keyword)\n" " ram Read the content from the memory\n"; enum cmd_read_mode { none, firmware, ram, + reg, }; static struct argp_option cmd_read_options[] = { { "type", 't', "TYPE", 0, "Type to be read from", 0 }, + { "force-quit", 'F', 0, 0, "Blindly exit debug mode before entering", + 0 }, { 0 }, }; struct cmd_read_args { unsigned long mem_base; unsigned long mem_size; - struct connection_args connection; enum cmd_read_mode mode; + struct connection_args connection; + struct ast_ahb_args ahb_args; }; static error_t cmd_read_parse_opt(int key, char *arg, struct argp_state *state) @@ -61,13 +68,19 @@ static error_t cmd_read_parse_opt(int key, char *arg, struct argp_state *state) switch (key) { case 't': - if (strcmp(arg, "firmware") && strcmp(arg, "ram")) + if (strcmp(arg, "firmware") && strcmp(arg, "ram") && + strcmp(arg, "reg")) argp_error(state, "Invalid type '%s'", arg); if (!strcmp(arg, "firmware")) arguments->mode = firmware; - else + else if (!strcmp(arg, "ram")) arguments->mode = ram; + else + arguments->mode = reg; + break; + case 'F': + arguments->connection.force_quit = true; break; case ARGP_KEY_ARG: if (!strcmp(arg, "via")) { @@ -76,19 +89,20 @@ static error_t cmd_read_parse_opt(int key, char *arg, struct argp_state *state) if (rc != 0) argp_error( state, - "Failed to parse connection arguments. Returned code %d", + "Failed to parse connection arguments." + " Returned code %d", rc); break; } - /* If mode is not ram, skip any further args */ - if (arguments->mode != ram) + if (arguments->mode != ram && arguments->mode != reg) break; if (state->arg_num == 0) - parse_mem_arg(state, "read RAM base", - &arguments->mem_base, arg); - else if (state->arg_num == 1) + parse_mem_arg(state, "read base", &arguments->mem_base, + arg); + + if (arguments->mode == ram && state->arg_num == 1) parse_mem_arg(state, "read RAM size", &arguments->mem_size, arg); @@ -96,11 +110,20 @@ static error_t cmd_read_parse_opt(int key, char *arg, struct argp_state *state) case ARGP_KEY_END: if (arguments->mode == none) argp_error(state, "No type to be read from defined..."); - /* It is possible to not pass the ram base and size */ + + if (arguments->mode == reg && state->arg_num < 1) + argp_error(state, + "Not enough arguments for 'reg' mode..."); + + if (arguments->mode == reg && + arguments->connection.bridge_driver == NULL) + argp_error(state, + "Connection arguments (via) missing..."); + if (arguments->mode == ram && (state->arg_num > 0 && state->arg_num < 2)) argp_error(state, - "Not enough arguments for ram mode..."); + "Not enough arguments for 'ram' mode..."); break; default: return ARGP_ERR_UNKNOWN; @@ -262,6 +285,33 @@ static int cmd_read_ram(struct cmd_read_args *arguments) return rc; } +static int cmd_read_reg(struct cmd_read_args *arguments) +{ + struct host _host, *host = &_host; + struct ahb *ahb; + int rc; + + if ((rc = host_init(host, &arguments->connection)) < 0) { + loge("Failed to initialise host interfaces: %d\n", rc); + return rc; + } + + if (!(ahb = host_get_ahb(host))) { + loge("Failed to acquire AHB interface, exiting\n"); + rc = -ENODEV; + goto cleanup_host; + } + + arguments->ahb_args.read = true; + arguments->ahb_args.address = arguments->mem_base; + rc = ast_ahb_access(&arguments->ahb_args, ahb); + +cleanup_host: + host_destroy(host); + + return rc; +} + static int do_read(int argc, char **argv) { int rc; @@ -280,6 +330,9 @@ static int do_read(int argc, char **argv) case ram: rc = cmd_read_ram(&arguments); break; + case reg: + rc = cmd_read_reg(&arguments); + break; /* If it reaches none here, then the argument parse logic is broken. */ case none: loge("read: Reached 'none' mode after argument parsing. This is a bug!\n"); @@ -292,7 +345,7 @@ static int do_read(int argc, char **argv) static const struct cmd read_cmd = { .name = "read", - .description = "Read data from the FMC or RAM", + .description = "Read data from the FMC, RAM or a register", .fn = do_read, }; REGISTER_CMD(read_cmd); diff --git a/src/cmd/write.c b/src/cmd/write.c index 662a19a..1c24a82 100644 --- a/src/cmd/write.c +++ b/src/cmd/write.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,35 +28,43 @@ #define SFC_FLASH_WIN (64 << 10) static char cmd_write_args_doc[] = - "--type= [
] " + "--type= [
] " "[via DRIVER [INTERFACE [IP PORT USERNAME PASSWORD]]]"; static char cmd_write_doc[] = "\n" "Write command" "\v" - "NOTE: Only the 'ram' type can parse address and length and requires them!\n\n" - "All data will be read from stdin.\n\n" + "NOTE: Both the 'ram' and 'reg' types require both " + "address and length!\n\n" + "All data for 'firmware' and 'ram' will be read from stdin.\n\n" "Supported types:\n" " firmware Write stdin to the FMC\n" + " reg Write a value to a specific register " + "(requires the use of the via keyword)\n" " ram Write stdin to the memory\n"; enum cmd_write_mode { none, firmware, ram, + reg, }; static struct argp_option cmd_write_options[] = { - { "type", 't', "TYPE", 0, "Type to be write to", 0 }, + { "type", 't', "TYPE", 0, "Type to write to", 0 }, + { "force-quit", 'F', 0, 0, "Blindly exit debug mode before entering", + 0 }, { 0 }, }; struct cmd_write_args { unsigned long mem_base; unsigned long mem_size; - struct connection_args connection; enum cmd_write_mode mode; + struct connection_args connection; + struct ast_ahb_args ahb_args; + uint32_t reg_value; }; static error_t cmd_write_parse_opt(int key, char *arg, struct argp_state *state) @@ -65,13 +74,19 @@ static error_t cmd_write_parse_opt(int key, char *arg, struct argp_state *state) switch (key) { case 't': - if (strcmp(arg, "firmware") && strcmp(arg, "ram")) + if (strcmp(arg, "firmware") && strcmp(arg, "ram") && + strcmp(arg, "reg")) argp_error(state, "Invalid type '%s'", arg); if (!strcmp(arg, "firmware")) arguments->mode = firmware; - else + else if (!strcmp(arg, "ram")) arguments->mode = ram; + else + arguments->mode = reg; + break; + case 'F': + arguments->connection.force_quit = true; break; case ARGP_KEY_ARG: if (!strcmp(arg, "via")) { @@ -80,34 +95,39 @@ static error_t cmd_write_parse_opt(int key, char *arg, struct argp_state *state) if (rc != 0) argp_error( state, - "Failed to parse connection arguments. Returned code %d", + "Failed to parse connection arguments." + " Returned code %d", rc); break; } - /* If mode is not ram, skip any further args */ - if (arguments->mode != ram) + if (arguments->mode != ram && arguments->mode != reg) break; - switch (state->arg_num) { - case 0: - parse_mem_arg(state, "write RAM base", - &arguments->mem_base, arg); - break; - case 1: + if (state->arg_num == 0) + parse_mem_arg(state, "write base", &arguments->mem_base, + arg); + + if (arguments->mode == ram && state->arg_num == 1) parse_mem_arg(state, "write RAM size", &arguments->mem_size, arg); - break; - } + + if (arguments->mode == reg && state->arg_num == 1) + arguments->reg_value = strtoul(arg, NULL, 0); break; case ARGP_KEY_END: if (arguments->mode == none) argp_error(state, "No type to write to defined..."); - /* Other than the read command,this requires the arguments for ram */ - if (arguments->mode == ram && state->arg_num < 2) + + if (arguments->mode == reg && + arguments->connection.bridge_driver == NULL) + argp_error(state, + "Connection arguments (via) missing..."); + + if (arguments->mode != firmware && state->arg_num < 2) argp_error(state, - "Not enough arguments for ram mode..."); + "Not enough arguments for selected mode..."); break; default: return ARGP_ERR_UNKNOWN; @@ -336,6 +356,34 @@ static int cmd_write_ram(struct cmd_write_args *arguments) return rc; } +static int cmd_write_reg(struct cmd_write_args *arguments) +{ + struct host _host, *host = &_host; + struct ahb *ahb; + int rc; + + if ((rc = host_init(host, &arguments->connection)) < 0) { + loge("Failed to initialise host interfaces: %d\n", rc); + return rc; + } + + if (!(ahb = host_get_ahb(host))) { + loge("Failed to acquire AHB interface, exiting\n"); + rc = -ENODEV; + goto cleanup_host; + } + + arguments->ahb_args.read = false; + arguments->ahb_args.address = arguments->mem_base; + arguments->ahb_args.write_value = &arguments->reg_value; + rc = ast_ahb_access(&arguments->ahb_args, ahb); + +cleanup_host: + host_destroy(host); + + return rc; +} + static int do_write(int argc, char **argv) { int rc; @@ -353,9 +401,12 @@ static int do_write(int argc, char **argv) case ram: rc = cmd_write_ram(&arguments); break; + case reg: + rc = cmd_write_reg(&arguments); + break; /* If it reaches none here, then the argument parse logic is broken. */ case none: - loge("read: Reached 'none' mode after argument parsing. This is a bug!\n"); + loge("write: Reached 'none' mode after argument parsing. This is a bug!\n"); rc = -EINVAL; break; } @@ -365,7 +416,7 @@ static int do_write(int argc, char **argv) static const struct cmd write_cmd = { .name = "write", - .description = "Write data to the FMC or RAM", + .description = "Write data to the FMC, RAM or a register", .fn = do_write, }; REGISTER_CMD(write_cmd); diff --git a/src/connection.h b/src/connection.h index 6253a66..c86013a 100644 --- a/src/connection.h +++ b/src/connection.h @@ -42,5 +42,12 @@ struct connection_args { * (IP, username, etc.) are set. */ bool internet_args; + + /** + * Blindly send an escape + quit sequence to the debug UART, before + * entering debug mode, in case a previous session was left open. + * Only relevant for the debug-uart bridge driver. + */ + bool force_quit; }; #endif