This is an automated email from Gerrit.

Daniel Goehring (dgoeh...@os.amperecomputing.com) just uploaded a new patch set 
to Gerrit, which you can find at http://openocd.zylin.com/5572

-- gerrit

commit 4b8c1d609316af15c7cde7d26a3fc1f8013af2c6
Author: Kevin Burke <kev...@os.amperecomputing.com>
Date:   Fri Apr 3 20:28:36 2020 -0400

    target|aarch64: Add MSR/MRS TCL/UI support
    
    Aarch64 has a new class of system registers that are accessed
    via the MRS/MSR assembly instructions. This update allows
    the user to read or write these registers regardless of
    exception level.
    
    Tested on an Ampere eMAG8180 and Quicksilver silicon
    
    Change-Id: I99cfc37ac756294fd9779c84e840037529ef304f
    Signed-off-by: Kevin Burke <kev...@os.amperecomputing.com>
    Signed-off-by: Daniel Goehring <dgoeh...@os.amperecomputing.com>

diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 87176f6..527e994 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -1,6 +1,8 @@
 /***************************************************************************
  *   Copyright (C) 2015 by David Ung                                       *
  *                                                                         *
+ *   Copyright (C) 2019-2020, Ampere Computing LLC                         *
+ *                                                                         *
  *   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     *
@@ -2738,6 +2740,140 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, 
Jim_Obj * const *argv)
        return JIM_OK;
 }
 
+COMMAND_HANDLER(aarch64_msr_mrs)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct arm *arm;
+       int retval;
+       bool is_msr;
+       unsigned int arg_cnt;
+       uint32_t op0;
+       uint32_t op1;
+       uint32_t op2;
+       uint32_t CRn;
+       uint32_t CRm;
+       uint64_t value;
+       uint32_t ns_requested = MSRMRS_NOOPTION;
+       int index = 0;
+
+       if (!strcmp(CMD_NAME, "mrs")) {
+               is_msr = false;
+               arg_cnt = 5;
+       } else {
+               is_msr = true;
+               arg_cnt = 6;
+       }
+
+       /* check to see if user is specifying a security preference */
+       if (CMD_ARGC > 0) {
+               if (!strcmp(CMD_ARGV[0], "sec")) {
+                       ns_requested = MSRMRS_SECURE;
+                       arg_cnt++;
+                       index++;
+               } else if (!strcmp(CMD_ARGV[0], "nsec")) {
+                       ns_requested = MSRMRS_NONSECURE;
+                       arg_cnt++;
+                       index++;
+               } else if (!strcmp(CMD_ARGV[0], "asis")) {
+                       ns_requested = MSRMRS_ASIS;
+                       arg_cnt++;
+                       index++;
+               }
+       }
+
+       if (CMD_ARGC != arg_cnt) {
+               LOG_ERROR("%s command failed: wrong number of arguments", 
CMD_NAME);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       if (target == NULL) {
+               LOG_ERROR("%s: target not found", CMD_NAME);
+               return ERROR_FAIL;
+       }
+
+       if (!target_was_examined(target)) {
+               LOG_ERROR("%s: not yet examined", target_name(target));
+               return ERROR_FAIL;
+       }
+
+       arm = target_to_arm(target);
+       if (!is_arm(arm)) {
+               LOG_ERROR("%s: not an ARM", target_name(target));
+               return ERROR_FAIL;
+       }
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("%s: not halted", target_name(target));
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (arm->core_state != ARM_STATE_AARCH64) {
+               LOG_ERROR("%s: not 64-bit arm target", target_name(target));
+               return ERROR_FAIL;
+       }
+
+       /* NOTE:  parameter sequence matches ARM instruction set usage:
+        *      MSR <sec/nsec> op0, op1, rX, CRn, CRm, op2 ; write System Reg 
from rX
+        *      MRS <sec/nsec> op0, op1, rX, CRn, CRm, op2 ; read System Reg 
into rX
+        * The "rX" is necessarily omitted; it uses Tcl mechanisms.
+        */
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], op0);
+       if (op0 & ~0x3) {
+               LOG_ERROR("%s: %s %d out of range", CMD_NAME,
+                       "op0", (int) op0);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], op1);
+       if (op1 & ~0x7) {
+               LOG_ERROR("%s: %s %d out of range", CMD_NAME,
+                       "op1", (int) op1);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], CRn);
+       if (CRn & ~0xf) {
+               LOG_ERROR("%s: %s %d out of range", CMD_NAME,
+                       "CRn", (int) CRn);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], CRm);
+       if (CRm & ~0xf) {
+               LOG_ERROR("%s: %s %d out of range", CMD_NAME,
+                       "CRm", (int) CRm);
+               return ERROR_FAIL;
+       }
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], op2);
+       if (op2 & ~0x7) {
+               LOG_ERROR("%s: %s %d out of range", CMD_NAME,
+                       "op2", (int) op2);
+               return ERROR_FAIL;
+       }
+
+       value = 0;
+
+       if (is_msr == true) {
+               COMMAND_PARSE_NUMBER(u64, CMD_ARGV[index], value);
+               /* NOTE: parameters reordered! */
+               /* ARMV8_MSR(ns, op0, op1, 0, CRn, CRm, op2) */
+               retval = arm->msr(target, ns_requested, op0, op1, op2, CRn, 
CRm, value);
+               if (retval != ERROR_OK)
+                       LOG_ERROR("%s: error encountered writing the designated 
register", CMD_NAME);
+       } else {
+               /* NOTE: parameters reordered! */
+               /* ARMV8_MRS(ns, op0, op1, 0, CRn, CRm, op2) */
+               retval = arm->mrs(target, ns_requested, op0, op1, op2, CRn, 
CRm, &value);
+               if (retval == ERROR_OK)
+                       command_print(CMD, "0x%16.16" PRIx64, value);
+               else
+                       LOG_ERROR("%s: error encountered reading the designated 
register", CMD_NAME);
+       }
+
+       return retval;
+}
+
 static const struct command_registration aarch64_exec_command_handlers[] = {
        {
                .name = "cache_info",
@@ -2775,6 +2911,20 @@ static const struct command_registration 
aarch64_exec_command_handlers[] = {
                .usage = "cpnum op1 CRn CRm op2",
        },
        {
+               .name = "msr",
+               .mode = COMMAND_EXEC,
+               .handler = aarch64_msr_mrs,
+               .help = "write system register",
+               .usage = "['sec' | 'nsec' | ' ' | 'asis'] op0 op1 CRn CRm op2 
value",
+       },
+       {
+               .name = "mrs",
+               .mode = COMMAND_EXEC,
+               .handler = aarch64_msr_mrs,
+               .help = "read system register",
+               .usage = "['sec' | 'nsec' | ' ' | 'asis'] op0 op1 CRn CRm op2",
+       },
+       {
                .chain = smp_command_handlers,
        },
 
diff --git a/src/target/arm.h b/src/target/arm.h
index b399574..7461f88 100644
--- a/src/target/arm.h
+++ b/src/target/arm.h
@@ -11,6 +11,8 @@
  * Copyright (C) 2018 by Liviu Ionescu
  *   <i...@livius.net>
  *
+ * Copyright (C) 2019-2020, Ampere Computing LLC
+ *
  * 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
@@ -234,6 +236,18 @@ struct arm {
                        uint32_t CRn, uint32_t CRm,
                        uint32_t value);
 
+       /** Read system register.  */
+       int (*mrs)(struct target *target, uint32_t ns_requested, uint32_t op0,
+                       uint32_t op1, uint32_t op2,
+                       uint32_t CRn, uint32_t CRm,
+                       uint64_t *value);
+
+       /** Write system register.  */
+       int (*msr)(struct target *target, uint32_t ns_requested, uint32_t op0,
+                       uint32_t op1, uint32_t op2,
+                       uint32_t CRn, uint32_t CRm,
+                       uint64_t value);
+
        void *arch_info;
 
        /** For targets conforming to ARM Debug Interface v5,
diff --git a/src/target/armv8.h b/src/target/armv8.h
index 1a61145..abf8d25 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -1,6 +1,8 @@
 /***************************************************************************
  *   Copyright (C) 2015 by David Ung                                       *
  *                                                                         *
+ *   Copyright (C) 2020, Ampere Computing LLC                              *
+ *                                                                         *
  *   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     *
@@ -199,6 +201,8 @@ struct armv8_common {
        uint32_t debug_base;
        struct adiv5_ap *debug_ap;
 
+       enum arm_mode max_aarch64_el;
+
        const uint32_t *opcodes;
 
        /* mdir */
@@ -246,9 +250,16 @@ static inline bool is_armv8(struct armv8_common *armv8)
        return armv8->common_magic == ARMV8_COMMON_MAGIC;
 }
 
+/* msr/mrs command options */
+#define MSRMRS_SECURE          0
+#define MSRMRS_NONSECURE       1
+#define MSRMRS_ASIS            2
+#define MSRMRS_NOOPTION                3
+
 /* register offsets from armv8.debug_base */
 #define CPUV8_DBG_MAINID0              0xD00
 #define CPUV8_DBG_CPUFEATURE0  0xD20
+#define CPUV8_DBG_PFR          0xD20
 #define CPUV8_DBG_DBGFEATURE0  0xD28
 #define CPUV8_DBG_MEMFEATURE0  0xD38
 
diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c
index 5be5272..a350591 100644
--- a/src/target/armv8_dpm.c
+++ b/src/target/armv8_dpm.c
@@ -1,6 +1,8 @@
 /*
  * Copyright (C) 2009 by David Brownell
  *
+ * Copyright (C) 2019-2020, Ampere Computing LLC
+ *
  * 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
@@ -539,6 +541,220 @@ static int dpmv8_mcr(struct target *target, int cpnum,
        return retval;
 }
 
+/* determine highest Exception Level for this target */
+static int dpmv8_maximum_el(struct arm_dpm *dpm, enum arm_mode *highest_mode)
+{
+       int retval;
+       uint32_t edpfr_lower;
+
+       struct armv8_common *armv8 = (struct armv8_common *) 
dpm->arm->arch_info;
+
+       if (armv8->max_aarch64_el == ARMV8_64_EL0T) {
+               /* read EDPFR register to see what ELs exist in AARCH64 state */
+               retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+                               armv8->debug_base + CPUV8_DBG_PFR,
+                               &edpfr_lower);
+               if (retval != ERROR_OK)
+                       return retval;
+               if ((edpfr_lower >> 12) & 0xf)  /* aarch64 EL3 present */
+                       *highest_mode = ARMV8_64_EL3H;
+               else if ((edpfr_lower >> 8) & 0xf)      /* EL2 present bits */
+                       *highest_mode = ARMV8_64_EL2H;
+               else
+                       *highest_mode = ARMV8_64_EL1H;
+
+               armv8->max_aarch64_el = *highest_mode;
+       } else
+               *highest_mode = armv8->max_aarch64_el;
+
+       return ERROR_OK;
+}
+
+/*
+ * System register support
+ */
+
+/* Read system register */
+static int dpmv8_mrs(struct target *target, uint32_t ns_requested, uint32_t 
op0,
+       uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
+       uint64_t *value)
+{
+       struct arm *arm = target_to_arm(target);
+       struct arm_dpm *dpm = arm->dpm;
+       int retval;
+       enum arm_mode highest_mode;
+       uint32_t target_el, highest_el;
+       uint64_t scr_value;
+
+       target_el = 0;
+       highest_el = target_el;         /* set default to run with current 
excetion level */
+       scr_value = ns_requested;       /* set default not to restore the scr 
register */
+
+       LOG_DEBUG("MRS %d, %d, x0, c%d, c%d, %d", (int) op0,
+               (int) op1, (int) CRn,
+               (int) CRm, (int) op2);
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (ns_requested != MSRMRS_ASIS) {
+               /* user wants to execute the command at the highest exception 
level */
+               retval = dpmv8_maximum_el(dpm, &highest_mode);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to determine highest EL level to use 
on MSR operation");
+                       goto fail;
+               }
+
+               target_el = ((buf_get_u32(dpm->arm->cpsr->value, 0, 32) >> 2) & 
3); /* current el */
+               highest_el = ((uint32_t) highest_mode) >> 2;
+               if (target_el < highest_el) {
+                       retval = armv8_dpm_modeswitch(dpm, highest_mode); /* 
all accesses at highest EL */
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Unable to switch to highest 
exception level on MSR operation");
+                               highest_el = target_el; /* no need to try to 
restore exception level */
+                               goto fail;
+                       }
+               }
+               if (ns_requested != MSRMRS_NOOPTION) {  /* user specified a 
specific security setting */
+                       if (ns_requested == MSRMRS_SECURE && highest_mode != 
ARMV8_64_EL3H) {
+                               LOG_ERROR("MSR %d, %d, x0, c%d, c%d, %d secure 
does not exist",
+                                       (int) op0, (int) op1, (int) CRn,
+                                       (int) CRm, (int) op2);
+                               goto fail;      /* may need to restore 
target_el */
+                       } else if (highest_mode == ARMV8_64_EL3H) {
+                               /* Need to see if EL3's NS bit is set correctly 
*/
+                               /* by reading SCR_EL3 */
+                               retval = dpm->instr_read_data_r0_64(dpm,
+                                       ARMV8_MRS_INSTR(3, 6, 0, 1, 1, 0),
+                                       &scr_value);
+                               if (retval != ERROR_OK) {
+                                       scr_value = ns_requested; /* no need to 
restore ns bit */
+                                       goto fail;
+                               }
+                               if (ns_requested != (scr_value & 0x1)) {
+                                       retval = 
dpm->instr_write_data_r0_64(dpm,
+                                               ARMV8_MSR_INSTR(3, 6, 0, 1, 1, 
0),
+                                               ((scr_value & 
0xFFFFFFFFFFFFFFFE) | ns_requested));
+                                       if (retval != ERROR_OK) {
+                                               scr_value = ns_requested; /* no 
need to restore ns bit */
+                                               goto fail;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* read system register into x0; return via DCC */
+       retval = dpm->instr_read_data_r0_64(dpm,
+                       ARMV8_MRS_INSTR(op0, op1, 0, CRn, CRm, op2), value);
+fail:
+       if (ns_requested != (scr_value & 0x1)) {
+               /* need to restore scr_el3.ns before leaving */
+               retval += dpm->instr_write_data_r0_64(dpm,
+                       ARMV8_MSR_INSTR(3, 6, 0, 1, 1, 0),
+                       scr_value);
+       }
+       if (target_el < highest_el) {
+               /* need to restore exception level */
+               retval += armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); /* return to 
previous access */
+       }
+
+       /* (void) */ dpm->finish(dpm);
+       return retval;
+}
+
+/* Write system register */
+static int dpmv8_msr(struct target *target, uint32_t ns_requested, uint32_t 
op0,
+       uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm,
+       uint64_t value)
+{
+       struct arm *arm = target_to_arm(target);
+       struct arm_dpm *dpm = arm->dpm;
+       int retval;
+       enum arm_mode highest_mode;
+       uint32_t target_el, highest_el;
+       uint64_t scr_value;
+
+       target_el = 0;
+       highest_el = target_el;         /* set default not to restore exception 
level */
+       scr_value = ns_requested;       /* set default not to restore the scr 
register */
+
+       LOG_DEBUG("MSR %d, %d, x0, c%d, c%d, %d", (int) op0,
+               (int) op1, (int) CRn,
+               (int) CRm, (int) op2);
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (ns_requested != MSRMRS_ASIS) {
+               /* user wants to execute the command at the highest exception 
level */
+               retval = dpmv8_maximum_el(dpm, &highest_mode);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Unable to determine highest EL level to use 
on MSR operation");
+                       goto fail;
+               }
+
+               target_el = ((buf_get_u32(dpm->arm->cpsr->value, 0, 32) >> 2) & 
3); /* current el */
+               highest_el = ((uint32_t) highest_mode) >> 2;
+               if (target_el < highest_el) {
+                       retval = armv8_dpm_modeswitch(dpm, highest_mode); /* 
all accesses at highest EL */
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Unable to switch to highest 
exception level on MSR operation");
+                               highest_el = target_el; /* no need to try to 
restore exception level */
+                               goto fail;
+                       }
+               }
+               if (ns_requested != MSRMRS_NOOPTION) {  /* user specified a 
specific security setting */
+                       if (ns_requested == MSRMRS_SECURE && highest_mode != 
ARMV8_64_EL3H) {
+                               LOG_ERROR("MSR %d, %d, x0, c%d, c%d, %d secure 
does not exist",
+                                       (int) op0, (int) op1, (int) CRn,
+                                       (int) CRm, (int) op2);
+                               goto fail;      /* may need to restore 
target_el */
+                       } else if (highest_mode == ARMV8_64_EL3H) {
+                               /* Need to see if EL3's NS bit is set correctly 
*/
+                               /* by reading SCR_EL3 */
+                               retval = dpm->instr_read_data_r0_64(dpm,
+                                       ARMV8_MRS_INSTR(3, 6, 0, 1, 1, 0),
+                                       &scr_value);
+                               if (retval != ERROR_OK) {
+                                       scr_value = ns_requested; /* no need to 
restore ns bit */
+                                       goto fail;
+                               }
+                               if (ns_requested != (scr_value & 0x1)) {
+                                       retval = 
dpm->instr_write_data_r0_64(dpm,
+                                               ARMV8_MSR_INSTR(3, 6, 0, 1, 1, 
0),
+                                               ((scr_value & 
0xFFFFFFFFFFFFFFFE) | ns_requested));
+                                       if (retval != ERROR_OK) {
+                                               scr_value = ns_requested; /* no 
need to restore ns bit */
+                                               goto fail;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* read DCC into x0; then write system register from R0 */
+       retval = dpm->instr_write_data_r0_64(dpm,
+                       ARMV8_MSR_INSTR(op0, op1, 0, CRn, CRm, op2), value);
+
+fail:
+       if (ns_requested != (scr_value & 0x1)) {
+               /* need to restore scr_el3.ns before leaving */
+               retval += dpm->instr_write_data_r0_64(dpm,
+                       ARMV8_MSR_INSTR(3, 6, 0, 1, 1, 0),
+                       scr_value);
+       }
+       if (target_el < highest_el) {
+               /* need to restore exception level */
+               retval += armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); /* return to 
previous access */
+       }
+
+       /* (void) */ dpm->finish(dpm);
+       return retval;
+}
+
 /*----------------------------------------------------------------------*/
 
 /*
@@ -1438,6 +1654,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm)
        arm->mrc = dpmv8_mrc;
        arm->mcr = dpmv8_mcr;
 
+       /* system register setup */
+       arm->mrs = dpmv8_mrs;
+       arm->msr = dpmv8_msr;
+
        dpm->prepare = dpmv8_dpm_prepare;
        dpm->finish = dpmv8_dpm_finish;
 
diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h
index 239c4c5..78426cf 100644
--- a/src/target/armv8_opcodes.h
+++ b/src/target/armv8_opcodes.h
@@ -1,6 +1,9 @@
 /*
  * Copyright (C) 2015 by pierrr kuo
  * vichy....@gmail.com
+ *
+ * Copyright (C) 2019, Ampere Computing LLC
+ *
  * 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
@@ -137,6 +140,30 @@
 #define ARMV8_ISB                              0xd5033fdf
 #define ARMV8_ISB_SY_T1                                0xf3bf8f6f
 
+/* Move to ARM register from system register
+ * op0: first system register opcode
+ * op1: second system register opcode
+ * CRn: first system register operand
+ * CRm: second system register operand
+ * op2: third system register opcode
+ * Rd: destination register
+ */
+#define ARMV8_MRS_INSTR(op0, op1, Rd, CRn, CRm, op2) \
+       (0xd5300000 | (Rd) | ((op2) << 5) | ((CRm) << 8) \
+       | ((CRn) << 12) | ((op1) << 16) | ((op0) << 19))
+
+/* Move to system register from ARM register
+ * op0: first system register opcode
+ * op1: second system register opcode
+ * CRn: first system register operand
+ * CRm: second system register operand
+ * op2: third system register opcode
+ * Rd: destination register
+ */
+#define ARMV8_MSR_INSTR(op0, op1, Rd, CRn, CRm, op2) \
+       (0xd5100000 | (Rd) | ((op2) << 5) | ((CRm) << 8) \
+       | ((CRn) << 12) | ((op1) << 16) | ((op0) << 19))
+
 #define ARMV8_MRS(System, Rt)  (0xd5300000 | ((System) << 5) | (Rt))
 /* ARM V8 Move to system register. */
 #define ARMV8_MSR_GP(System, Rt) \

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to