mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-25 21:06:54 +00:00
target-arm: add CPREG secure state support
Prepare ARMCPRegInfo to support specifying two fieldoffsets per register definition. This will allow us to keep one register definition for banked registers (different offsets for secure/ non-secure world). Also added secure state tracking field and flags. This allows for identification of the register info secure state. Backports commit c3e302606253a17568dc3ef30238f102468f7ee1 from qemu
This commit is contained in:
parent
acdd665668
commit
4f5106b56d
|
@ -654,9 +654,9 @@ static void arm_v7m_class_init(struct uc_struct *uc, ObjectClass *oc, void *data
|
||||||
|
|
||||||
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
|
||||||
{ "L2LOCKDOWN", 15,9,0, 0,1,0, 0,
|
{ "L2LOCKDOWN", 15,9,0, 0,1,0, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
{ "L2AUXCR", 15,9,0, 0,1,2, 0,
|
{ "L2AUXCR", 15,9,0, 0,1,2, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -703,24 +703,24 @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
|
||||||
* default to 0 and set by private hook
|
* default to 0 and set by private hook
|
||||||
*/
|
*/
|
||||||
{ "A9_PWRCTL", 15,15,0, 0,0,0, 0,
|
{ "A9_PWRCTL", 15,15,0, 0,0,0, 0,
|
||||||
0, PL1_RW, NULL, 0, offsetof(CPUARMState, cp15.c15_power_control) },
|
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_power_control) },
|
||||||
{ "A9_DIAG", 15,15,0, 0,0,1, 0,
|
{ "A9_DIAG", 15,15,0, 0,0,1, 0,
|
||||||
0, PL1_RW, NULL, 0, offsetof(CPUARMState, cp15.c15_diagnostic) },
|
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_diagnostic) },
|
||||||
{ "A9_PWRDIAG",15,15,0, 0,0,2, 0,
|
{ "A9_PWRDIAG",15,15,0, 0,0,2, 0,
|
||||||
0, PL1_RW, NULL, 0, offsetof(CPUARMState, cp15.c15_power_diagnostic) },
|
0, PL1_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_power_diagnostic) },
|
||||||
{ "NEONBUSY", 15,15,1, 0,0,0, 0,
|
{ "NEONBUSY", 15,15,1, 0,0,0, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
/* TLB lockdown control */
|
/* TLB lockdown control */
|
||||||
{ "TLB_LOCKR", 15,15,4, 0,5,2, 0,
|
{ "TLB_LOCKR", 15,15,4, 0,5,2, 0,
|
||||||
ARM_CP_NOP, PL1_W, NULL, 0 },
|
ARM_CP_NOP, PL1_W, 0, NULL, 0 },
|
||||||
{ "TLB_LOCKW", 15,15,4, 0,5,4, 0,
|
{ "TLB_LOCKW", 15,15,4, 0,5,4, 0,
|
||||||
ARM_CP_NOP, PL1_W, NULL, 0, },
|
ARM_CP_NOP, PL1_W, 0, NULL, 0, },
|
||||||
{ "TLB_VA", 15,15,5, 0,5,2, 0,
|
{ "TLB_VA", 15,15,5, 0,5,2, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
{ "TLB_PA", 15,15,6, 0,5,2, 0,
|
{ "TLB_PA", 15,15,6, 0,5,2, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
{ "TLB_ATTR", 15,15,7, 0,5,2, 0,
|
{ "TLB_ATTR", 15,15,7, 0,5,2, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -779,11 +779,11 @@ static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
{ "L2CTLR", 15,9,0, 0,1,2, 0,
|
{ "L2CTLR", 15,9,0, 0,1,2, 0,
|
||||||
0, PL1_RW, NULL, 0, 0,
|
0, PL1_RW, 0, NULL, 0, 0, {0, 0},
|
||||||
NULL, a15_l2ctlr_read, arm_cp_write_ignore, },
|
NULL, a15_l2ctlr_read, arm_cp_write_ignore, },
|
||||||
#endif
|
#endif
|
||||||
{ "L2ECTLR", 15,9,0, 0,1,3, 0,
|
{ "L2ECTLR", 15,9,0, 0,1,3, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1007,6 +1007,21 @@ enum {
|
||||||
ARM_CP_STATE_BOTH = 2,
|
ARM_CP_STATE_BOTH = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ARM CP register secure state flags. These flags identify security state
|
||||||
|
* attributes for a given CP register entry.
|
||||||
|
* The existence of both or neither secure and non-secure flags indicates that
|
||||||
|
* the register has both a secure and non-secure hash entry. A single one of
|
||||||
|
* these flags causes the register to only be hashed for the specified
|
||||||
|
* security state.
|
||||||
|
* Although definitions may have any combination of the S/NS bits, each
|
||||||
|
* registered entry will only have one to identify whether the entry is secure
|
||||||
|
* or non-secure.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */
|
||||||
|
ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
|
||||||
|
};
|
||||||
|
|
||||||
/* Return true if cptype is a valid type field. This is used to try to
|
/* Return true if cptype is a valid type field. This is used to try to
|
||||||
* catch errors where the sentinel has been accidentally left off the end
|
* catch errors where the sentinel has been accidentally left off the end
|
||||||
* of a list of registers.
|
* of a list of registers.
|
||||||
|
@ -1141,6 +1156,8 @@ struct ARMCPRegInfo {
|
||||||
int type;
|
int type;
|
||||||
/* Access rights: PL*_[RW] */
|
/* Access rights: PL*_[RW] */
|
||||||
int access;
|
int access;
|
||||||
|
/* Security state: ARM_CP_SECSTATE_* bits/values */
|
||||||
|
int secure;
|
||||||
/* The opaque pointer passed to define_arm_cp_regs_with_opaque() when
|
/* The opaque pointer passed to define_arm_cp_regs_with_opaque() when
|
||||||
* this register was defined: can be used to hand data through to the
|
* this register was defined: can be used to hand data through to the
|
||||||
* register read/write functions, since they are passed the ARMCPRegInfo*.
|
* register read/write functions, since they are passed the ARMCPRegInfo*.
|
||||||
|
@ -1150,12 +1167,27 @@ struct ARMCPRegInfo {
|
||||||
* fieldoffset is non-zero, the reset value of the register.
|
* fieldoffset is non-zero, the reset value of the register.
|
||||||
*/
|
*/
|
||||||
uint64_t resetvalue;
|
uint64_t resetvalue;
|
||||||
/* Offset of the field in CPUARMState for this register. This is not
|
/* Offset of the field in CPUARMState for this register.
|
||||||
* needed if either:
|
*
|
||||||
|
* This is not needed if either:
|
||||||
* 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs
|
* 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs
|
||||||
* 2. both readfn and writefn are specified
|
* 2. both readfn and writefn are specified
|
||||||
*/
|
*/
|
||||||
ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
|
ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
|
||||||
|
|
||||||
|
/* Offsets of the secure and non-secure fields in CPUARMState for the
|
||||||
|
* register if it is banked. These fields are only used during the static
|
||||||
|
* registration of a register. During hashing the bank associated
|
||||||
|
* with a given security state is copied to fieldoffset which is used from
|
||||||
|
* there on out.
|
||||||
|
*
|
||||||
|
* It is expected that register definitions use either fieldoffset or
|
||||||
|
* bank_fieldoffsets in the definition but not both. It is also expected
|
||||||
|
* that both bank offsets are set when defining a banked register. This
|
||||||
|
* use indicates that a register is banked.
|
||||||
|
*/
|
||||||
|
ptrdiff_t bank_fieldoffsets[2];
|
||||||
|
|
||||||
/* Function for making any access checks for this register in addition to
|
/* Function for making any access checks for this register in addition to
|
||||||
* those specified by the 'access' permissions bits. If NULL, no extra
|
* those specified by the 'access' permissions bits. If NULL, no extra
|
||||||
* checks required. The access check is performed at runtime, not at
|
* checks required. The access check is performed at runtime, not at
|
||||||
|
@ -1200,7 +1232,7 @@ struct ARMCPRegInfo {
|
||||||
#define CPREG_FIELD64(env, ri) \
|
#define CPREG_FIELD64(env, ri) \
|
||||||
(*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
|
(*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
|
||||||
|
|
||||||
#define REGINFO_SENTINEL { NULL, 0,0,0,0,0,0, 0, ARM_CP_SENTINEL, 0, NULL, 0,0,0,0,0,0,0,0, }
|
#define REGINFO_SENTINEL { NULL, 0,0,0,0,0,0, 0, ARM_CP_SENTINEL, 0, 0, NULL, 0,0, {0, 0}, 0,0,0,0,0,0, }
|
||||||
|
|
||||||
void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
|
void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
|
||||||
const ARMCPRegInfo *regs, void *opaque);
|
const ARMCPRegInfo *regs, void *opaque);
|
||||||
|
|
|
@ -39,34 +39,34 @@ static uint64_t a57_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
static const ARMCPRegInfo cortexa57_cp_reginfo[] = {
|
static const ARMCPRegInfo cortexa57_cp_reginfo[] = {
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
{ "L2CTLR_EL1", 0,11,0, 3,1,2, ARM_CP_STATE_AA64,
|
{ "L2CTLR_EL1", 0,11,0, 3,1,2, ARM_CP_STATE_AA64,
|
||||||
0, PL1_RW, NULL, 0, 0,
|
0, PL1_RW, 0, NULL, 0, 0, {0, 0},
|
||||||
NULL, a57_l2ctlr_read, arm_cp_write_ignore, },
|
NULL, a57_l2ctlr_read, arm_cp_write_ignore, },
|
||||||
{ "L2CTLR", 15,9,0, 0,1,2, 0,
|
{ "L2CTLR", 15,9,0, 0,1,2, 0,
|
||||||
0, PL1_RW, NULL, 0, 0,
|
0, PL1_RW, 0, NULL, 0, 0, {0, 0},
|
||||||
NULL, a57_l2ctlr_read, arm_cp_write_ignore, },
|
NULL, a57_l2ctlr_read, arm_cp_write_ignore, },
|
||||||
#endif
|
#endif
|
||||||
{ "L2ECTLR_EL1", 0,11,0, 3,1,3, ARM_CP_STATE_AA64,
|
{ "L2ECTLR_EL1", 0,11,0, 3,1,3, ARM_CP_STATE_AA64,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
{ "L2ECTLR", 15,9,0, 0,1,3, 0,
|
{ "L2ECTLR", 15,9,0, 0,1,3, 0,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
{ "L2ACTLR", 0,15,0, 3,1,0, ARM_CP_STATE_BOTH,
|
{ "L2ACTLR", 0,15,0, 3,1,0, ARM_CP_STATE_BOTH,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
{ "CPUACTLR_EL1", 0,15,2, 3,1,0, ARM_CP_STATE_AA64,
|
{ "CPUACTLR_EL1", 0,15,2, 3,1,0, ARM_CP_STATE_AA64,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
{ "CPUACTLR", 15,0,15, 0,0,0, 0,
|
{ "CPUACTLR", 15,0,15, 0,0,0, 0,
|
||||||
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, NULL, 0, },
|
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, 0, NULL, 0, },
|
||||||
{ "CPUECTLR_EL1", 0,15,2, 3,1,1, ARM_CP_STATE_AA64,
|
{ "CPUECTLR_EL1", 0,15,2, 3,1,1, ARM_CP_STATE_AA64,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0, },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0, },
|
||||||
{ "CPUECTLR", 15,0,15, 0,1,0, 0,
|
{ "CPUECTLR", 15,0,15, 0,1,0, 0,
|
||||||
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, NULL, 0, },
|
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, 0, NULL, 0, },
|
||||||
{ "CPUMERRSR_EL1", 0,15,2, 3,1,2, ARM_CP_STATE_AA64,
|
{ "CPUMERRSR_EL1", 0,15,2, 3,1,2, ARM_CP_STATE_AA64,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
{ "CPUMERRSR", 15,0,15, 0,2,0, 0,
|
{ "CPUMERRSR", 15,0,15, 0,2,0, 0,
|
||||||
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, NULL, 0 },
|
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, 0, NULL, 0 },
|
||||||
{ "L2MERRSR_EL1", 0,15,2, 3,1,3, ARM_CP_STATE_AA64,
|
{ "L2MERRSR_EL1", 0,15,2, 3,1,3, ARM_CP_STATE_AA64,
|
||||||
ARM_CP_CONST, PL1_RW, NULL, 0 },
|
ARM_CP_CONST, PL1_RW, 0, NULL, 0 },
|
||||||
{ "L2MERRSR", 15,0,15, 0,3,0, 0,
|
{ "L2MERRSR", 15,0,15, 0,3,0, 0,
|
||||||
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, NULL, 0 },
|
ARM_CP_CONST | ARM_CP_64BIT, PL1_RW, 0, NULL, 0 },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue