#include "target.h"
#include "target_type.h"
-#define __unused __attribute__((unused))
-
static const char * const armv8_state_strings[] = {
"AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
};
static const struct {
const char *name;
unsigned psr;
- /* For user and system modes, these list indices for all registers.
- * otherwise they're just indices for the shadow registers and SPSR.
- */
- unsigned short n_indices;
- const uint8_t *indices;
} armv8_mode_data[] = {
- /* These special modes are currently only supported
- * by ARMv6M and ARMv7M profiles */
{
.name = "USR",
.psr = ARM_MODE_USR,
return "UNRECOGNIZED";
}
-int armv8_mode_to_number(enum arm_mode mode)
-{
- switch (mode) {
- case ARM_MODE_ANY:
- /* map MODE_ANY to user mode */
- case ARM_MODE_USR:
- return 0;
- case ARM_MODE_FIQ:
- return 1;
- case ARM_MODE_IRQ:
- return 2;
- case ARM_MODE_SVC:
- return 3;
- case ARM_MODE_ABT:
- return 4;
- case ARM_MODE_UND:
- return 5;
- case ARM_MODE_SYS:
- return 6;
- case ARM_MODE_MON:
- return 7;
- case ARMV8_64_EL0T:
- return 8;
- case ARMV8_64_EL1T:
- return 9;
- case ARMV8_64_EL1H:
- return 10;
- case ARMV8_64_EL2T:
- return 11;
- case ARMV8_64_EL2H:
- return 12;
- case ARMV8_64_EL3T:
- return 13;
- case ARMV8_64_EL3H:
- return 14;
-
- default:
- LOG_ERROR("invalid mode value encountered %d", mode);
- return -1;
- }
-}
-
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
{
struct arm_dpm *dpm = &armv8->dpm;
break;
case ARMV8_SP:
retval = dpm->instr_write_data_dcc(dpm,
- ARMV4_5_MRC(14, 0, 13, 0, 5, 0),
- value);
+ ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value);
break;
case ARMV8_PC:/* PC
* read r0 from DCC; then "MOV pc, r0" */
LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target),
armv8->cluster_id,
armv8->cpu_id,
- armv8->multi_processor_system == 0 ? "multi core" : "mono core");
-
+ armv8->multi_processor_system == 0 ? "multi core" : "single core");
} else
- LOG_ERROR("mpdir not in multiprocessor format");
+ LOG_ERROR("mpidr not in multiprocessor format");
done:
dpm->finish(dpm);
/* Older ARMs won't have the J bit */
enum arm_state state = 0xFF;
- if (((cpsr & 0x10) >> 4) == 0) {
- state = ARM_STATE_AARCH64;
- } else {
+ if ((cpsr & 0x10) != 0) {
+ /* Aarch32 state */
if (cpsr & (1 << 5)) { /* T */
if (cpsr & (1 << 24)) { /* J */
LOG_WARNING("ThumbEE -- incomplete support");
} else
state = ARM_STATE_ARM;
}
+ } else {
+ /* Aarch64 state */
+ state = ARM_STATE_AARCH64;
}
+
arm->core_state = state;
- if (arm->core_state == ARM_STATE_AARCH64)
- arm->core_mode = (mode << 4) | 0xf;
- else
- arm->core_mode = mode;
+ arm->core_mode = mode;
LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr,
armv8_mode_name(arm->core_mode),
/* (void) */ dpm->finish(dpm);
}
-static void armv8_show_fault_registers(struct target *target)
+static __attribute__((unused)) void armv8_show_fault_registers(struct target *target)
{
struct armv8_common *armv8 = target_to_armv8(target);
return ret;
}
-static __unused int armv8_read_ttbcr32(struct target *target)
+static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = armv8->arm.dpm;
return retval;
}
-static __unused int armv8_read_ttbcr(struct target *target)
+static __attribute__((unused)) int armv8_read_ttbcr(struct target *target)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm_dpm *dpm = armv8->arm.dpm;
armv8->page_size = (ttbcr >> 14) & 3;
break;
case SYSTEM_CUREL_EL0:
+ armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
+ /* fall through */
case SYSTEM_CUREL_EL1:
retval = dpm->instr_read_data_r0_64(dpm,
ARMV8_MRS(SYSTEM_TCR_EL1, 0),
LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask));
done:
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
dpm->finish(dpm);
return retval;
}
struct armv8_common *armv8 = target_to_armv8(target);
struct arm *arm = target_to_arm(target);
struct arm_dpm *dpm = &armv8->dpm;
+ enum arm_mode target_mode = ARM_MODE_ANY;
uint32_t retval;
uint32_t instr = 0;
uint64_t par;
case SYSTEM_CUREL_EL0:
instr = ARMV8_SYS(SYSTEM_ATS12E0R, 0);
/* can only execute instruction at EL2 */
- dpmv8_modeswitch(dpm, ARMV8_64_EL2T);
+ target_mode = ARMV8_64_EL2H;
break;
case SYSTEM_CUREL_EL1:
instr = ARMV8_SYS(SYSTEM_ATS12E1R, 0);
/* can only execute instruction at EL2 */
- dpmv8_modeswitch(dpm, ARMV8_64_EL2T);
+ target_mode = ARMV8_64_EL2H;
break;
case SYSTEM_CUREL_EL2:
instr = ARMV8_SYS(SYSTEM_ATS1E2R, 0);
break;
};
+ if (target_mode != ARM_MODE_ANY)
+ armv8_dpm_modeswitch(dpm, target_mode);
+
/* write VA to R0 and execute translation instruction */
retval = dpm->instr_write_data_r0_64(dpm, instr, (uint64_t)va);
/* read result from PAR_EL1 */
if (retval == ERROR_OK)
retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_PAR_EL1, 0), &par);
- dpm->finish(dpm);
-
/* switch back to saved PE mode */
- dpmv8_modeswitch(dpm, ARM_MODE_ANY);
+ if (target_mode != ARM_MODE_ANY)
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
+
+ dpm->finish(dpm);
if (retval != ERROR_OK)
return retval;
{ ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" },
};
-#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs)
+static const struct {
+ unsigned id;
+ const char *name;
+ unsigned bits;
+ enum arm_mode mode;
+ enum reg_type type;
+ const char *group;
+ const char *feature;
+} armv8_regs32[] = {
+ { ARMV8_R0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R1, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R2, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R3, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R4, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R5, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R6, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R7, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R8, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R9, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R10, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R11, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R12, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R13, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_R14, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_PC, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" },
+ { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" },
+};
+#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs)
+#define ARMV8_NUM_REGS32 ARRAY_SIZE(armv8_regs32)
static int armv8_get_core_reg(struct reg *reg)
{
- int retval;
struct arm_reg *armv8_reg = reg->arch_info;
struct target *target = armv8_reg->target;
struct arm *arm = target_to_arm(target);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- retval = arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode);
-
- return retval;
+ return arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode);
}
static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
.set = armv8_set_core_reg,
};
+static int armv8_get_core_reg32(struct reg *reg)
+{
+ struct arm_reg *armv8_reg = reg->arch_info;
+ struct target *target = armv8_reg->target;
+ struct arm *arm = target_to_arm(target);
+ struct reg_cache *cache = arm->core_cache;
+ struct reg *reg64;
+ int retval;
+
+ /* get the corresponding Aarch64 register */
+ reg64 = cache->reg_list + armv8_reg->num;
+ if (reg64->valid) {
+ reg->valid = true;
+ return ERROR_OK;
+ }
+
+ retval = arm->read_core_reg(target, reg64, armv8_reg->num, arm->core_mode);
+ if (retval == ERROR_OK)
+ reg->valid = reg64->valid;
+
+ return retval;
+}
+
+static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
+{
+ struct arm_reg *armv8_reg = reg->arch_info;
+ struct target *target = armv8_reg->target;
+ struct arm *arm = target_to_arm(target);
+ struct reg_cache *cache = arm->core_cache;
+ struct reg *reg64 = cache->reg_list + armv8_reg->num;
+ uint32_t value = buf_get_u32(buf, 0, 32);
+
+ if (reg64 == arm->cpsr) {
+ armv8_set_cpsr(arm, value);
+ } else {
+ buf_set_u32(reg->value, 0, 32, value);
+ reg->valid = 1;
+ reg64->valid = 1;
+ }
+
+ reg64->dirty = 1;
+
+ return ERROR_OK;
+}
+
+static const struct reg_arch_type armv8_reg32_type = {
+ .get = armv8_get_core_reg32,
+ .set = armv8_set_core_reg32,
+};
+
/** Builds cache of architecturally defined registers. */
struct reg_cache *armv8_build_reg_cache(struct target *target)
{
struct armv8_common *armv8 = target_to_armv8(target);
struct arm *arm = &armv8->arm;
int num_regs = ARMV8_NUM_REGS;
+ int num_regs32 = ARMV8_NUM_REGS32;
struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
struct reg_cache *cache = malloc(sizeof(struct reg_cache));
+ struct reg_cache *cache32 = malloc(sizeof(struct reg_cache));
struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
+ struct reg *reg_list32 = calloc(num_regs32, sizeof(struct reg));
struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg));
struct reg_feature *feature;
int i;
/* Build the process context cache */
- cache->name = "arm v8 registers";
- cache->next = NULL;
+ cache->name = "Aarch64 registers";
+ cache->next = cache32;
cache->reg_list = reg_list;
cache->num_regs = num_regs;
- (*cache_p) = cache;
for (i = 0; i < num_regs; i++) {
arch_info[i].num = armv8_regs[i].id;
reg_list[i].name = armv8_regs[i].name;
reg_list[i].size = armv8_regs[i].bits;
- reg_list[i].value = calloc(1, 8);
- reg_list[i].dirty = 0;
- reg_list[i].valid = 0;
+ reg_list[i].value = &arch_info[i].value[0];
reg_list[i].type = &armv8_reg_type;
reg_list[i].arch_info = &arch_info[i];
arm->pc = reg_list + ARMV8_PC;
arm->core_cache = cache;
+ /* shadow cache for ARM mode registers */
+ cache32->name = "Aarch32 registers";
+ cache32->next = NULL;
+ cache32->reg_list = reg_list32;
+ cache32->num_regs = num_regs32;
+
+ for (i = 0; i < num_regs32; i++) {
+ reg_list32[i].name = armv8_regs32[i].name;
+ reg_list32[i].size = armv8_regs32[i].bits;
+ reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[0];
+ reg_list32[i].type = &armv8_reg32_type;
+ reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id];
+ reg_list32[i].group = armv8_regs32[i].group;
+ reg_list32[i].number = i;
+ reg_list32[i].exist = true;
+ reg_list32[i].caller_save = true;
+
+ feature = calloc(1, sizeof(struct reg_feature));
+ if (feature) {
+ feature->name = armv8_regs32[i].feature;
+ reg_list32[i].feature = feature;
+ } else
+ LOG_ERROR("unable to allocate feature list");
+
+ reg_list32[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
+ if (reg_list32[i].reg_data_type)
+ reg_list32[i].reg_data_type->type = armv8_regs32[i].type;
+ else
+ LOG_ERROR("unable to allocate reg type list");
+ }
+
+ (*cache_p) = cache;
return cache;
}
struct arm *arm = target_to_arm(target);
int i;
- switch (reg_class) {
- case REG_CLASS_GENERAL:
- *reg_list_size = ARMV8_ELR_EL1;
- *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+ if (arm->core_state == ARM_STATE_AARCH64) {
- for (i = 0; i < *reg_list_size; i++)
- (*reg_list)[i] = armv8_reg_current(arm, i);
+ LOG_DEBUG("Creating Aarch64 register list for target %s", target_name(target));
- return ERROR_OK;
- case REG_CLASS_ALL:
- *reg_list_size = ARMV8_LAST_REG;
- *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+ switch (reg_class) {
+ case REG_CLASS_GENERAL:
+ *reg_list_size = ARMV8_ELR_EL1;
+ *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
- for (i = 0; i < *reg_list_size; i++)
- (*reg_list)[i] = armv8_reg_current(arm, i);
+ for (i = 0; i < *reg_list_size; i++)
+ (*reg_list)[i] = armv8_reg_current(arm, i);
+ return ERROR_OK;
- return ERROR_OK;
+ case REG_CLASS_ALL:
+ *reg_list_size = ARMV8_LAST_REG;
+ *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
- default:
- LOG_ERROR("not a valid register class type in query.");
- return ERROR_FAIL;
- break;
+ for (i = 0; i < *reg_list_size; i++)
+ (*reg_list)[i] = armv8_reg_current(arm, i);
+
+ return ERROR_OK;
+
+ default:
+ LOG_ERROR("not a valid register class type in query.");
+ return ERROR_FAIL;
+ }
+ } else {
+ struct reg_cache *cache32 = arm->core_cache->next;
+
+ LOG_DEBUG("Creating Aarch32 register list for target %s", target_name(target));
+
+ switch (reg_class) {
+ case REG_CLASS_GENERAL:
+ case REG_CLASS_ALL:
+ *reg_list_size = cache32->num_regs;
+ *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+
+ for (i = 0; i < *reg_list_size; i++)
+ (*reg_list)[i] = cache32->reg_list + i;
+
+ return ERROR_OK;
+ default:
+ LOG_ERROR("not a valid register class type in query.");
+ return ERROR_FAIL;
+ }
}
}
+
+int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value)
+{
+ uint32_t tmp;
+
+ /* Read register */
+ int retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + reg, &tmp);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* clear bitfield */
+ tmp &= ~mask;
+ /* put new value */
+ tmp |= value & mask;
+
+ /* write new value */
+ retval = mem_ap_write_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + reg, tmp);
+ return retval;
+}