* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
+ * Copyright (C) 2018 by Liviu Ionescu *
+ * <ilg@livius.net> *
+ * *
* 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 *
#include "armv7m.h"
#include "algorithm.h"
#include "register.h"
+#include "semihosting_common.h"
#if 0
#define _DEBUG_INSTRUCTION_EXECUTION_
static const char * const armv7m_exception_strings[] = {
"", "Reset", "NMI", "HardFault",
- "MemManage", "BusFault", "UsageFault", "RESERVED",
+ "MemManage", "BusFault", "UsageFault", "SecureFault",
"RESERVED", "RESERVED", "RESERVED", "SVCall",
"DebugMonitor", "RESERVED", "PendSV", "SysTick"
};
{ ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
{ ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
{ ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
- { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
+ { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
{ ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
{ ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode);
+ retval = arm->read_core_reg(target, reg, reg->number, arm->core_mode);
return retval;
}
return ERROR_TARGET_NOT_HALTED;
buf_cpy(buf, reg->value, reg->size);
- reg->dirty = 1;
- reg->valid = 1;
+ reg->dirty = true;
+ reg->valid = true;
return ERROR_OK;
}
+static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
+{
+ switch (arm_reg_id) {
+ case ARMV7M_R0 ... ARMV7M_R14:
+ case ARMV7M_PC:
+ case ARMV7M_xPSR:
+ case ARMV7M_MSP:
+ case ARMV7M_PSP:
+ /* NOTE: we "know" here that the register identifiers
+ * match the Cortex-M DCRSR.REGSEL selectors values
+ * for R0..R14, PC, xPSR, MSP, and PSP.
+ */
+ return arm_reg_id;
+
+ case ARMV7M_FPSCR:
+ return ARMV7M_REGSEL_FPSCR;
+
+ case ARMV7M_D0 ... ARMV7M_D15:
+ return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0);
+
+ /* TODO: remove. This is temporary hack until packing/unpacking
+ * of special regs is moved to armv7m.c */
+ case ARMV7M_PRIMASK:
+ case ARMV7M_BASEPRI:
+ case ARMV7M_FAULTMASK:
+ case ARMV7M_CONTROL:
+ return arm_reg_id;
+
+ default:
+ LOG_ERROR("Bad register ID %u", arm_reg_id);
+ return arm_reg_id;
+ }
+}
+
static int armv7m_read_core_reg(struct target *target, struct reg *r,
int num, enum arm_mode mode)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
assert(num < (int)armv7m->arm.core_cache->num_regs);
+ assert(num == (int)r->number);
armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
+ uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num);
+
if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
/* map D0..D15 to S0..S31 */
- size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
- retval = armv7m->load_core_reg_u32(target, regidx, ®_value);
+ retval = armv7m->load_core_reg_u32(target, regsel, ®_value);
if (retval != ERROR_OK)
return retval;
buf_set_u32(armv7m->arm.core_cache->reg_list[num].value,
0, 32, reg_value);
- retval = armv7m->load_core_reg_u32(target, regidx + 1, ®_value);
+ retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value);
if (retval != ERROR_OK)
return retval;
buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4,
0, 32, reg_value);
} else {
retval = armv7m->load_core_reg_u32(target,
- armv7m_core_reg->num, ®_value);
+ regsel, ®_value);
if (retval != ERROR_OK)
return retval;
buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value);
}
- armv7m->arm.core_cache->reg_list[num].valid = 1;
- armv7m->arm.core_cache->reg_list[num].dirty = 0;
+ armv7m->arm.core_cache->reg_list[num].valid = true;
+ armv7m->arm.core_cache->reg_list[num].dirty = false;
return retval;
}
struct armv7m_common *armv7m = target_to_armv7m(target);
assert(num < (int)armv7m->arm.core_cache->num_regs);
+ assert(num == (int)r->number);
armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info;
+ uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num);
+
if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) {
/* map D0..D15 to S0..S31 */
- size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0);
-
uint32_t t = buf_get_u32(value, 0, 32);
- retval = armv7m->store_core_reg_u32(target, regidx, t);
+ retval = armv7m->store_core_reg_u32(target, regsel, t);
if (retval != ERROR_OK)
goto out_error;
t = buf_get_u32(value + 4, 0, 32);
- retval = armv7m->store_core_reg_u32(target, regidx + 1, t);
+ retval = armv7m->store_core_reg_u32(target, regsel + 1, t);
if (retval != ERROR_OK)
goto out_error;
} else {
uint32_t t = buf_get_u32(value, 0, 32);
LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t);
- retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t);
+ retval = armv7m->store_core_reg_u32(target, regsel, t);
if (retval != ERROR_OK)
goto out_error;
}
- armv7m->arm.core_cache->reg_list[num].valid = 1;
- armv7m->arm.core_cache->reg_list[num].dirty = 0;
+ armv7m->arm.core_cache->reg_list[num].valid = true;
+ armv7m->arm.core_cache->reg_list[num].dirty = false;
return ERROR_OK;
int *reg_list_size, enum target_register_class reg_class)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
- int i;
+ int i, size;
if (reg_class == REG_CLASS_ALL)
- *reg_list_size = armv7m->arm.core_cache->num_regs;
+ size = armv7m->arm.core_cache->num_regs;
else
- *reg_list_size = ARMV7M_NUM_CORE_REGS;
+ size = ARMV7M_NUM_CORE_REGS;
- *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+ *reg_list = malloc(sizeof(struct reg *) * size);
if (*reg_list == NULL)
return ERROR_FAIL;
- for (i = 0; i < *reg_list_size; i++)
+ for (i = 0; i < size; i++)
(*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i];
+ *reg_list_size = size;
+
return ERROR_OK;
}
}
for (int i = 0; i < num_mem_params; i++) {
- /* TODO: Write only out params */
+ if (mem_params[i].direction == PARAM_IN)
+ continue;
retval = target_write_buffer(target, mem_params[i].address,
mem_params[i].size,
mem_params[i].value);
}
for (int i = 0; i < num_reg_params; i++) {
+ if (reg_params[i].direction == PARAM_IN)
+ continue;
+
struct reg *reg =
register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
/* uint32_t regvalue; */
armv7m_set_core_reg(reg, reg_params[i].value);
}
+ {
+ /*
+ * Ensure xPSR.T is set to avoid trying to run things in arm
+ * (non-thumb) mode, which armv7m does not support.
+ *
+ * We do this by setting the entirety of xPSR, which should
+ * remove all the unknowns about xPSR state.
+ *
+ * Because xPSR.T is populated on reset from the vector table,
+ * it might be 0 if the vector table has "bad" data in it.
+ */
+ struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
+ buf_set_u32(reg->value, 0, 32, 0x01000000);
+ reg->valid = true;
+ reg->dirty = true;
+ }
+
if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
armv7m_algorithm_info->core_mode != core_mode) {
LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
0, 1, armv7m_algorithm_info->core_mode);
- armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
- armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
+ armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
+ armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
}
/* save previous core mode */
struct armv7m_common *armv7m = target_to_armv7m(target);
struct armv7m_algorithm *armv7m_algorithm_info = arch_info;
int retval = ERROR_OK;
- uint32_t pc;
/* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint
* at the exit point */
return ERROR_TARGET_TIMEOUT;
}
- armv7m->load_core_reg_u32(target, 15, &pc);
- if (exit_point && (pc != exit_point)) {
- LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR,
- pc,
- exit_point);
- return ERROR_TARGET_TIMEOUT;
+ if (exit_point) {
+ /* PC value has been cached in cortex_m_debug_entry() */
+ uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32);
+ if (pc != exit_point) {
+ LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR,
+ pc, exit_point);
+ return ERROR_TARGET_ALGO_EXIT;
+ }
}
/* Read memory values to mem_params[] */
armv7m_algorithm_info->context[i]);
buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
0, 32, armv7m_algorithm_info->context[i]);
- armv7m->arm.core_cache->reg_list[i].valid = 1;
- armv7m->arm.core_cache->reg_list[i].dirty = 1;
+ armv7m->arm.core_cache->reg_list[i].valid = true;
+ armv7m->arm.core_cache->reg_list[i].dirty = true;
}
}
LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode);
buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value,
0, 1, armv7m_algorithm_info->core_mode);
- armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1;
- armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1;
+ armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true;
+ armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = true;
}
armv7m->arm.core_mode = armv7m_algorithm_info->core_mode;
uint32_t ctrl, sp;
/* avoid filling log waiting for fileio reply */
- if (arm->semihosting_hit_fileio)
+ if (target->semihosting && target->semihosting->hit_fileio)
return ERROR_OK;
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
buf_get_u32(arm->pc->value, 0, 32),
(ctrl & 0x02) ? 'p' : 'm',
sp,
- arm->is_semihosting ? ", semihosting" : "",
- arm->is_semihosting_fileio ? " fileio" : "");
+ (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "",
+ (target->semihosting && target->semihosting->is_fileio) ? " fileio" : "");
return ERROR_OK;
}
if (storage_size < 4)
storage_size = 4;
reg_list[i].value = calloc(1, storage_size);
- reg_list[i].dirty = 0;
- reg_list[i].valid = 0;
+ reg_list[i].dirty = false;
+ reg_list[i].valid = false;
reg_list[i].type = &armv7m_reg_type;
reg_list[i].arch_info = &arch_info[i];
/* Enable stimulus port #0 by default */
armv7m->trace_config.itm_ter[0] = 1;
- arm->core_type = ARM_MODE_THREAD;
+ arm->core_type = ARM_CORE_TYPE_M_PROFILE;
arm->arch_info = armv7m;
arm->setup_semihosting = armv7m_setup_semihosting;