From: "vimoon.zheng" <[email protected]>

Implement `msr` and `mrs` commands to write and read AArch64 system registers.
This adds function pointers `msr` and `mrs` to the `armv8_common` struct and 
utilizes DPMv8 instructions to perform the operations, allowing direct 
manipulation of system registers via the debug interface.
---
 src/target/aarch64.c       | 88 ++++++++++++++++++++++++++++++++++++++
 src/target/armv8.h         |  6 +++
 src/target/armv8_dpm.c     | 50 ++++++++++++++++++++++
 src/target/armv8_opcodes.h | 26 +++++++++++
 4 files changed, 170 insertions(+)

diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 032a0da9a..0ed27dd20 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -3204,6 +3204,80 @@ COMMAND_HANDLER(aarch64_mcrmrc_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(aarch64_msrmrs_command)
+{
+       struct target *target;
+       struct armv8_common *armv8;
+       bool is_msr = false;
+       uint arg_cnt = 0;
+       int retval;
+
+       if (!strcmp(CMD_NAME, "msr")) {
+               is_msr = true;
+               arg_cnt = 6;
+       } else {
+               arg_cnt = 5;
+       }
+
+       target = get_current_target(CMD_CTX);
+       if (!target) {
+               command_print(CMD, "no current target");
+               return ERROR_FAIL;
+       }
+       if (!target_was_examined(target)) {
+               command_print(CMD, "%s: not yet examined", target_name(target));
+               return ERROR_TARGET_NOT_EXAMINED;
+       }
+
+       armv8 = target_to_armv8(target);
+       if (!is_armv8(armv8)) {
+               command_print(CMD, "%s: not an ARMv8", target_name(target));
+               return ERROR_FAIL;
+       }
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       if (armv8->arm.core_state != ARM_STATE_AARCH64) {
+               command_print(CMD, "%s: not 64-bit arm target", 
target_name(target));
+               return ERROR_FAIL;
+       }
+
+       if (arg_cnt != CMD_ARGC) {
+               command_print(CMD, "%s: wrong number of arguments", __func__);
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       uint32_t op0;
+       uint32_t op1;
+       uint32_t crn;
+       uint32_t crm;
+       uint32_t op2;
+       uint64_t value;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], op0);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm);
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2);
+       value = 0;
+
+       if (is_msr) {
+               COMMAND_PARSE_NUMBER(u64, CMD_ARGV[5], value);
+               retval = armv8->msr(target, op0, op1, op2, crn, crm, value);
+               if (retval)
+                       return retval;
+       } else {
+               /* NOTE: parameters reordered! */
+               retval = armv8->mrs(target, op0, op1, op2, crn, crm, &value);
+               if (retval)
+                       return retval;
+               command_print(CMD, "0x%" PRIx64, value);
+       }
+
+       return ERROR_OK;
+}
+
 static const struct command_registration aarch64_exec_command_handlers[] = {
        {
                .name = "cache_info",
@@ -3247,6 +3321,20 @@ static const struct command_registration 
aarch64_exec_command_handlers[] = {
                .help = "read coprocessor register",
                .usage = "cpnum op1 CRn CRm op2",
        },
+       {
+               .name = "msr",
+               .mode = COMMAND_EXEC,
+               .handler = aarch64_msrmrs_command,
+               .help = "write sysreg register",
+               .usage = "op0 op1 CRn CRm op2 value",
+       },
+       {
+               .name = "mrs",
+               .mode = COMMAND_EXEC,
+               .handler = aarch64_msrmrs_command,
+               .help = "read sysreg register",
+               .usage = "op0 op1 CRn CRm op2",
+       },
        {
                .chain = smp_command_handlers,
        },
diff --git a/src/target/armv8.h b/src/target/armv8.h
index 5bc1719df..51be31255 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -228,6 +228,12 @@ struct armv8_common {
        int (*post_debug_entry)(struct target *target);
 
        void (*pre_restore_context)(struct target *target);
+
+       /* Read/Write coprocessor register.  */
+       int (*mrs)(struct target *target, uint32_t op0, uint32_t op1,
+                               uint32_t op2, uint32_t crn, uint32_t crm, 
uint64_t *value);
+       int (*msr)(struct target *target, uint32_t op0, uint32_t op1,
+                               uint32_t op2, uint32_t crn, uint32_t crm, 
uint64_t value);
 };
 
 static inline struct armv8_common *
diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c
index 508ec973e..dd7439e90 100644
--- a/src/target/armv8_dpm.c
+++ b/src/target/armv8_dpm.c
@@ -478,6 +478,53 @@ static int dpmv8_bpwp_disable(struct arm_dpm *dpm, 
unsigned int index_t)
  * Coprocessor support
  */
 
+/* Read coprocessor */
+static int dpmv8_mrs(struct target *target, 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;
+       uint32_t opcode;
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       LOG_DEBUG("MRS %d, %d, %d, %d, %d", op0, (int)op1, (int)crn, (int)crm, 
(int)op2);
+
+       opcode = ARMV8_SYSREG(op0, op1, crn, crm, op2);
+       opcode = ARMV8_MRS(opcode, 0);
+       /* read coprocessor register into R0; return via DCC */
+       retval = dpm->instr_read_data_r0_64(dpm, opcode, value);
+
+       /* (void) */ dpm->finish(dpm);
+       return retval;
+}
+
+static int dpmv8_msr(struct target *target, 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;
+       uint32_t opcode;
+
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       LOG_DEBUG("MSR %d, %d, %d, %d, %d", op0, (int)op1, (int)crn, (int)crm, 
(int)op2);
+
+       opcode = ARMV8_SYSREG(op0, op1, crn, crm, op2);
+       opcode = ARMV8_MSR_GP(opcode, 0);
+       /* read DCC into r0; then write coprocessor register from R0 */
+       retval = dpm->instr_write_data_r0_64(dpm, opcode, value);
+
+       /* (void) */ dpm->finish(dpm);
+       return retval;
+}
+
 /* Read coprocessor */
 static int dpmv8_mrc(struct target *target, int cpnum,
        uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm,
@@ -1407,6 +1454,7 @@ void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t 
dscr)
 int armv8_dpm_setup(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
+       struct armv8_common *armv8 = arm->arch_info;
        struct target *target = arm->target;
        struct reg_cache *cache;
        arm->dpm = dpm;
@@ -1425,6 +1473,8 @@ int armv8_dpm_setup(struct arm_dpm *dpm)
        /* coprocessor access setup */
        arm->mrc = dpmv8_mrc;
        arm->mcr = dpmv8_mcr;
+       armv8->mrs = dpmv8_mrs;
+       armv8->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 9f18e94d2..70c66e3a8 100644
--- a/src/target/armv8_opcodes.h
+++ b/src/target/armv8_opcodes.h
@@ -103,6 +103,32 @@
 #define SYSTEM_ESR_EL2                 0xE290
 #define SYSTEM_ESR_EL3                 0xF290
 
+/*
+ * ARMv8 ARM reserves the following encoding for system registers:
+ * (Ref: ARMv8 ARM, Section: "System instruction class encoding overview",
+ *  C5.2, version:ARM DDI 0487A.f)
+ *     [20-19] : Op0
+ *     [18-16] : Op1
+ *     [15-12] : CRn
+ *     [11-8]  : CRm
+ *     [7-5]   : Op2
+ */
+#define OP0_SHIFT 19
+#define OP0_MASK 0x3
+#define OP1_SHIFT 16
+#define OP1_MASK 0x7
+#define CRN_SHIFT 12
+#define CRN_MASK 0xf
+#define CRM_SHIFT 8
+#define CRM_MASK 0xf
+#define OP2_SHIFT 5
+#define OP2_MASK 0x7
+
+#define ARMV8_SYSREG(op0, op1, crn, crm, op2)                                  
                       \
+       ((((op0) << OP0_SHIFT) | ((op1) << OP1_SHIFT) | ((crn) << CRN_SHIFT) | 
((crm) << CRM_SHIFT) | \
+         ((op2) << OP2_SHIFT)) >>                                              
                      \
+        OP2_SHIFT)
+
 #define ARMV8_MRS_DSPSR(rt)    (0xd53b4500 | (rt))
 #define ARMV8_MSR_DSPSR(rt)    (0xd51b4500 | (rt))
 #define ARMV8_MRS_DLR(rt)      (0xd53b4520 | (rt))
-- 
2.52.0


Reply via email to