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:
committed by
Antonio Borneo
parent
1bc4182ceb
commit
d27a3a00b8
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user