arm_opcode: Add support for ARM MCRR/MRRC

Add support for the ARM MCRR/MRRC instructions which require the use of
two registers to transfer a 64-bit co-processor registers. We are going
to use this in a subsequent patch in order to properly dump 64-bit page
table descriptors that exist on ARMv7A with VMSA extensions.

We make use of r0 and r1 to transfer 64-bit quantities to/from DCC.

Change-Id: Ic4975026c1ae4f2853795575ac7701d541248736
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Michael Chalfant <michael.chalfant@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/5228
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
Florian Fainelli
2019-03-18 16:00:07 -07:00
committed by Antonio Borneo
parent 1bc4182ceb
commit d27a3a00b8
6 changed files with 262 additions and 0 deletions
+122
View File
@@ -1093,6 +1093,94 @@ COMMAND_HANDLER(handle_armv4_5_mcrmrc)
return ERROR_OK;
}
COMMAND_HANDLER(handle_armv4_5_mcrrmrrc)
{
bool is_mcrr = false;
unsigned int arg_cnt = 3;
if (!strcmp(CMD_NAME, "mcrr")) {
is_mcrr = true;
arg_cnt = 4;
}
if (arg_cnt != CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
struct target *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;
}
struct arm *arm = target_to_arm(target);
if (!is_arm(arm)) {
command_print(CMD, "%s: not an ARM", target_name(target));
return ERROR_FAIL;
}
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
int cpnum;
uint32_t op1;
uint32_t crm;
uint64_t value;
/* NOTE: parameter sequence matches ARM instruction set usage:
* MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2
* MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2
* The "rXn" are necessarily omitted; they use Tcl mechanisms.
*/
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum);
if (cpnum & ~0xf) {
command_print(CMD, "coprocessor %d out of range", cpnum);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1);
if (op1 & ~0xf) {
command_print(CMD, "op1 %d out of range", op1);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm);
if (crm & ~0xf) {
command_print(CMD, "CRm %d out of range", crm);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
/*
* FIXME change the call syntax here ... simplest to just pass
* the MRC() or MCR() instruction to be executed. That will also
* let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit)
* if that's ever needed.
*/
if (is_mcrr) {
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value);
/* NOTE: parameters reordered! */
/* ARMV5_T_MCRR(cpnum, op1, crm) */
int retval = arm->mcrr(target, cpnum, op1, crm, value);
if (retval != ERROR_OK)
return retval;
} else {
value = 0;
/* NOTE: parameters reordered! */
/* ARMV5_T_MRRC(cpnum, op1, crm) */
int retval = arm->mrrc(target, cpnum, op1, crm, &value);
if (retval != ERROR_OK)
return retval;
command_print(CMD, "0x%" PRIx64, value);
}
return ERROR_OK;
}
static const struct command_registration arm_exec_command_handlers[] = {
{
.name = "reg",
@@ -1115,6 +1203,20 @@ static const struct command_registration arm_exec_command_handlers[] = {
.help = "read coprocessor register",
.usage = "cpnum op1 CRn CRm op2",
},
{
.name = "mcrr",
.mode = COMMAND_EXEC,
.handler = handle_armv4_5_mcrrmrrc,
.help = "write coprocessor 64-bit register",
.usage = "cpnum op1 CRm value",
},
{
.name = "mrrc",
.mode = COMMAND_EXEC,
.handler = handle_armv4_5_mcrrmrrc,
.help = "read coprocessor 64-bit register",
.usage = "cpnum op1 CRm",
},
{
.chain = arm_all_profiles_command_handlers,
},
@@ -1669,6 +1771,14 @@ static int arm_default_mrc(struct target *target, int cpnum,
return ERROR_FAIL;
}
static int arm_default_mrrc(struct target *target, int cpnum,
uint32_t op, uint32_t crm,
uint64_t *value)
{
LOG_ERROR("%s doesn't implement MRRC", target_type_name(target));
return ERROR_FAIL;
}
static int arm_default_mcr(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t crn, uint32_t crm,
@@ -1678,6 +1788,14 @@ static int arm_default_mcr(struct target *target, int cpnum,
return ERROR_FAIL;
}
static int arm_default_mcrr(struct target *target, int cpnum,
uint32_t op, uint32_t crm,
uint64_t value)
{
LOG_ERROR("%s doesn't implement MCRR", target_type_name(target));
return ERROR_FAIL;
}
int arm_init_arch_info(struct target *target, struct arm *arm)
{
target->arch_info = arm;
@@ -1697,8 +1815,12 @@ int arm_init_arch_info(struct target *target, struct arm *arm)
if (!arm->mrc)
arm->mrc = arm_default_mrc;
if (!arm->mrrc)
arm->mrrc = arm_default_mrrc;
if (!arm->mcr)
arm->mcr = arm_default_mcr;
if (!arm->mcrr)
arm->mcrr = arm_default_mcrr;
return ERROR_OK;
}