diff options
-rw-r--r-- | doc/openocd.texi | 8 | ||||
-rw-r--r-- | src/target/mem_ap.c | 93 |
2 files changed, 97 insertions, 4 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi index 2cba45e..6b74243 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4509,7 +4509,13 @@ The current implementation supports eSi-32xx cores. @item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link. @item @code{ls1_sap} -- this is the SAP on NXP LS102x CPUs, allowing access to physical memory addresses independently of CPU cores. -@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without a CPU, through which bus read and write cycles can be generated; it may be useful for working with non-CPU hardware behind an AP or during development of support for new CPUs. +@item @code{mem_ap} -- this is an ARM debug infrastructure Access Port without +a CPU, through which bus read and write cycles can be generated; it may be +useful for working with non-CPU hardware behind an AP or during development of +support for new CPUs. +It's possible to connect a GDB client to this target (the GDB port has to be +specified, @xref{gdbportoverride,,option -gdb-port}), and a fake ARM core will +be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. @item @code{nds32_v2} -- this is an Andes NDS32 v2 core. diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 7ed41c6..89c0c02 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -20,6 +20,7 @@ #include "target_type.h" #include "arm.h" #include "arm_adi_v5.h" +#include "register.h" #include <jtag/jtag.h> @@ -55,6 +56,9 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) target->arch_info = mem_ap; + if (!target->gdb_port_override) + target->gdb_port_override = strdup("disabled"); + return ERROR_OK; } @@ -62,6 +66,7 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta { LOG_DEBUG("%s", __func__); target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; return ERROR_OK; } @@ -82,8 +87,10 @@ static int mem_ap_arch_state(struct target *target) static int mem_ap_poll(struct target *target) { - if (target->state == TARGET_UNKNOWN) + if (target->state == TARGET_UNKNOWN) { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } return ERROR_OK; } @@ -92,6 +99,8 @@ static int mem_ap_halt(struct target *target) { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } @@ -100,6 +109,7 @@ static int mem_ap_resume(struct target *target, int current, target_addr_t addre { LOG_DEBUG("%s", __func__); target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } @@ -108,12 +118,15 @@ static int mem_ap_step(struct target *target, int current, target_addr_t address { LOG_DEBUG("%s", __func__); target->state = TARGET_HALTED; + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int mem_ap_assert_reset(struct target *target) { target->state = TARGET_RESET; + target->debug_reason = DBG_REASON_UNDEFINED; LOG_DEBUG("%s", __func__); return ERROR_OK; @@ -127,6 +140,7 @@ static int mem_ap_examine(struct target *target) mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num); target_set_examined(target); target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; return mem_ap_init(mem_ap->ap); } @@ -135,15 +149,85 @@ static int mem_ap_examine(struct target *target) static int mem_ap_deassert_reset(struct target *target) { - if (target->reset_halt) + if (target->reset_halt) { target->state = TARGET_HALTED; - else + target->debug_reason = DBG_REASON_DBGRQ; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } else { target->state = TARGET_RUNNING; + target->debug_reason = DBG_REASON_NOTHALTED; + } LOG_DEBUG("%s", __func__); return ERROR_OK; } +static int mem_ap_reg_get(struct reg *reg) +{ + return ERROR_OK; +} + +static int mem_ap_reg_set(struct reg *reg, uint8_t *buf) +{ + return ERROR_OK; +} + +static struct reg_arch_type mem_ap_reg_arch_type = { + .get = mem_ap_reg_get, + .set = mem_ap_reg_set, +}; + +const char *mem_ap_get_gdb_arch(struct target *target) +{ + return "arm"; +} + +/* + * Dummy ARM register emulation: + * reg[0..15]: 32 bits, r0~r12, sp, lr, pc + * reg[16..23]: 96 bits, f0~f7 + * reg[24]: 32 bits, fps + * reg[25]: 32 bits, cpsr + * + * Set 'exist' only to reg[0..15], so initial response to GDB is correct + */ +#define NUM_REGS 26 +#define MAX_REG_SIZE 96 +#define REG_EXIST(n) ((n) < 16) +#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32) + +struct mem_ap_alloc_reg_list { + /* reg_list must be the first field */ + struct reg *reg_list[NUM_REGS]; + struct reg regs[NUM_REGS]; + uint8_t regs_value[MAX_REG_SIZE / 8]; +}; + +static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list)); + if (!mem_ap_alloc) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + *reg_list = mem_ap_alloc->reg_list; + *reg_list_size = NUM_REGS; + struct reg *regs = mem_ap_alloc->regs; + + for (int i = 0; i < NUM_REGS; i++) { + regs[i].number = i; + regs[i].value = mem_ap_alloc->regs_value; + regs[i].size = REG_SIZE(i); + regs[i].exist = REG_EXIST(i); + regs[i].type = &mem_ap_reg_arch_type; + (*reg_list)[i] = ®s[i]; + } + + 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) { @@ -192,6 +276,9 @@ struct target_type mem_ap_target = { .assert_reset = mem_ap_assert_reset, .deassert_reset = mem_ap_deassert_reset, + .get_gdb_arch = mem_ap_get_gdb_arch, + .get_gdb_reg_list = mem_ap_get_gdb_reg_list, + .read_memory = mem_ap_read_memory, .write_memory = mem_ap_write_memory, }; |