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