flash/nor/atsame5: add SAME51G18A and SAME51G19A devices
[fw/openocd] / src / target / armv8.c
index e8c700af35d8da9ca166a34f77f5597ae5fffd02..6bf3b110daac3196e30c180957236d3d4bb5aa8d 100644 (file)
@@ -1,6 +1,9 @@
 /***************************************************************************
  *   Copyright (C) 2015 by David Ung                                       *
  *                                                                         *
+ *   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     *
@@ -36,6 +39,7 @@
 #include "armv8_opcodes.h"
 #include "target.h"
 #include "target_type.h"
+#include "semihosting_common.h"
 
 static const char * const armv8_state_strings[] = {
        "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
@@ -69,6 +73,14 @@ static const struct {
                .name = "ABT",
                .psr = ARM_MODE_ABT,
        },
+       {
+               .name = "HYP",
+               .psr = ARM_MODE_HYP,
+       },
+       {
+               .name = "SYS",
+               .psr = ARM_MODE_SYS,
+       },
        {
                .name = "EL0T",
                .psr = ARMV8_64_EL0T,
@@ -638,7 +650,7 @@ int armv8_read_mpidr(struct armv8_common *armv8)
        retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
        if (retval != ERROR_OK)
                goto done;
-       if (mpidr & 1<<31) {
+       if (mpidr & 1U<<31) {
                armv8->multi_processor_system = (mpidr >> 30) & 1;
                armv8->cluster_id = (mpidr >> 8) & 0xf;
                armv8->cpu_id = mpidr & 0x3;
@@ -670,8 +682,8 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr)
         */
        if (arm->cpsr) {
                buf_set_u32(arm->cpsr->value, 0, 32, cpsr);
-               arm->cpsr->valid = 1;
-               arm->cpsr->dirty = 0;
+               arm->cpsr->valid = true;
+               arm->cpsr->dirty = false;
        }
 
        /* Older ARMs won't have the J bit */
@@ -783,7 +795,7 @@ static uint8_t armv8_pa_size(uint32_t ps)
                        ret = 48;
                        break;
                default:
-                       LOG_INFO("Unknow physicall address size");
+                       LOG_INFO("Unknown physical address size");
                        break;
        }
        return ret;
@@ -810,7 +822,7 @@ static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target)
        armv8->armv8_mmu.ttbcr = ttbcr;
 
        /*
-        * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
+        * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
         * document # ARM DDI 0406C
         */
        armv8->armv8_mmu.ttbr_range[0]  = 0xffffffff >> ttbcr_n;
@@ -840,7 +852,7 @@ static __attribute__((unused)) int armv8_read_ttbcr(struct target *target)
        if (retval != ERROR_OK)
                goto done;
 
-       /* claaer ttrr1_used and ttbr0_mask */
+       /* clear ttrr1_used and ttbr0_mask */
        memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used));
        memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask));
 
@@ -890,7 +902,7 @@ static __attribute__((unused)) int armv8_read_ttbcr(struct target *target)
                        goto done;
                break;
        default:
-               LOG_ERROR("unknow core state");
+               LOG_ERROR("unknown core state");
                retval = ERROR_FAIL;
                break;
        }
@@ -932,6 +944,11 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va,
                        "Secure", "Not Secure"
        };
 
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target %s not halted", target_name(target));
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
                return retval;
@@ -1000,16 +1017,87 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va,
        return retval;
 }
 
-int armv8_handle_cache_info_command(struct command_context *cmd_ctx,
+COMMAND_HANDLER(armv8_handle_exception_catch_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct armv8_common *armv8 = target_to_armv8(target);
+       uint32_t edeccr = 0;
+       unsigned int argp = 0;
+       int retval;
+
+       static const Jim_Nvp nvp_ecatch_modes[] = {
+               { .name = "off",       .value = 0 },
+               { .name = "nsec_el1",  .value = (1 << 5) },
+               { .name = "nsec_el2",  .value = (2 << 5) },
+               { .name = "nsec_el12", .value = (3 << 5) },
+               { .name = "sec_el1",   .value = (1 << 1) },
+               { .name = "sec_el3",   .value = (4 << 1) },
+               { .name = "sec_el13",  .value = (5 << 1) },
+               { .name = NULL, .value = -1 },
+       };
+       const Jim_Nvp *n;
+
+       if (CMD_ARGC == 0) {
+               const char *sec = NULL, *nsec = NULL;
+
+               retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+                                       armv8->debug_base + CPUV8_DBG_ECCR, &edeccr);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               n = Jim_Nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0x0f);
+               if (n->name != NULL)
+                       sec = n->name;
+
+               n = Jim_Nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0xf0);
+               if (n->name != NULL)
+                       nsec = n->name;
+
+               if (sec == NULL || nsec == NULL) {
+                       LOG_WARNING("Exception Catch: unknown exception catch configuration: EDECCR = %02" PRIx32, edeccr & 0xff);
+                       return ERROR_FAIL;
+               }
+
+               command_print(CMD, "Exception Catch: Secure: %s, Non-Secure: %s", sec, nsec);
+               return ERROR_OK;
+       }
+
+       while (CMD_ARGC > argp) {
+               n = Jim_Nvp_name2value_simple(nvp_ecatch_modes, CMD_ARGV[argp]);
+               if (n->name == NULL) {
+                       LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]);
+                       return ERROR_FAIL;
+               }
+
+               LOG_DEBUG("found: %s", n->name);
+
+               edeccr |= n->value;
+               argp++;
+       }
+
+       retval = mem_ap_write_atomic_u32(armv8->debug_ap,
+                               armv8->debug_base + CPUV8_DBG_ECCR, edeccr);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+int armv8_handle_cache_info_command(struct command_invocation *cmd,
        struct armv8_cache_common *armv8_cache)
 {
        if (armv8_cache->info == -1) {
-               command_print(cmd_ctx, "cache not yet identified");
+               command_print(cmd, "cache not yet identified");
                return ERROR_OK;
        }
 
        if (armv8_cache->display_cache_info)
-               armv8_cache->display_cache_info(cmd_ctx, armv8_cache);
+               armv8_cache->display_cache_info(cmd, armv8_cache);
+       return ERROR_OK;
+}
+
+static int armv8_setup_semihosting(struct target *target, int enable)
+{
        return ERROR_OK;
 }
 
@@ -1018,6 +1106,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
        struct arm *arm = &armv8->arm;
        arm->arch_info = armv8;
        target->arch_info = &armv8->arm;
+       arm->setup_semihosting = armv8_setup_semihosting;
        /*  target is useful in all function arm v4 5 compatible */
        armv8->arm.target = target;
        armv8->arm.common_magic = ARM_COMMON_MAGIC;
@@ -1030,7 +1119,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8)
        return ERROR_OK;
 }
 
-int armv8_aarch64_state(struct target *target)
+static int armv8_aarch64_state(struct target *target)
 {
        struct arm *arm = target_to_arm(target);
 
@@ -1039,14 +1128,15 @@ int armv8_aarch64_state(struct target *target)
                return ERROR_FAIL;
        }
 
-       LOG_USER("target halted in %s state due to %s, current mode: %s\n"
+       LOG_USER("%s halted in %s state due to %s, current mode: %s\n"
                "cpsr: 0x%8.8" PRIx32 " pc: 0x%" PRIx64 "%s",
+               target_name(target),
                armv8_state_strings[arm->core_state],
                debug_reason_name(target),
                armv8_mode_name(arm->core_mode),
                buf_get_u32(arm->cpsr->value, 0, 32),
                buf_get_u64(arm->pc->value, 0, 64),
-               arm->is_semihosting ? ", semihosting" : "");
+               (target->semihosting && target->semihosting->is_active) ? ", semihosting" : "");
 
        return ERROR_OK;
 }
@@ -1186,7 +1276,49 @@ static struct reg_data_type_union aarch64v_union[] = {
 };
 
 static struct reg_data_type aarch64v[] = {
-       {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64v_union} },
+       {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION,
+               {.reg_type_union = aarch64v_union} },
+};
+
+static struct reg_data_type_bitfield aarch64_cpsr_bits[] = {
+       {  0,  0, REG_TYPE_UINT8 },
+       {  2,  3, REG_TYPE_UINT8 },
+       {  4,  4, REG_TYPE_UINT8 },
+       {  6,  6, REG_TYPE_BOOL },
+       {  7,  7, REG_TYPE_BOOL },
+       {  8,  8, REG_TYPE_BOOL },
+       {  9,  9, REG_TYPE_BOOL },
+       { 20, 20, REG_TYPE_BOOL },
+       { 21, 21, REG_TYPE_BOOL },
+       { 28, 28, REG_TYPE_BOOL },
+       { 29, 29, REG_TYPE_BOOL },
+       { 30, 30, REG_TYPE_BOOL },
+       { 31, 31, REG_TYPE_BOOL },
+};
+
+static struct reg_data_type_flags_field aarch64_cpsr_fields[] = {
+       { "SP",  aarch64_cpsr_bits + 0,  aarch64_cpsr_fields + 1 },
+       { "EL",  aarch64_cpsr_bits + 1,  aarch64_cpsr_fields + 2 },
+       { "nRW", aarch64_cpsr_bits + 2,  aarch64_cpsr_fields + 3 },
+       { "F",   aarch64_cpsr_bits + 3,  aarch64_cpsr_fields + 4 },
+       { "I",   aarch64_cpsr_bits + 4,  aarch64_cpsr_fields + 5 },
+       { "A",   aarch64_cpsr_bits + 5,  aarch64_cpsr_fields + 6 },
+       { "D",   aarch64_cpsr_bits + 6,  aarch64_cpsr_fields + 7 },
+       { "IL",  aarch64_cpsr_bits + 7,  aarch64_cpsr_fields + 8 },
+       { "SS",  aarch64_cpsr_bits + 8,  aarch64_cpsr_fields + 9 },
+       { "V",   aarch64_cpsr_bits + 9,  aarch64_cpsr_fields + 10 },
+       { "C",   aarch64_cpsr_bits + 10, aarch64_cpsr_fields + 11 },
+       { "Z",   aarch64_cpsr_bits + 11, aarch64_cpsr_fields + 12 },
+       { "N",   aarch64_cpsr_bits + 12, NULL }
+};
+
+static struct reg_data_type_flags aarch64_cpsr_flags[] = {
+       { 4, aarch64_cpsr_fields }
+};
+
+static struct reg_data_type aarch64_flags_cpsr[] = {
+       {REG_TYPE_ARCH_DEFINED, "cpsr_flags", REG_TYPE_CLASS_FLAGS,
+               {.reg_type_flags = aarch64_cpsr_flags} },
 };
 
 static const struct {
@@ -1233,9 +1365,8 @@ static const struct {
 
        { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL},
        { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL},
-
-       { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core", NULL},
-
+       { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED,
+               "general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr},
        { ARMV8_V0,  "v0",  128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
        { ARMV8_V1,  "v1",  128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
        { ARMV8_V2,  "v2",  128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v},
@@ -1385,17 +1516,17 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf)
                        armv8_set_cpsr(arm, (uint32_t)value);
                else {
                        buf_set_u64(reg->value, 0, reg->size, value);
-                       reg->valid = 1;
+                       reg->valid = true;
                }
        } else if (reg->size <= 128) {
                uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64);
 
                buf_set_u64(reg->value, 0, 64, value);
                buf_set_u64(reg->value + 8, 0, reg->size - 64, hvalue);
-               reg->valid = 1;
+               reg->valid = true;
        }
 
-       reg->dirty = 1;
+       reg->dirty = true;
 
        return ERROR_OK;
 }
@@ -1414,6 +1545,9 @@ static int armv8_get_core_reg32(struct reg *reg)
        struct reg *reg64;
        int retval;
 
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
        /* get the corresponding Aarch64 register */
        reg64 = cache->reg_list + armv8_reg->num;
        if (reg64->valid) {
@@ -1437,6 +1571,9 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
        struct reg *reg64 = cache->reg_list + armv8_reg->num;
        uint32_t value = buf_get_u32(buf, 0, 32);
 
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
        if (reg64 == arm->cpsr) {
                armv8_set_cpsr(arm, value);
        } else {
@@ -1446,11 +1583,11 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
                        uint64_t value64 = buf_get_u64(buf, 0, 64);
                        buf_set_u64(reg->value, 0, 64, value64);
                }
-               reg->valid = 1;
-               reg64->valid = 1;
+               reg->valid = true;
+               reg64->valid = true;
        }
 
-       reg64->dirty = 1;
+       reg64->dirty = true;
 
        return ERROR_OK;
 }
@@ -1506,15 +1643,14 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
                } else
                        LOG_ERROR("unable to allocate feature list");
 
-               if (armv8_regs[i].data_type == NULL) {
-                       reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
-                       if (reg_list[i].reg_data_type)
+               reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
+               if (reg_list[i].reg_data_type) {
+                       if (armv8_regs[i].data_type == NULL)
                                reg_list[i].reg_data_type->type = armv8_regs[i].type;
                        else
-                               LOG_ERROR("unable to allocate reg type list");
+                               *reg_list[i].reg_data_type = *armv8_regs[i].data_type;
                } else
-                       reg_list[i].reg_data_type =     armv8_regs[i].data_type;
-
+                       LOG_ERROR("unable to allocate reg type list");
        }
 
        arm->cpsr = reg_list + ARMV8_xPSR;
@@ -1567,13 +1703,57 @@ struct reg *armv8_reg_current(struct arm *arm, unsigned regnum)
        return r;
 }
 
+static void armv8_free_cache(struct reg_cache *cache, bool regs32)
+{
+       struct reg *reg;
+       unsigned int i;
+
+       if (!cache)
+               return;
+
+       for (i = 0; i < cache->num_regs; i++) {
+               reg = &cache->reg_list[i];
+
+               free(reg->feature);
+               free(reg->reg_data_type);
+       }
+
+       if (!regs32)
+               free(cache->reg_list[0].arch_info);
+       free(cache->reg_list);
+       free(cache);
+}
+
+void armv8_free_reg_cache(struct target *target)
+{
+       struct armv8_common *armv8 = target_to_armv8(target);
+       struct arm *arm = &armv8->arm;
+       struct reg_cache *cache = NULL, *cache32 = NULL;
+
+       cache = arm->core_cache;
+       if (cache != NULL)
+               cache32 = cache->next;
+       armv8_free_cache(cache32, true);
+       armv8_free_cache(cache, false);
+       arm->core_cache = NULL;
+}
+
 const struct command_registration armv8_command_handlers[] = {
        {
-               .chain = dap_command_handlers,
+               .name = "catch_exc",
+               .handler = armv8_handle_exception_catch_command,
+               .mode = COMMAND_EXEC,
+               .help = "configure exception catch",
+               .usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]",
        },
        COMMAND_REGISTRATION_DONE
 };
 
+const char *armv8_get_gdb_arch(struct target *target)
+{
+       struct arm *arm = target_to_arm(target);
+       return arm->core_state == ARM_STATE_AARCH64 ? "aarch64" : "arm";
+}
 
 int armv8_get_gdb_reg_list(struct target *target,
        struct reg **reg_list[], int *reg_list_size,