helper/command: change prototype of command_print/command_print_sameline
[fw/openocd] / src / target / armv8.c
index 82b2b24950d1a068bd0737b68204ad52da36a744..e7369372ab711ed1a95e075818827194bd897f93 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,10 @@ static const struct {
                .name = "ABT",
                .psr = ARM_MODE_ABT,
        },
+       {
+               .name = "SYS",
+               .psr = ARM_MODE_SYS,
+       },
        {
                .name = "EL0T",
                .psr = ARMV8_64_EL0T,
@@ -638,7 +646,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 +678,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 */
@@ -932,6 +940,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 +1013,94 @@ 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 = %02x", 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)
+{
+       struct arm *arm = target_to_arm(target);
+
+       if (arm->core_state != ARM_STATE_AARCH64) {
+               LOG_ERROR("semihosting only supported in AArch64 state\n");
+               return ERROR_FAIL;
+       }
+
        return ERROR_OK;
 }
 
@@ -1018,6 +1109,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;
@@ -1046,7 +1138,7 @@ int armv8_aarch64_state(struct target *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;
 }
@@ -1426,17 +1518,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;
 }
@@ -1455,6 +1547,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) {
@@ -1478,6 +1573,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 {
@@ -1487,11 +1585,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;
 }
@@ -1643,9 +1741,21 @@ void armv8_free_reg_cache(struct target *target)
 }
 
 const struct command_registration armv8_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)
+{
+       return "aarch64";
+}
+
 int armv8_get_gdb_reg_list(struct target *target,
        struct reg **reg_list[], int *reg_list_size,
        enum target_register_class reg_class)