aboutsummaryrefslogtreecommitdiff
path: root/src/target/mem_ap.c
diff options
context:
space:
mode:
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>2017-02-20 14:29:01 +0100
committerMatthias Welwarsky <matthias@welwarsky.de>2018-09-10 09:37:03 +0100
commit5d458cf72734a4474f38bbed10eea4d9acfe93a2 (patch)
tree38593c85509aa7f58fd46447f66eb813f4806aa9 /src/target/mem_ap.c
parent23cd59cdf2a563b840e5917e36c4241ee4d988f4 (diff)
downloadriscv-openocd-5d458cf72734a4474f38bbed10eea4d9acfe93a2.zip
riscv-openocd-5d458cf72734a4474f38bbed10eea4d9acfe93a2.tar.gz
riscv-openocd-5d458cf72734a4474f38bbed10eea4d9acfe93a2.tar.bz2
target/mem_ap: generic mem-ap target
This pseudo target allows attaching to any access point on the DAP at the MEM-AP level and read and write addresses on the connected bus. For example, one can create a mem_ap target on the APB-AP and read and write registers of debug components directly. This allows many diagnostic and other features be programmed entirely using TCL, without necessity of adding drivers to OpenOCD. Change-Id: I53229ffd68fb0f96fb68be15b0f3a76cc8843c8e Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com> Reviewed-on: http://openocd.zylin.com/4002 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Leonard Crestez <cdleonard@gmail.com>
Diffstat (limited to 'src/target/mem_ap.c')
-rw-r--r--src/target/mem_ap.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c
new file mode 100644
index 0000000..3a2d4b7
--- /dev/null
+++ b/src/target/mem_ap.c
@@ -0,0 +1,181 @@
+/*****************************************************************************
+ * Copyright (C) 2016 by Matthias Welwarsky <matthias.welwarsky@sysgo.com> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "target.h"
+#include "target_type.h"
+#include "arm.h"
+#include "arm_adi_v5.h"
+
+#include <jtag/jtag.h>
+
+struct mem_ap {
+ struct arm arm;
+ struct adiv5_ap *ap;
+ int ap_num;
+};
+
+static int mem_ap_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct mem_ap *mem_ap = calloc(1, sizeof(struct mem_ap));
+ struct adiv5_private_config *pc;
+
+ pc = (struct adiv5_private_config *)target->private_config;
+ if (pc == NULL)
+ return ERROR_FAIL;
+
+ if (pc->ap_num == DP_APSEL_INVALID) {
+ LOG_ERROR("AP number not specified");
+ return ERROR_FAIL;
+ }
+
+ mem_ap->ap_num = pc->ap_num;
+ mem_ap->arm.common_magic = ARM_COMMON_MAGIC;
+ mem_ap->arm.dap = pc->dap;
+
+ target->arch_info = mem_ap;
+
+ return ERROR_OK;
+}
+
+static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_UNKNOWN;
+ return ERROR_OK;
+}
+
+static int mem_ap_arch_state(struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_poll(struct target *target)
+{
+ if (target->state == TARGET_UNKNOWN)
+ target->state = TARGET_RUNNING;
+
+ return ERROR_OK;
+}
+
+static int mem_ap_halt(struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_HALTED;
+ return ERROR_OK;
+}
+
+static int mem_ap_resume(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints, int debug_execution)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_RUNNING;
+ return ERROR_OK;
+}
+
+static int mem_ap_step(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_HALTED;
+ return ERROR_OK;
+}
+
+static int mem_ap_assert_reset(struct target *target)
+{
+ target->state = TARGET_RESET;
+
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_examine(struct target *target)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ if (!target_was_examined(target)) {
+ mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num);
+ target_set_examined(target);
+ target->state = TARGET_UNKNOWN;
+ return mem_ap_init(mem_ap->ap);
+ }
+
+ return ERROR_OK;
+}
+
+static int mem_ap_deassert_reset(struct target *target)
+{
+ if (target->reset_halt)
+ target->state = TARGET_HALTED;
+ else
+ target->state = TARGET_RUNNING;
+
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_read_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ LOG_DEBUG("Reading memory at physical address 0x" TARGET_ADDR_FMT
+ "; size %" PRId32 "; count %" PRId32, address, size, count);
+
+ if (count == 0 || buffer == NULL)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return mem_ap_read_buf(mem_ap->ap, buffer, size, count, address);
+}
+
+static int mem_ap_write_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count,
+ const uint8_t *buffer)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ LOG_DEBUG("Writing memory at physical address 0x" TARGET_ADDR_FMT
+ "; size %" PRId32 "; count %" PRId32, address, size, count);
+
+ if (count == 0 || buffer == NULL)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return mem_ap_write_buf(mem_ap->ap, buffer, size, count, address);
+}
+
+struct target_type mem_ap_target = {
+ .name = "mem_ap",
+
+ .target_create = mem_ap_target_create,
+ .init_target = mem_ap_init_target,
+ .examine = mem_ap_examine,
+ .target_jim_configure = adiv5_jim_configure,
+
+ .poll = mem_ap_poll,
+ .arch_state = mem_ap_arch_state,
+
+ .halt = mem_ap_halt,
+ .resume = mem_ap_resume,
+ .step = mem_ap_step,
+
+ .assert_reset = mem_ap_assert_reset,
+ .deassert_reset = mem_ap_deassert_reset,
+
+ .read_memory = mem_ap_read_memory,
+ .write_memory = mem_ap_write_memory,
+};