aboutsummaryrefslogtreecommitdiff
path: root/target/arm/cpregs.h
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/cpregs.h')
-rw-r--r--target/arm/cpregs.h186
1 files changed, 113 insertions, 73 deletions
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
index 2183de8..763de5e 100644
--- a/target/arm/cpregs.h
+++ b/target/arm/cpregs.h
@@ -22,7 +22,9 @@
#define TARGET_ARM_CPREGS_H
#include "hw/registerfields.h"
+#include "exec/memop.h"
#include "target/arm/kvm-consts.h"
+#include "cpu.h"
/*
* ARMCPRegInfo type field bits:
@@ -45,6 +47,14 @@ enum {
ARM_CP_DC_ZVA = 0x0005,
ARM_CP_DC_GVA = 0x0006,
ARM_CP_DC_GZVA = 0x0007,
+ /* Special: gcs instructions */
+ ARM_CP_GCSPUSHM = 0x0008,
+ ARM_CP_GCSPOPM = 0x0009,
+ ARM_CP_GCSPUSHX = 0x000a,
+ ARM_CP_GCSPOPX = 0x000b,
+ ARM_CP_GCSPOPCX = 0x000c,
+ ARM_CP_GCSSS1 = 0x000d,
+ ARM_CP_GCSSS2 = 0x000e,
/* Flag: reads produce resetvalue; writes ignored. */
ARM_CP_CONST = 1 << 4,
@@ -134,6 +144,11 @@ enum {
* identically to the normal one, other than FGT trapping handling.)
*/
ARM_CP_ADD_TLBI_NXS = 1 << 21,
+ /*
+ * Flag: even though this sysreg has opc1 == 4 or 5, it
+ * should not trap to EL2 when HCR_EL2.NV is set.
+ */
+ ARM_CP_NV_NO_TRAP = 1 << 22,
};
/*
@@ -173,16 +188,20 @@ enum {
* add a bit to distinguish between secure and non-secure cpregs in the
* hashtable.
*/
-#define CP_REG_NS_SHIFT 29
-#define CP_REG_NS_MASK (1 << CP_REG_NS_SHIFT)
+#define CP_REG_AA32_NS_SHIFT 29
+#define CP_REG_AA32_NS_MASK (1 << CP_REG_AA32_NS_SHIFT)
+
+/* Distinguish 32-bit and 64-bit views of AArch32 system registers. */
+#define CP_REG_AA32_64BIT_SHIFT 15
+#define CP_REG_AA32_64BIT_MASK (1 << CP_REG_AA32_64BIT_SHIFT)
#define ENCODE_CP_REG(cp, is64, ns, crn, crm, opc1, opc2) \
- ((ns) << CP_REG_NS_SHIFT | ((cp) << 16) | ((is64) << 15) | \
- ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
+ (((ns) << CP_REG_AA32_NS_SHIFT) | \
+ ((is64) << CP_REG_AA32_64BIT_SHIFT) | \
+ ((cp) << 16) | ((crn) << 11) | ((crm) << 7) | ((opc1) << 3) | (opc2))
-#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
- (CP_REG_AA64_MASK | \
- ((cp) << CP_REG_ARM_COPROC_SHIFT) | \
+#define ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2) \
+ (CP_REG_AA64_MASK | CP_REG_ARM64_SYSREG | \
((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) | \
((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) | \
((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) | \
@@ -200,14 +219,14 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
cpregid |= CP_REG_AA64_MASK;
} else {
if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
- cpregid |= (1 << 15);
+ cpregid |= CP_REG_AA32_64BIT_MASK;
}
/*
* KVM is always non-secure so add the NS flag on AArch32 register
* entries.
*/
- cpregid |= 1 << CP_REG_NS_SHIFT;
+ cpregid |= CP_REG_AA32_NS_MASK;
}
return cpregid;
}
@@ -224,8 +243,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
kvmid = cpregid & ~CP_REG_AA64_MASK;
kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
} else {
- kvmid = cpregid & ~(1 << 15);
- if (cpregid & (1 << 15)) {
+ kvmid = cpregid & ~CP_REG_AA32_64BIT_MASK;
+ if (cpregid & CP_REG_AA32_64BIT_MASK) {
kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
} else {
kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
@@ -345,6 +364,14 @@ typedef enum CPAccessResult {
* specified target EL.
*/
CP_ACCESS_UNDEFINED = (2 << 2),
+
+ /*
+ * Access fails with EXLOCK, a GCS exception syndrome.
+ * These traps are always to the current execution EL,
+ * which is the same as the usual target EL because
+ * they cannot occur from EL0.
+ */
+ CP_ACCESS_EXLOCK = (3 << 2),
} CPAccessResult;
/* Indexes into fgt_read[] */
@@ -407,10 +434,19 @@ FIELD(HFGRTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGRTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGRTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGRTR_EL2, NACCDATA_EL1, 50, 1)
-/* 51-53: RES0 */
+/* 51: RES0 */
+FIELD(HFGRTR_EL2, NGCS_EL0, 52, 1)
+FIELD(HFGRTR_EL2, NGCS_EL1, 53, 1)
FIELD(HFGRTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGRTR_EL2, NTPIDR2_EL0, 55, 1)
-/* 56-63: RES0 */
+FIELD(HFGRTR_EL2, NRCWMASK_EL1, 56, 1)
+FIELD(HFGRTR_EL2, NPIRE0_EL1, 57, 1)
+FIELD(HFGRTR_EL2, NPIR_EL1, 58, 1)
+FIELD(HFGRTR_EL2, NPOR_EL0, 59, 1)
+FIELD(HFGRTR_EL2, NPOR_EL1, 60, 1)
+FIELD(HFGRTR_EL2, NS2POR_EL1, 61, 1)
+FIELD(HFGRTR_EL2, NMAIR2_EL1, 62, 1)
+FIELD(HFGRTR_EL2, NAMAIR2_EL1, 63, 1)
/* These match HFGRTR but bits for RO registers are RES0 */
FIELD(HFGWTR_EL2, AFSR0_EL1, 0, 1)
@@ -451,8 +487,18 @@ FIELD(HFGWTR_EL2, ERXPFGCTL_EL1, 47, 1)
FIELD(HFGWTR_EL2, ERXPFGCDN_EL1, 48, 1)
FIELD(HFGWTR_EL2, ERXADDR_EL1, 49, 1)
FIELD(HFGWTR_EL2, NACCDATA_EL1, 50, 1)
+FIELD(HFGWTR_EL2, NGCS_EL0, 52, 1)
+FIELD(HFGWTR_EL2, NGCS_EL1, 53, 1)
FIELD(HFGWTR_EL2, NSMPRI_EL1, 54, 1)
FIELD(HFGWTR_EL2, NTPIDR2_EL0, 55, 1)
+FIELD(HFGWTR_EL2, NRCWMASK_EL1, 56, 1)
+FIELD(HFGWTR_EL2, NPIRE0_EL1, 57, 1)
+FIELD(HFGWTR_EL2, NPIR_EL1, 58, 1)
+FIELD(HFGWTR_EL2, NPOR_EL0, 59, 1)
+FIELD(HFGWTR_EL2, NPOR_EL1, 60, 1)
+FIELD(HFGWTR_EL2, NS2POR_EL1, 61, 1)
+FIELD(HFGWTR_EL2, NMAIR2_EL1, 62, 1)
+FIELD(HFGWTR_EL2, NAMAIR2_EL1, 63, 1)
FIELD(HFGITR_EL2, ICIALLUIS, 0, 1)
FIELD(HFGITR_EL2, ICIALLU, 1, 1)
@@ -511,6 +557,11 @@ FIELD(HFGITR_EL2, SVC_EL1, 53, 1)
FIELD(HFGITR_EL2, DCCVAC, 54, 1)
FIELD(HFGITR_EL2, NBRBINJ, 55, 1)
FIELD(HFGITR_EL2, NBRBIALL, 56, 1)
+FIELD(HFGITR_EL2, NGCSPUSHM_EL1, 57, 1)
+FIELD(HFGITR_EL2, NGCSSTR_EL1, 58, 1)
+FIELD(HFGITR_EL2, NGCSEPP, 59, 1)
+FIELD(HFGITR_EL2, COSPRCTX, 60, 1)
+FIELD(HFGITR_EL2, ATS1E1A, 62, 1)
FIELD(HDFGRTR_EL2, DBGBCRN_EL1, 0, 1)
FIELD(HDFGRTR_EL2, DBGBVRN_EL1, 1, 1)
@@ -749,8 +800,12 @@ typedef enum FGTBit {
DO_BIT(HFGRTR, VBAR_EL1),
DO_BIT(HFGRTR, ICC_IGRPENN_EL1),
DO_BIT(HFGRTR, ERRIDR_EL1),
+ DO_REV_BIT(HFGRTR, NGCS_EL0),
+ DO_REV_BIT(HFGRTR, NGCS_EL1),
DO_REV_BIT(HFGRTR, NSMPRI_EL1),
DO_REV_BIT(HFGRTR, NTPIDR2_EL0),
+ DO_REV_BIT(HFGRTR, NPIRE0_EL1),
+ DO_REV_BIT(HFGRTR, NPIR_EL1),
/* Trap bits in HDFGRTR_EL2 / HDFGWTR_EL2, starting from bit 0. */
DO_BIT(HDFGRTR, DBGBCRN_EL1),
@@ -829,6 +884,9 @@ typedef enum FGTBit {
DO_BIT(HFGITR, DVPRCTX),
DO_BIT(HFGITR, CPPRCTX),
DO_BIT(HFGITR, DCCVAC),
+ DO_REV_BIT(HFGITR, NGCSPUSHM_EL1),
+ DO_REV_BIT(HFGITR, NGCSEPP),
+ DO_BIT(HFGITR, ATS1E1A),
} FGTBit;
#undef DO_BIT
@@ -840,15 +898,15 @@ typedef struct ARMCPRegInfo ARMCPRegInfo;
* Access functions for coprocessor registers. These cannot fail and
* may not raise exceptions.
*/
-typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
-typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
+typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *ri);
+typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value);
/* Access permission check functions for coprocessor registers. */
typedef CPAccessResult CPAccessFn(CPUARMState *env,
- const ARMCPRegInfo *opaque,
+ const ARMCPRegInfo *ri,
bool isread);
/* Hook function for register reset */
-typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
+typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *ri);
#define CP_ANY 0xff
@@ -906,11 +964,19 @@ struct ARMCPRegInfo {
uint32_t nv2_redirect_offset;
/*
- * 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
- * register read/write functions, since they are passed the ARMCPRegInfo*.
+ * With VHE, with E2H, at EL2, access to this EL0/EL1 reg redirects
+ * to the EL2 reg with the specified key.
+ */
+ uint32_t vhe_redir_to_el2;
+
+ /*
+ * For VHE. Before registration, this field holds the key for an
+ * EL02/EL12 reg to be created to point back to this EL0/EL1 reg.
+ * After registration, this field is set only on the EL02/EL12 reg
+ * and points back to the EL02/EL12 reg for redirection with E2H.
*/
- void *opaque;
+ uint32_t vhe_redir_to_el01;
+
/*
* Value of this register, if it is ARM_CP_CONST. Otherwise, if
* fieldoffset is non-zero, the reset value of the register.
@@ -978,52 +1044,17 @@ struct ARMCPRegInfo {
* fieldoffset is 0 then no reset will be done.
*/
CPResetFn *resetfn;
-
- /*
- * "Original" readfn, writefn, accessfn.
- * For ARMv8.1-VHE register aliases, we overwrite the read/write
- * accessor functions of various EL1/EL0 to perform the runtime
- * check for which sysreg should actually be modified, and then
- * forwards the operation. Before overwriting the accessors,
- * the original function is copied here, so that accesses that
- * really do go to the EL1/EL0 version proceed normally.
- * (The corresponding EL2 register is linked via opaque.)
- */
- CPReadFn *orig_readfn;
- CPWriteFn *orig_writefn;
- CPAccessFn *orig_accessfn;
};
-/*
- * Macros which are lvalues for the field in CPUARMState for the
- * ARMCPRegInfo *ri.
- */
-#define CPREG_FIELD32(env, ri) \
- (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
-#define CPREG_FIELD64(env, ri) \
- (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
-
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
- void *opaque);
+void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs);
+void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len);
-static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
-{
- define_one_arm_cp_reg_with_opaque(cpu, regs, NULL);
-}
-
-void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
- void *opaque, size_t len);
-
-#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE) \
- do { \
- QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \
- define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE, \
- ARRAY_SIZE(REGS)); \
+#define define_arm_cp_regs(CPU, REGS) \
+ do { \
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \
+ define_arm_cp_regs_len(CPU, REGS, ARRAY_SIZE(REGS)); \
} while (0)
-#define define_arm_cp_regs(CPU, REGS) \
- define_arm_cp_regs_with_opaque(CPU, REGS, NULL)
-
const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
/*
@@ -1064,6 +1095,9 @@ void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
/* CPReadFn that can be used for read-as-zero behaviour */
uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
+/* CPReadFn that just reads the value from ri->fieldoffset */
+uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri);
+
/* CPWriteFn that just writes the value to ri->fieldoffset */
void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
@@ -1071,15 +1105,16 @@ void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
* CPResetFn that does nothing, for use if no reset is required even
* if fieldoffset is non zero.
*/
-void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri);
/*
- * Return true if this reginfo struct's field in the cpu state struct
- * is 64 bits wide.
+ * Return MO_32 if the field in CPUARMState is uint32_t or
+ * MO_64 if the field in CPUARMState is uint64_t.
*/
-static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
+static inline MemOp cpreg_field_type(const ARMCPRegInfo *ri)
{
- return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT);
+ return (ri->state == ARM_CP_STATE_AA64 || (ri->type & ARM_CP_64BIT)
+ ? MO_64 : MO_32);
}
static inline bool cp_access_ok(int current_el,
@@ -1139,7 +1174,7 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
* means that the right set of registers is exactly those where
* the opc1 field is 4 or 5. (You can see this also in the assert
* we do that the opc1 field and the permissions mask line up in
- * define_one_arm_cp_reg_with_opaque().)
+ * define_one_arm_cp_reg().)
* Checking the opc1 field is easier for us and avoids the problem
* that we do not consistently use the right architectural names
* for all sysregs, since we treat the name field as largely for debug.
@@ -1148,12 +1183,17 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
* fragile to future new sysregs, but this seems the least likely
* to break.
*
- * In particular, note that the released sysreg XML defines that
- * the FEAT_MEC sysregs and instructions do not follow this FEAT_NV
- * trapping rule, so we will need to add an ARM_CP_* flag to indicate
- * "register does not trap on NV" to handle those if/when we implement
- * FEAT_MEC.
+ * In particular, note that the FEAT_MEC sysregs and instructions
+ * are exceptions to this trapping rule, so they are marked as
+ * ARM_CP_NV_NO_TRAP to indicate that they should not be trapped
+ * to EL2. (They are an exception because the FEAT_MEC sysregs UNDEF
+ * unless in Realm, and Realm is not expected to be virtualized.)
*/
+
+ if (ri->type & ARM_CP_NV_NO_TRAP) {
+ return false;
+ }
+
return ri->opc1 == 4 || ri->opc1 == 5;
}