target/mem_ap: generic mem-ap target 02/4002/11
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Mon, 20 Feb 2017 13:29:01 +0000 (14:29 +0100)
committerMatthias Welwarsky <matthias@welwarsky.de>
Mon, 10 Sep 2018 08:37:03 +0000 (09:37 +0100)
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>
src/target/Makefile.am
src/target/mem_ap.c [new file with mode: 0644]
src/target/target.c

index b1119e7..4b7c8c0 100644 (file)
@@ -75,7 +75,8 @@ ARMV7_SRC = \
        %D%/cortex_m.c \
        %D%/armv7a.c \
        %D%/cortex_a.c \
        %D%/cortex_m.c \
        %D%/armv7a.c \
        %D%/cortex_a.c \
-       %D%/ls1_sap.c
+       %D%/ls1_sap.c \
+       %D%/mem_ap.c
 
 ARMV8_SRC = \
        %D%/armv8_dpm.c \
 
 ARMV8_SRC = \
        %D%/armv8_dpm.c \
diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c
new file mode 100644 (file)
index 0000000..3a2d4b7
--- /dev/null
@@ -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,
+};
index 253928d..060fbdc 100644 (file)
@@ -108,6 +108,7 @@ extern struct target_type quark_x10xx_target;
 extern struct target_type quark_d20xx_target;
 extern struct target_type stm8_target;
 extern struct target_type riscv_target;
 extern struct target_type quark_d20xx_target;
 extern struct target_type stm8_target;
 extern struct target_type riscv_target;
+extern struct target_type mem_ap_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -144,6 +145,7 @@ static struct target_type *target_types[] = {
 #if BUILD_TARGET64
        &aarch64_target,
 #endif
 #if BUILD_TARGET64
        &aarch64_target,
 #endif
+       &mem_ap_target,
        NULL,
 };
 
        NULL,
 };