diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/arm/arm-powerctl.c | 26 | ||||
-rw-r--r-- | target/arm/cpregs.h | 111 | ||||
-rw-r--r-- | target/arm/cpu-features.h | 415 | ||||
-rw-r--r-- | target/arm/cpu-sysregs.h.inc | 1 | ||||
-rw-r--r-- | target/arm/cpu.c | 16 | ||||
-rw-r--r-- | target/arm/cpu.h | 413 | ||||
-rw-r--r-- | target/arm/gdbstub.c | 14 | ||||
-rw-r--r-- | target/arm/helper.c | 933 | ||||
-rw-r--r-- | target/arm/hvf/hvf.c | 240 | ||||
-rw-r--r-- | target/arm/hvf/sysreg.c.inc | 147 | ||||
-rw-r--r-- | target/arm/internals.h | 3 | ||||
-rw-r--r-- | target/arm/kvm-consts.h | 14 | ||||
-rw-r--r-- | target/arm/kvm.c | 12 | ||||
-rw-r--r-- | target/arm/tcg/hflags.c | 8 | ||||
-rw-r--r-- | target/arm/tcg/translate-a64.c | 47 | ||||
-rw-r--r-- | target/arm/tcg/translate.h | 2 | ||||
-rw-r--r-- | target/arm/trace-events | 10 |
17 files changed, 1187 insertions, 1225 deletions
diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index 20c70c7..a788376 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -17,24 +17,12 @@ #include "qemu/main-loop.h" #include "system/tcg.h" #include "target/arm/multiprocessing.h" - -#ifndef DEBUG_ARM_POWERCTL -#define DEBUG_ARM_POWERCTL 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_ARM_POWERCTL) { \ - fprintf(stderr, "[ARM]%s: " fmt , __func__, ##args); \ - } \ - } while (0) +#include "trace.h" CPUState *arm_get_cpu_by_id(uint64_t id) { CPUState *cpu; - DPRINTF("cpu %" PRId64 "\n", id); - CPU_FOREACH(cpu) { ARMCPU *armcpu = ARM_CPU(cpu); @@ -102,9 +90,9 @@ int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id, assert(bql_locked()); - DPRINTF("cpu %" PRId64 " (EL %d, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64 - "\n", cpuid, target_el, target_aa64 ? "aarch64" : "aarch32", entry, - context_id); + trace_arm_powerctl_set_cpu_on(cpuid, target_el, + target_aa64 ? "aarch64" : "aarch32", + entry, context_id); /* requested EL level need to be in the 1 to 3 range */ assert((target_el > 0) && (target_el < 4)); @@ -208,6 +196,8 @@ int arm_set_cpu_on_and_reset(uint64_t cpuid) assert(bql_locked()); + trace_arm_powerctl_set_cpu_on_and_reset(cpuid); + /* Retrieve the cpu we are powering up */ target_cpu_state = arm_get_cpu_by_id(cpuid); if (!target_cpu_state) { @@ -261,7 +251,7 @@ int arm_set_cpu_off(uint64_t cpuid) assert(bql_locked()); - DPRINTF("cpu %" PRId64 "\n", cpuid); + trace_arm_powerctl_set_cpu_off(cpuid); /* change to the cpu we are powering up */ target_cpu_state = arm_get_cpu_by_id(cpuid); @@ -297,7 +287,7 @@ int arm_reset_cpu(uint64_t cpuid) assert(bql_locked()); - DPRINTF("cpu %" PRId64 "\n", cpuid); + trace_arm_powerctl_set_cpu_off(cpuid); /* change to the cpu we are resetting */ target_cpu_state = arm_get_cpu_by_id(cpuid); diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 2a4826f..57fde5f 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -22,6 +22,7 @@ #define TARGET_ARM_CPREGS_H #include "hw/registerfields.h" +#include "exec/memop.h" #include "target/arm/kvm-consts.h" #include "cpu.h" @@ -174,16 +175,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) | \ @@ -201,14 +206,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; } @@ -225,8 +230,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; @@ -866,15 +871,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 @@ -932,11 +937,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. */ - void *opaque; + 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. + */ + 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. @@ -1004,52 +1017,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(ARMCPU *cpu, const ARMCPRegInfo *regs); +void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len); -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg, - void *opaque); - -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); /* @@ -1100,15 +1078,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, @@ -1168,7 +1147,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. diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 512eeaf..602f6a8 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -26,6 +26,421 @@ #include "cpu-sysregs.h" /* + * System register ID fields. + */ +FIELD(CLIDR_EL1, CTYPE1, 0, 3) +FIELD(CLIDR_EL1, CTYPE2, 3, 3) +FIELD(CLIDR_EL1, CTYPE3, 6, 3) +FIELD(CLIDR_EL1, CTYPE4, 9, 3) +FIELD(CLIDR_EL1, CTYPE5, 12, 3) +FIELD(CLIDR_EL1, CTYPE6, 15, 3) +FIELD(CLIDR_EL1, CTYPE7, 18, 3) +FIELD(CLIDR_EL1, LOUIS, 21, 3) +FIELD(CLIDR_EL1, LOC, 24, 3) +FIELD(CLIDR_EL1, LOUU, 27, 3) +FIELD(CLIDR_EL1, ICB, 30, 3) + +/* When FEAT_CCIDX is implemented */ +FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3) +FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21) +FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24) + +/* When FEAT_CCIDX is not implemented */ +FIELD(CCSIDR_EL1, LINESIZE, 0, 3) +FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10) +FIELD(CCSIDR_EL1, NUMSETS, 13, 15) + +FIELD(CTR_EL0, IMINLINE, 0, 4) +FIELD(CTR_EL0, L1IP, 14, 2) +FIELD(CTR_EL0, DMINLINE, 16, 4) +FIELD(CTR_EL0, ERG, 20, 4) +FIELD(CTR_EL0, CWG, 24, 4) +FIELD(CTR_EL0, IDC, 28, 1) +FIELD(CTR_EL0, DIC, 29, 1) +FIELD(CTR_EL0, TMINLINE, 32, 6) + +FIELD(MIDR_EL1, REVISION, 0, 4) +FIELD(MIDR_EL1, PARTNUM, 4, 12) +FIELD(MIDR_EL1, ARCHITECTURE, 16, 4) +FIELD(MIDR_EL1, VARIANT, 20, 4) +FIELD(MIDR_EL1, IMPLEMENTER, 24, 8) + +FIELD(ID_ISAR0, SWAP, 0, 4) +FIELD(ID_ISAR0, BITCOUNT, 4, 4) +FIELD(ID_ISAR0, BITFIELD, 8, 4) +FIELD(ID_ISAR0, CMPBRANCH, 12, 4) +FIELD(ID_ISAR0, COPROC, 16, 4) +FIELD(ID_ISAR0, DEBUG, 20, 4) +FIELD(ID_ISAR0, DIVIDE, 24, 4) + +FIELD(ID_ISAR1, ENDIAN, 0, 4) +FIELD(ID_ISAR1, EXCEPT, 4, 4) +FIELD(ID_ISAR1, EXCEPT_AR, 8, 4) +FIELD(ID_ISAR1, EXTEND, 12, 4) +FIELD(ID_ISAR1, IFTHEN, 16, 4) +FIELD(ID_ISAR1, IMMEDIATE, 20, 4) +FIELD(ID_ISAR1, INTERWORK, 24, 4) +FIELD(ID_ISAR1, JAZELLE, 28, 4) + +FIELD(ID_ISAR2, LOADSTORE, 0, 4) +FIELD(ID_ISAR2, MEMHINT, 4, 4) +FIELD(ID_ISAR2, MULTIACCESSINT, 8, 4) +FIELD(ID_ISAR2, MULT, 12, 4) +FIELD(ID_ISAR2, MULTS, 16, 4) +FIELD(ID_ISAR2, MULTU, 20, 4) +FIELD(ID_ISAR2, PSR_AR, 24, 4) +FIELD(ID_ISAR2, REVERSAL, 28, 4) + +FIELD(ID_ISAR3, SATURATE, 0, 4) +FIELD(ID_ISAR3, SIMD, 4, 4) +FIELD(ID_ISAR3, SVC, 8, 4) +FIELD(ID_ISAR3, SYNCHPRIM, 12, 4) +FIELD(ID_ISAR3, TABBRANCH, 16, 4) +FIELD(ID_ISAR3, T32COPY, 20, 4) +FIELD(ID_ISAR3, TRUENOP, 24, 4) +FIELD(ID_ISAR3, T32EE, 28, 4) + +FIELD(ID_ISAR4, UNPRIV, 0, 4) +FIELD(ID_ISAR4, WITHSHIFTS, 4, 4) +FIELD(ID_ISAR4, WRITEBACK, 8, 4) +FIELD(ID_ISAR4, SMC, 12, 4) +FIELD(ID_ISAR4, BARRIER, 16, 4) +FIELD(ID_ISAR4, SYNCHPRIM_FRAC, 20, 4) +FIELD(ID_ISAR4, PSR_M, 24, 4) +FIELD(ID_ISAR4, SWP_FRAC, 28, 4) + +FIELD(ID_ISAR5, SEVL, 0, 4) +FIELD(ID_ISAR5, AES, 4, 4) +FIELD(ID_ISAR5, SHA1, 8, 4) +FIELD(ID_ISAR5, SHA2, 12, 4) +FIELD(ID_ISAR5, CRC32, 16, 4) +FIELD(ID_ISAR5, RDM, 24, 4) +FIELD(ID_ISAR5, VCMA, 28, 4) + +FIELD(ID_ISAR6, JSCVT, 0, 4) +FIELD(ID_ISAR6, DP, 4, 4) +FIELD(ID_ISAR6, FHM, 8, 4) +FIELD(ID_ISAR6, SB, 12, 4) +FIELD(ID_ISAR6, SPECRES, 16, 4) +FIELD(ID_ISAR6, BF16, 20, 4) +FIELD(ID_ISAR6, I8MM, 24, 4) + +FIELD(ID_MMFR0, VMSA, 0, 4) +FIELD(ID_MMFR0, PMSA, 4, 4) +FIELD(ID_MMFR0, OUTERSHR, 8, 4) +FIELD(ID_MMFR0, SHARELVL, 12, 4) +FIELD(ID_MMFR0, TCM, 16, 4) +FIELD(ID_MMFR0, AUXREG, 20, 4) +FIELD(ID_MMFR0, FCSE, 24, 4) +FIELD(ID_MMFR0, INNERSHR, 28, 4) + +FIELD(ID_MMFR1, L1HVDVA, 0, 4) +FIELD(ID_MMFR1, L1UNIVA, 4, 4) +FIELD(ID_MMFR1, L1HVDSW, 8, 4) +FIELD(ID_MMFR1, L1UNISW, 12, 4) +FIELD(ID_MMFR1, L1HVD, 16, 4) +FIELD(ID_MMFR1, L1UNI, 20, 4) +FIELD(ID_MMFR1, L1TSTCLN, 24, 4) +FIELD(ID_MMFR1, BPRED, 28, 4) + +FIELD(ID_MMFR2, L1HVDFG, 0, 4) +FIELD(ID_MMFR2, L1HVDBG, 4, 4) +FIELD(ID_MMFR2, L1HVDRNG, 8, 4) +FIELD(ID_MMFR2, HVDTLB, 12, 4) +FIELD(ID_MMFR2, UNITLB, 16, 4) +FIELD(ID_MMFR2, MEMBARR, 20, 4) +FIELD(ID_MMFR2, WFISTALL, 24, 4) +FIELD(ID_MMFR2, HWACCFLG, 28, 4) + +FIELD(ID_MMFR3, CMAINTVA, 0, 4) +FIELD(ID_MMFR3, CMAINTSW, 4, 4) +FIELD(ID_MMFR3, BPMAINT, 8, 4) +FIELD(ID_MMFR3, MAINTBCST, 12, 4) +FIELD(ID_MMFR3, PAN, 16, 4) +FIELD(ID_MMFR3, COHWALK, 20, 4) +FIELD(ID_MMFR3, CMEMSZ, 24, 4) +FIELD(ID_MMFR3, SUPERSEC, 28, 4) + +FIELD(ID_MMFR4, SPECSEI, 0, 4) +FIELD(ID_MMFR4, AC2, 4, 4) +FIELD(ID_MMFR4, XNX, 8, 4) +FIELD(ID_MMFR4, CNP, 12, 4) +FIELD(ID_MMFR4, HPDS, 16, 4) +FIELD(ID_MMFR4, LSM, 20, 4) +FIELD(ID_MMFR4, CCIDX, 24, 4) +FIELD(ID_MMFR4, EVT, 28, 4) + +FIELD(ID_MMFR5, ETS, 0, 4) +FIELD(ID_MMFR5, NTLBPA, 4, 4) + +FIELD(ID_PFR0, STATE0, 0, 4) +FIELD(ID_PFR0, STATE1, 4, 4) +FIELD(ID_PFR0, STATE2, 8, 4) +FIELD(ID_PFR0, STATE3, 12, 4) +FIELD(ID_PFR0, CSV2, 16, 4) +FIELD(ID_PFR0, AMU, 20, 4) +FIELD(ID_PFR0, DIT, 24, 4) +FIELD(ID_PFR0, RAS, 28, 4) + +FIELD(ID_PFR1, PROGMOD, 0, 4) +FIELD(ID_PFR1, SECURITY, 4, 4) +FIELD(ID_PFR1, MPROGMOD, 8, 4) +FIELD(ID_PFR1, VIRTUALIZATION, 12, 4) +FIELD(ID_PFR1, GENTIMER, 16, 4) +FIELD(ID_PFR1, SEC_FRAC, 20, 4) +FIELD(ID_PFR1, VIRT_FRAC, 24, 4) +FIELD(ID_PFR1, GIC, 28, 4) + +FIELD(ID_PFR2, CSV3, 0, 4) +FIELD(ID_PFR2, SSBS, 4, 4) +FIELD(ID_PFR2, RAS_FRAC, 8, 4) + +FIELD(ID_AA64ISAR0, AES, 4, 4) +FIELD(ID_AA64ISAR0, SHA1, 8, 4) +FIELD(ID_AA64ISAR0, SHA2, 12, 4) +FIELD(ID_AA64ISAR0, CRC32, 16, 4) +FIELD(ID_AA64ISAR0, ATOMIC, 20, 4) +FIELD(ID_AA64ISAR0, TME, 24, 4) +FIELD(ID_AA64ISAR0, RDM, 28, 4) +FIELD(ID_AA64ISAR0, SHA3, 32, 4) +FIELD(ID_AA64ISAR0, SM3, 36, 4) +FIELD(ID_AA64ISAR0, SM4, 40, 4) +FIELD(ID_AA64ISAR0, DP, 44, 4) +FIELD(ID_AA64ISAR0, FHM, 48, 4) +FIELD(ID_AA64ISAR0, TS, 52, 4) +FIELD(ID_AA64ISAR0, TLB, 56, 4) +FIELD(ID_AA64ISAR0, RNDR, 60, 4) + +FIELD(ID_AA64ISAR1, DPB, 0, 4) +FIELD(ID_AA64ISAR1, APA, 4, 4) +FIELD(ID_AA64ISAR1, API, 8, 4) +FIELD(ID_AA64ISAR1, JSCVT, 12, 4) +FIELD(ID_AA64ISAR1, FCMA, 16, 4) +FIELD(ID_AA64ISAR1, LRCPC, 20, 4) +FIELD(ID_AA64ISAR1, GPA, 24, 4) +FIELD(ID_AA64ISAR1, GPI, 28, 4) +FIELD(ID_AA64ISAR1, FRINTTS, 32, 4) +FIELD(ID_AA64ISAR1, SB, 36, 4) +FIELD(ID_AA64ISAR1, SPECRES, 40, 4) +FIELD(ID_AA64ISAR1, BF16, 44, 4) +FIELD(ID_AA64ISAR1, DGH, 48, 4) +FIELD(ID_AA64ISAR1, I8MM, 52, 4) +FIELD(ID_AA64ISAR1, XS, 56, 4) +FIELD(ID_AA64ISAR1, LS64, 60, 4) + +FIELD(ID_AA64ISAR2, WFXT, 0, 4) +FIELD(ID_AA64ISAR2, RPRES, 4, 4) +FIELD(ID_AA64ISAR2, GPA3, 8, 4) +FIELD(ID_AA64ISAR2, APA3, 12, 4) +FIELD(ID_AA64ISAR2, MOPS, 16, 4) +FIELD(ID_AA64ISAR2, BC, 20, 4) +FIELD(ID_AA64ISAR2, PAC_FRAC, 24, 4) +FIELD(ID_AA64ISAR2, CLRBHB, 28, 4) +FIELD(ID_AA64ISAR2, SYSREG_128, 32, 4) +FIELD(ID_AA64ISAR2, SYSINSTR_128, 36, 4) +FIELD(ID_AA64ISAR2, PRFMSLC, 40, 4) +FIELD(ID_AA64ISAR2, RPRFM, 48, 4) +FIELD(ID_AA64ISAR2, CSSC, 52, 4) +FIELD(ID_AA64ISAR2, LUT, 56, 4) +FIELD(ID_AA64ISAR2, ATS1A, 60, 4) + +FIELD(ID_AA64PFR0, EL0, 0, 4) +FIELD(ID_AA64PFR0, EL1, 4, 4) +FIELD(ID_AA64PFR0, EL2, 8, 4) +FIELD(ID_AA64PFR0, EL3, 12, 4) +FIELD(ID_AA64PFR0, FP, 16, 4) +FIELD(ID_AA64PFR0, ADVSIMD, 20, 4) +FIELD(ID_AA64PFR0, GIC, 24, 4) +FIELD(ID_AA64PFR0, RAS, 28, 4) +FIELD(ID_AA64PFR0, SVE, 32, 4) +FIELD(ID_AA64PFR0, SEL2, 36, 4) +FIELD(ID_AA64PFR0, MPAM, 40, 4) +FIELD(ID_AA64PFR0, AMU, 44, 4) +FIELD(ID_AA64PFR0, DIT, 48, 4) +FIELD(ID_AA64PFR0, RME, 52, 4) +FIELD(ID_AA64PFR0, CSV2, 56, 4) +FIELD(ID_AA64PFR0, CSV3, 60, 4) + +FIELD(ID_AA64PFR1, BT, 0, 4) +FIELD(ID_AA64PFR1, SSBS, 4, 4) +FIELD(ID_AA64PFR1, MTE, 8, 4) +FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4) +FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4) +FIELD(ID_AA64PFR1, SME, 24, 4) +FIELD(ID_AA64PFR1, RNDR_TRAP, 28, 4) +FIELD(ID_AA64PFR1, CSV2_FRAC, 32, 4) +FIELD(ID_AA64PFR1, NMI, 36, 4) +FIELD(ID_AA64PFR1, MTE_FRAC, 40, 4) +FIELD(ID_AA64PFR1, GCS, 44, 4) +FIELD(ID_AA64PFR1, THE, 48, 4) +FIELD(ID_AA64PFR1, MTEX, 52, 4) +FIELD(ID_AA64PFR1, DF2, 56, 4) +FIELD(ID_AA64PFR1, PFAR, 60, 4) + +FIELD(ID_AA64PFR2, MTEPERM, 0, 4) +FIELD(ID_AA64PFR2, MTESTOREONLY, 4, 4) +FIELD(ID_AA64PFR2, MTEFAR, 8, 4) +FIELD(ID_AA64PFR2, FPMR, 32, 4) + +FIELD(ID_AA64MMFR0, PARANGE, 0, 4) +FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4) +FIELD(ID_AA64MMFR0, BIGEND, 8, 4) +FIELD(ID_AA64MMFR0, SNSMEM, 12, 4) +FIELD(ID_AA64MMFR0, BIGENDEL0, 16, 4) +FIELD(ID_AA64MMFR0, TGRAN16, 20, 4) +FIELD(ID_AA64MMFR0, TGRAN64, 24, 4) +FIELD(ID_AA64MMFR0, TGRAN4, 28, 4) +FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4) +FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4) +FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4) +FIELD(ID_AA64MMFR0, EXS, 44, 4) +FIELD(ID_AA64MMFR0, FGT, 56, 4) +FIELD(ID_AA64MMFR0, ECV, 60, 4) + +FIELD(ID_AA64MMFR1, HAFDBS, 0, 4) +FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4) +FIELD(ID_AA64MMFR1, VH, 8, 4) +FIELD(ID_AA64MMFR1, HPDS, 12, 4) +FIELD(ID_AA64MMFR1, LO, 16, 4) +FIELD(ID_AA64MMFR1, PAN, 20, 4) +FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) +FIELD(ID_AA64MMFR1, XNX, 28, 4) +FIELD(ID_AA64MMFR1, TWED, 32, 4) +FIELD(ID_AA64MMFR1, ETS, 36, 4) +FIELD(ID_AA64MMFR1, HCX, 40, 4) +FIELD(ID_AA64MMFR1, AFP, 44, 4) +FIELD(ID_AA64MMFR1, NTLBPA, 48, 4) +FIELD(ID_AA64MMFR1, TIDCP1, 52, 4) +FIELD(ID_AA64MMFR1, CMOW, 56, 4) +FIELD(ID_AA64MMFR1, ECBHB, 60, 4) + +FIELD(ID_AA64MMFR2, CNP, 0, 4) +FIELD(ID_AA64MMFR2, UAO, 4, 4) +FIELD(ID_AA64MMFR2, LSM, 8, 4) +FIELD(ID_AA64MMFR2, IESB, 12, 4) +FIELD(ID_AA64MMFR2, VARANGE, 16, 4) +FIELD(ID_AA64MMFR2, CCIDX, 20, 4) +FIELD(ID_AA64MMFR2, NV, 24, 4) +FIELD(ID_AA64MMFR2, ST, 28, 4) +FIELD(ID_AA64MMFR2, AT, 32, 4) +FIELD(ID_AA64MMFR2, IDS, 36, 4) +FIELD(ID_AA64MMFR2, FWB, 40, 4) +FIELD(ID_AA64MMFR2, TTL, 48, 4) +FIELD(ID_AA64MMFR2, BBM, 52, 4) +FIELD(ID_AA64MMFR2, EVT, 56, 4) +FIELD(ID_AA64MMFR2, E0PD, 60, 4) + +FIELD(ID_AA64MMFR3, TCRX, 0, 4) +FIELD(ID_AA64MMFR3, SCTLRX, 4, 4) +FIELD(ID_AA64MMFR3, S1PIE, 8, 4) +FIELD(ID_AA64MMFR3, S2PIE, 12, 4) +FIELD(ID_AA64MMFR3, S1POE, 16, 4) +FIELD(ID_AA64MMFR3, S2POE, 20, 4) +FIELD(ID_AA64MMFR3, AIE, 24, 4) +FIELD(ID_AA64MMFR3, MEC, 28, 4) +FIELD(ID_AA64MMFR3, D128, 32, 4) +FIELD(ID_AA64MMFR3, D128_2, 36, 4) +FIELD(ID_AA64MMFR3, SNERR, 40, 4) +FIELD(ID_AA64MMFR3, ANERR, 44, 4) +FIELD(ID_AA64MMFR3, SDERR, 52, 4) +FIELD(ID_AA64MMFR3, ADERR, 56, 4) +FIELD(ID_AA64MMFR3, SPEC_FPACC, 60, 4) + +FIELD(ID_AA64DFR0, DEBUGVER, 0, 4) +FIELD(ID_AA64DFR0, TRACEVER, 4, 4) +FIELD(ID_AA64DFR0, PMUVER, 8, 4) +FIELD(ID_AA64DFR0, BRPS, 12, 4) +FIELD(ID_AA64DFR0, PMSS, 16, 4) +FIELD(ID_AA64DFR0, WRPS, 20, 4) +FIELD(ID_AA64DFR0, SEBEP, 24, 4) +FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) +FIELD(ID_AA64DFR0, PMSVER, 32, 4) +FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) +FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) +FIELD(ID_AA64DFR0, TRACEBUFFER, 44, 4) +FIELD(ID_AA64DFR0, MTPMU, 48, 4) +FIELD(ID_AA64DFR0, BRBE, 52, 4) +FIELD(ID_AA64DFR0, EXTTRCBUFF, 56, 4) +FIELD(ID_AA64DFR0, HPMN0, 60, 4) + +FIELD(ID_AA64ZFR0, SVEVER, 0, 4) +FIELD(ID_AA64ZFR0, AES, 4, 4) +FIELD(ID_AA64ZFR0, BITPERM, 16, 4) +FIELD(ID_AA64ZFR0, BFLOAT16, 20, 4) +FIELD(ID_AA64ZFR0, B16B16, 24, 4) +FIELD(ID_AA64ZFR0, SHA3, 32, 4) +FIELD(ID_AA64ZFR0, SM4, 40, 4) +FIELD(ID_AA64ZFR0, I8MM, 44, 4) +FIELD(ID_AA64ZFR0, F32MM, 52, 4) +FIELD(ID_AA64ZFR0, F64MM, 56, 4) + +FIELD(ID_AA64SMFR0, F32F32, 32, 1) +FIELD(ID_AA64SMFR0, BI32I32, 33, 1) +FIELD(ID_AA64SMFR0, B16F32, 34, 1) +FIELD(ID_AA64SMFR0, F16F32, 35, 1) +FIELD(ID_AA64SMFR0, I8I32, 36, 4) +FIELD(ID_AA64SMFR0, F16F16, 42, 1) +FIELD(ID_AA64SMFR0, B16B16, 43, 1) +FIELD(ID_AA64SMFR0, I16I32, 44, 4) +FIELD(ID_AA64SMFR0, F64F64, 48, 1) +FIELD(ID_AA64SMFR0, I16I64, 52, 4) +FIELD(ID_AA64SMFR0, SMEVER, 56, 4) +FIELD(ID_AA64SMFR0, FA64, 63, 1) + +FIELD(ID_DFR0, COPDBG, 0, 4) +FIELD(ID_DFR0, COPSDBG, 4, 4) +FIELD(ID_DFR0, MMAPDBG, 8, 4) +FIELD(ID_DFR0, COPTRC, 12, 4) +FIELD(ID_DFR0, MMAPTRC, 16, 4) +FIELD(ID_DFR0, MPROFDBG, 20, 4) +FIELD(ID_DFR0, PERFMON, 24, 4) +FIELD(ID_DFR0, TRACEFILT, 28, 4) + +FIELD(ID_DFR1, MTPMU, 0, 4) +FIELD(ID_DFR1, HPMN0, 4, 4) + +FIELD(DBGDIDR, SE_IMP, 12, 1) +FIELD(DBGDIDR, NSUHD_IMP, 14, 1) +FIELD(DBGDIDR, VERSION, 16, 4) +FIELD(DBGDIDR, CTX_CMPS, 20, 4) +FIELD(DBGDIDR, BRPS, 24, 4) +FIELD(DBGDIDR, WRPS, 28, 4) + +FIELD(DBGDEVID, PCSAMPLE, 0, 4) +FIELD(DBGDEVID, WPADDRMASK, 4, 4) +FIELD(DBGDEVID, BPADDRMASK, 8, 4) +FIELD(DBGDEVID, VECTORCATCH, 12, 4) +FIELD(DBGDEVID, VIRTEXTNS, 16, 4) +FIELD(DBGDEVID, DOUBLELOCK, 20, 4) +FIELD(DBGDEVID, AUXREGS, 24, 4) +FIELD(DBGDEVID, CIDMASK, 28, 4) + +FIELD(DBGDEVID1, PCSROFFSET, 0, 4) + +FIELD(MVFR0, SIMDREG, 0, 4) +FIELD(MVFR0, FPSP, 4, 4) +FIELD(MVFR0, FPDP, 8, 4) +FIELD(MVFR0, FPTRAP, 12, 4) +FIELD(MVFR0, FPDIVIDE, 16, 4) +FIELD(MVFR0, FPSQRT, 20, 4) +FIELD(MVFR0, FPSHVEC, 24, 4) +FIELD(MVFR0, FPROUND, 28, 4) + +FIELD(MVFR1, FPFTZ, 0, 4) +FIELD(MVFR1, FPDNAN, 4, 4) +FIELD(MVFR1, SIMDLS, 8, 4) /* A-profile only */ +FIELD(MVFR1, SIMDINT, 12, 4) /* A-profile only */ +FIELD(MVFR1, SIMDSP, 16, 4) /* A-profile only */ +FIELD(MVFR1, SIMDHP, 20, 4) /* A-profile only */ +FIELD(MVFR1, MVE, 8, 4) /* M-profile only */ +FIELD(MVFR1, FP16, 20, 4) /* M-profile only */ +FIELD(MVFR1, FPHP, 24, 4) +FIELD(MVFR1, SIMDFMAC, 28, 4) + +FIELD(MVFR2, SIMDMISC, 0, 4) +FIELD(MVFR2, FPMISC, 4, 4) + +/* * Naming convention for isar_feature functions: * Functions which test 32-bit ID registers should have _aa32_ in * their name. Functions which test 64-bit ID registers should have diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc index f48a9da..2bb2861 100644 --- a/target/arm/cpu-sysregs.h.inc +++ b/target/arm/cpu-sysregs.h.inc @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ DEF(ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) DEF(ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) +DEF(ID_AA64PFR2_EL1, 3, 0, 0, 4, 2) DEF(ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5) DEF(ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) DEF(ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index c65af7e..30e29fd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -52,6 +52,8 @@ #include "target/arm/cpu-qom.h" #include "target/arm/gtimer.h" +#include "trace.h" + static void arm_cpu_set_pc(CPUState *cs, vaddr value) { ARMCPU *cpu = ARM_CPU(cs); @@ -192,14 +194,8 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) * This is basically only used for fields in non-core coprocessors * (like the pxa2xx ones). */ - if (!ri->fieldoffset) { - return; - } - - if (cpreg_field_is_64bit(ri)) { - CPREG_FIELD64(&cpu->env, ri) = ri->resetvalue; - } else { - CPREG_FIELD32(&cpu->env, ri) = ri->resetvalue; + if (ri->fieldoffset) { + raw_write(&cpu->env, ri, ri->resetvalue); } } @@ -231,6 +227,8 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type) ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); CPUARMState *env = &cpu->env; + trace_arm_cpu_reset(arm_cpu_mp_affinity(cpu)); + if (acc->parent_phases.hold) { acc->parent_phases.hold(obj, type); } @@ -580,6 +578,8 @@ void arm_emulate_firmware_reset(CPUState *cpustate, int target_el) bool have_el3 = arm_feature(env, ARM_FEATURE_EL3); bool have_el2 = arm_feature(env, ARM_FEATURE_EL2); + trace_arm_emulate_firmware_reset(arm_cpu_mp_affinity(cpu), target_el); + /* * Check we have the EL we're aiming for. If that is the * highest implemented EL, then cpu_reset has already done diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 1c0deb7..2b9585d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1994,416 +1994,6 @@ FIELD(V7M_VPR, P0, 0, 16) FIELD(V7M_VPR, MASK01, 16, 4) FIELD(V7M_VPR, MASK23, 20, 4) -/* - * System register ID fields. - */ -FIELD(CLIDR_EL1, CTYPE1, 0, 3) -FIELD(CLIDR_EL1, CTYPE2, 3, 3) -FIELD(CLIDR_EL1, CTYPE3, 6, 3) -FIELD(CLIDR_EL1, CTYPE4, 9, 3) -FIELD(CLIDR_EL1, CTYPE5, 12, 3) -FIELD(CLIDR_EL1, CTYPE6, 15, 3) -FIELD(CLIDR_EL1, CTYPE7, 18, 3) -FIELD(CLIDR_EL1, LOUIS, 21, 3) -FIELD(CLIDR_EL1, LOC, 24, 3) -FIELD(CLIDR_EL1, LOUU, 27, 3) -FIELD(CLIDR_EL1, ICB, 30, 3) - -/* When FEAT_CCIDX is implemented */ -FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3) -FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21) -FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24) - -/* When FEAT_CCIDX is not implemented */ -FIELD(CCSIDR_EL1, LINESIZE, 0, 3) -FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10) -FIELD(CCSIDR_EL1, NUMSETS, 13, 15) - -FIELD(CTR_EL0, IMINLINE, 0, 4) -FIELD(CTR_EL0, L1IP, 14, 2) -FIELD(CTR_EL0, DMINLINE, 16, 4) -FIELD(CTR_EL0, ERG, 20, 4) -FIELD(CTR_EL0, CWG, 24, 4) -FIELD(CTR_EL0, IDC, 28, 1) -FIELD(CTR_EL0, DIC, 29, 1) -FIELD(CTR_EL0, TMINLINE, 32, 6) - -FIELD(MIDR_EL1, REVISION, 0, 4) -FIELD(MIDR_EL1, PARTNUM, 4, 12) -FIELD(MIDR_EL1, ARCHITECTURE, 16, 4) -FIELD(MIDR_EL1, VARIANT, 20, 4) -FIELD(MIDR_EL1, IMPLEMENTER, 24, 8) - -FIELD(ID_ISAR0, SWAP, 0, 4) -FIELD(ID_ISAR0, BITCOUNT, 4, 4) -FIELD(ID_ISAR0, BITFIELD, 8, 4) -FIELD(ID_ISAR0, CMPBRANCH, 12, 4) -FIELD(ID_ISAR0, COPROC, 16, 4) -FIELD(ID_ISAR0, DEBUG, 20, 4) -FIELD(ID_ISAR0, DIVIDE, 24, 4) - -FIELD(ID_ISAR1, ENDIAN, 0, 4) -FIELD(ID_ISAR1, EXCEPT, 4, 4) -FIELD(ID_ISAR1, EXCEPT_AR, 8, 4) -FIELD(ID_ISAR1, EXTEND, 12, 4) -FIELD(ID_ISAR1, IFTHEN, 16, 4) -FIELD(ID_ISAR1, IMMEDIATE, 20, 4) -FIELD(ID_ISAR1, INTERWORK, 24, 4) -FIELD(ID_ISAR1, JAZELLE, 28, 4) - -FIELD(ID_ISAR2, LOADSTORE, 0, 4) -FIELD(ID_ISAR2, MEMHINT, 4, 4) -FIELD(ID_ISAR2, MULTIACCESSINT, 8, 4) -FIELD(ID_ISAR2, MULT, 12, 4) -FIELD(ID_ISAR2, MULTS, 16, 4) -FIELD(ID_ISAR2, MULTU, 20, 4) -FIELD(ID_ISAR2, PSR_AR, 24, 4) -FIELD(ID_ISAR2, REVERSAL, 28, 4) - -FIELD(ID_ISAR3, SATURATE, 0, 4) -FIELD(ID_ISAR3, SIMD, 4, 4) -FIELD(ID_ISAR3, SVC, 8, 4) -FIELD(ID_ISAR3, SYNCHPRIM, 12, 4) -FIELD(ID_ISAR3, TABBRANCH, 16, 4) -FIELD(ID_ISAR3, T32COPY, 20, 4) -FIELD(ID_ISAR3, TRUENOP, 24, 4) -FIELD(ID_ISAR3, T32EE, 28, 4) - -FIELD(ID_ISAR4, UNPRIV, 0, 4) -FIELD(ID_ISAR4, WITHSHIFTS, 4, 4) -FIELD(ID_ISAR4, WRITEBACK, 8, 4) -FIELD(ID_ISAR4, SMC, 12, 4) -FIELD(ID_ISAR4, BARRIER, 16, 4) -FIELD(ID_ISAR4, SYNCHPRIM_FRAC, 20, 4) -FIELD(ID_ISAR4, PSR_M, 24, 4) -FIELD(ID_ISAR4, SWP_FRAC, 28, 4) - -FIELD(ID_ISAR5, SEVL, 0, 4) -FIELD(ID_ISAR5, AES, 4, 4) -FIELD(ID_ISAR5, SHA1, 8, 4) -FIELD(ID_ISAR5, SHA2, 12, 4) -FIELD(ID_ISAR5, CRC32, 16, 4) -FIELD(ID_ISAR5, RDM, 24, 4) -FIELD(ID_ISAR5, VCMA, 28, 4) - -FIELD(ID_ISAR6, JSCVT, 0, 4) -FIELD(ID_ISAR6, DP, 4, 4) -FIELD(ID_ISAR6, FHM, 8, 4) -FIELD(ID_ISAR6, SB, 12, 4) -FIELD(ID_ISAR6, SPECRES, 16, 4) -FIELD(ID_ISAR6, BF16, 20, 4) -FIELD(ID_ISAR6, I8MM, 24, 4) - -FIELD(ID_MMFR0, VMSA, 0, 4) -FIELD(ID_MMFR0, PMSA, 4, 4) -FIELD(ID_MMFR0, OUTERSHR, 8, 4) -FIELD(ID_MMFR0, SHARELVL, 12, 4) -FIELD(ID_MMFR0, TCM, 16, 4) -FIELD(ID_MMFR0, AUXREG, 20, 4) -FIELD(ID_MMFR0, FCSE, 24, 4) -FIELD(ID_MMFR0, INNERSHR, 28, 4) - -FIELD(ID_MMFR1, L1HVDVA, 0, 4) -FIELD(ID_MMFR1, L1UNIVA, 4, 4) -FIELD(ID_MMFR1, L1HVDSW, 8, 4) -FIELD(ID_MMFR1, L1UNISW, 12, 4) -FIELD(ID_MMFR1, L1HVD, 16, 4) -FIELD(ID_MMFR1, L1UNI, 20, 4) -FIELD(ID_MMFR1, L1TSTCLN, 24, 4) -FIELD(ID_MMFR1, BPRED, 28, 4) - -FIELD(ID_MMFR2, L1HVDFG, 0, 4) -FIELD(ID_MMFR2, L1HVDBG, 4, 4) -FIELD(ID_MMFR2, L1HVDRNG, 8, 4) -FIELD(ID_MMFR2, HVDTLB, 12, 4) -FIELD(ID_MMFR2, UNITLB, 16, 4) -FIELD(ID_MMFR2, MEMBARR, 20, 4) -FIELD(ID_MMFR2, WFISTALL, 24, 4) -FIELD(ID_MMFR2, HWACCFLG, 28, 4) - -FIELD(ID_MMFR3, CMAINTVA, 0, 4) -FIELD(ID_MMFR3, CMAINTSW, 4, 4) -FIELD(ID_MMFR3, BPMAINT, 8, 4) -FIELD(ID_MMFR3, MAINTBCST, 12, 4) -FIELD(ID_MMFR3, PAN, 16, 4) -FIELD(ID_MMFR3, COHWALK, 20, 4) -FIELD(ID_MMFR3, CMEMSZ, 24, 4) -FIELD(ID_MMFR3, SUPERSEC, 28, 4) - -FIELD(ID_MMFR4, SPECSEI, 0, 4) -FIELD(ID_MMFR4, AC2, 4, 4) -FIELD(ID_MMFR4, XNX, 8, 4) -FIELD(ID_MMFR4, CNP, 12, 4) -FIELD(ID_MMFR4, HPDS, 16, 4) -FIELD(ID_MMFR4, LSM, 20, 4) -FIELD(ID_MMFR4, CCIDX, 24, 4) -FIELD(ID_MMFR4, EVT, 28, 4) - -FIELD(ID_MMFR5, ETS, 0, 4) -FIELD(ID_MMFR5, NTLBPA, 4, 4) - -FIELD(ID_PFR0, STATE0, 0, 4) -FIELD(ID_PFR0, STATE1, 4, 4) -FIELD(ID_PFR0, STATE2, 8, 4) -FIELD(ID_PFR0, STATE3, 12, 4) -FIELD(ID_PFR0, CSV2, 16, 4) -FIELD(ID_PFR0, AMU, 20, 4) -FIELD(ID_PFR0, DIT, 24, 4) -FIELD(ID_PFR0, RAS, 28, 4) - -FIELD(ID_PFR1, PROGMOD, 0, 4) -FIELD(ID_PFR1, SECURITY, 4, 4) -FIELD(ID_PFR1, MPROGMOD, 8, 4) -FIELD(ID_PFR1, VIRTUALIZATION, 12, 4) -FIELD(ID_PFR1, GENTIMER, 16, 4) -FIELD(ID_PFR1, SEC_FRAC, 20, 4) -FIELD(ID_PFR1, VIRT_FRAC, 24, 4) -FIELD(ID_PFR1, GIC, 28, 4) - -FIELD(ID_PFR2, CSV3, 0, 4) -FIELD(ID_PFR2, SSBS, 4, 4) -FIELD(ID_PFR2, RAS_FRAC, 8, 4) - -FIELD(ID_AA64ISAR0, AES, 4, 4) -FIELD(ID_AA64ISAR0, SHA1, 8, 4) -FIELD(ID_AA64ISAR0, SHA2, 12, 4) -FIELD(ID_AA64ISAR0, CRC32, 16, 4) -FIELD(ID_AA64ISAR0, ATOMIC, 20, 4) -FIELD(ID_AA64ISAR0, TME, 24, 4) -FIELD(ID_AA64ISAR0, RDM, 28, 4) -FIELD(ID_AA64ISAR0, SHA3, 32, 4) -FIELD(ID_AA64ISAR0, SM3, 36, 4) -FIELD(ID_AA64ISAR0, SM4, 40, 4) -FIELD(ID_AA64ISAR0, DP, 44, 4) -FIELD(ID_AA64ISAR0, FHM, 48, 4) -FIELD(ID_AA64ISAR0, TS, 52, 4) -FIELD(ID_AA64ISAR0, TLB, 56, 4) -FIELD(ID_AA64ISAR0, RNDR, 60, 4) - -FIELD(ID_AA64ISAR1, DPB, 0, 4) -FIELD(ID_AA64ISAR1, APA, 4, 4) -FIELD(ID_AA64ISAR1, API, 8, 4) -FIELD(ID_AA64ISAR1, JSCVT, 12, 4) -FIELD(ID_AA64ISAR1, FCMA, 16, 4) -FIELD(ID_AA64ISAR1, LRCPC, 20, 4) -FIELD(ID_AA64ISAR1, GPA, 24, 4) -FIELD(ID_AA64ISAR1, GPI, 28, 4) -FIELD(ID_AA64ISAR1, FRINTTS, 32, 4) -FIELD(ID_AA64ISAR1, SB, 36, 4) -FIELD(ID_AA64ISAR1, SPECRES, 40, 4) -FIELD(ID_AA64ISAR1, BF16, 44, 4) -FIELD(ID_AA64ISAR1, DGH, 48, 4) -FIELD(ID_AA64ISAR1, I8MM, 52, 4) -FIELD(ID_AA64ISAR1, XS, 56, 4) -FIELD(ID_AA64ISAR1, LS64, 60, 4) - -FIELD(ID_AA64ISAR2, WFXT, 0, 4) -FIELD(ID_AA64ISAR2, RPRES, 4, 4) -FIELD(ID_AA64ISAR2, GPA3, 8, 4) -FIELD(ID_AA64ISAR2, APA3, 12, 4) -FIELD(ID_AA64ISAR2, MOPS, 16, 4) -FIELD(ID_AA64ISAR2, BC, 20, 4) -FIELD(ID_AA64ISAR2, PAC_FRAC, 24, 4) -FIELD(ID_AA64ISAR2, CLRBHB, 28, 4) -FIELD(ID_AA64ISAR2, SYSREG_128, 32, 4) -FIELD(ID_AA64ISAR2, SYSINSTR_128, 36, 4) -FIELD(ID_AA64ISAR2, PRFMSLC, 40, 4) -FIELD(ID_AA64ISAR2, RPRFM, 48, 4) -FIELD(ID_AA64ISAR2, CSSC, 52, 4) -FIELD(ID_AA64ISAR2, LUT, 56, 4) -FIELD(ID_AA64ISAR2, ATS1A, 60, 4) - -FIELD(ID_AA64PFR0, EL0, 0, 4) -FIELD(ID_AA64PFR0, EL1, 4, 4) -FIELD(ID_AA64PFR0, EL2, 8, 4) -FIELD(ID_AA64PFR0, EL3, 12, 4) -FIELD(ID_AA64PFR0, FP, 16, 4) -FIELD(ID_AA64PFR0, ADVSIMD, 20, 4) -FIELD(ID_AA64PFR0, GIC, 24, 4) -FIELD(ID_AA64PFR0, RAS, 28, 4) -FIELD(ID_AA64PFR0, SVE, 32, 4) -FIELD(ID_AA64PFR0, SEL2, 36, 4) -FIELD(ID_AA64PFR0, MPAM, 40, 4) -FIELD(ID_AA64PFR0, AMU, 44, 4) -FIELD(ID_AA64PFR0, DIT, 48, 4) -FIELD(ID_AA64PFR0, RME, 52, 4) -FIELD(ID_AA64PFR0, CSV2, 56, 4) -FIELD(ID_AA64PFR0, CSV3, 60, 4) - -FIELD(ID_AA64PFR1, BT, 0, 4) -FIELD(ID_AA64PFR1, SSBS, 4, 4) -FIELD(ID_AA64PFR1, MTE, 8, 4) -FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4) -FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4) -FIELD(ID_AA64PFR1, SME, 24, 4) -FIELD(ID_AA64PFR1, RNDR_TRAP, 28, 4) -FIELD(ID_AA64PFR1, CSV2_FRAC, 32, 4) -FIELD(ID_AA64PFR1, NMI, 36, 4) -FIELD(ID_AA64PFR1, MTE_FRAC, 40, 4) -FIELD(ID_AA64PFR1, GCS, 44, 4) -FIELD(ID_AA64PFR1, THE, 48, 4) -FIELD(ID_AA64PFR1, MTEX, 52, 4) -FIELD(ID_AA64PFR1, DF2, 56, 4) -FIELD(ID_AA64PFR1, PFAR, 60, 4) - -FIELD(ID_AA64MMFR0, PARANGE, 0, 4) -FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4) -FIELD(ID_AA64MMFR0, BIGEND, 8, 4) -FIELD(ID_AA64MMFR0, SNSMEM, 12, 4) -FIELD(ID_AA64MMFR0, BIGENDEL0, 16, 4) -FIELD(ID_AA64MMFR0, TGRAN16, 20, 4) -FIELD(ID_AA64MMFR0, TGRAN64, 24, 4) -FIELD(ID_AA64MMFR0, TGRAN4, 28, 4) -FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4) -FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4) -FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4) -FIELD(ID_AA64MMFR0, EXS, 44, 4) -FIELD(ID_AA64MMFR0, FGT, 56, 4) -FIELD(ID_AA64MMFR0, ECV, 60, 4) - -FIELD(ID_AA64MMFR1, HAFDBS, 0, 4) -FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4) -FIELD(ID_AA64MMFR1, VH, 8, 4) -FIELD(ID_AA64MMFR1, HPDS, 12, 4) -FIELD(ID_AA64MMFR1, LO, 16, 4) -FIELD(ID_AA64MMFR1, PAN, 20, 4) -FIELD(ID_AA64MMFR1, SPECSEI, 24, 4) -FIELD(ID_AA64MMFR1, XNX, 28, 4) -FIELD(ID_AA64MMFR1, TWED, 32, 4) -FIELD(ID_AA64MMFR1, ETS, 36, 4) -FIELD(ID_AA64MMFR1, HCX, 40, 4) -FIELD(ID_AA64MMFR1, AFP, 44, 4) -FIELD(ID_AA64MMFR1, NTLBPA, 48, 4) -FIELD(ID_AA64MMFR1, TIDCP1, 52, 4) -FIELD(ID_AA64MMFR1, CMOW, 56, 4) -FIELD(ID_AA64MMFR1, ECBHB, 60, 4) - -FIELD(ID_AA64MMFR2, CNP, 0, 4) -FIELD(ID_AA64MMFR2, UAO, 4, 4) -FIELD(ID_AA64MMFR2, LSM, 8, 4) -FIELD(ID_AA64MMFR2, IESB, 12, 4) -FIELD(ID_AA64MMFR2, VARANGE, 16, 4) -FIELD(ID_AA64MMFR2, CCIDX, 20, 4) -FIELD(ID_AA64MMFR2, NV, 24, 4) -FIELD(ID_AA64MMFR2, ST, 28, 4) -FIELD(ID_AA64MMFR2, AT, 32, 4) -FIELD(ID_AA64MMFR2, IDS, 36, 4) -FIELD(ID_AA64MMFR2, FWB, 40, 4) -FIELD(ID_AA64MMFR2, TTL, 48, 4) -FIELD(ID_AA64MMFR2, BBM, 52, 4) -FIELD(ID_AA64MMFR2, EVT, 56, 4) -FIELD(ID_AA64MMFR2, E0PD, 60, 4) - -FIELD(ID_AA64MMFR3, TCRX, 0, 4) -FIELD(ID_AA64MMFR3, SCTLRX, 4, 4) -FIELD(ID_AA64MMFR3, S1PIE, 8, 4) -FIELD(ID_AA64MMFR3, S2PIE, 12, 4) -FIELD(ID_AA64MMFR3, S1POE, 16, 4) -FIELD(ID_AA64MMFR3, S2POE, 20, 4) -FIELD(ID_AA64MMFR3, AIE, 24, 4) -FIELD(ID_AA64MMFR3, MEC, 28, 4) -FIELD(ID_AA64MMFR3, D128, 32, 4) -FIELD(ID_AA64MMFR3, D128_2, 36, 4) -FIELD(ID_AA64MMFR3, SNERR, 40, 4) -FIELD(ID_AA64MMFR3, ANERR, 44, 4) -FIELD(ID_AA64MMFR3, SDERR, 52, 4) -FIELD(ID_AA64MMFR3, ADERR, 56, 4) -FIELD(ID_AA64MMFR3, SPEC_FPACC, 60, 4) - -FIELD(ID_AA64DFR0, DEBUGVER, 0, 4) -FIELD(ID_AA64DFR0, TRACEVER, 4, 4) -FIELD(ID_AA64DFR0, PMUVER, 8, 4) -FIELD(ID_AA64DFR0, BRPS, 12, 4) -FIELD(ID_AA64DFR0, PMSS, 16, 4) -FIELD(ID_AA64DFR0, WRPS, 20, 4) -FIELD(ID_AA64DFR0, SEBEP, 24, 4) -FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4) -FIELD(ID_AA64DFR0, PMSVER, 32, 4) -FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4) -FIELD(ID_AA64DFR0, TRACEFILT, 40, 4) -FIELD(ID_AA64DFR0, TRACEBUFFER, 44, 4) -FIELD(ID_AA64DFR0, MTPMU, 48, 4) -FIELD(ID_AA64DFR0, BRBE, 52, 4) -FIELD(ID_AA64DFR0, EXTTRCBUFF, 56, 4) -FIELD(ID_AA64DFR0, HPMN0, 60, 4) - -FIELD(ID_AA64ZFR0, SVEVER, 0, 4) -FIELD(ID_AA64ZFR0, AES, 4, 4) -FIELD(ID_AA64ZFR0, BITPERM, 16, 4) -FIELD(ID_AA64ZFR0, BFLOAT16, 20, 4) -FIELD(ID_AA64ZFR0, B16B16, 24, 4) -FIELD(ID_AA64ZFR0, SHA3, 32, 4) -FIELD(ID_AA64ZFR0, SM4, 40, 4) -FIELD(ID_AA64ZFR0, I8MM, 44, 4) -FIELD(ID_AA64ZFR0, F32MM, 52, 4) -FIELD(ID_AA64ZFR0, F64MM, 56, 4) - -FIELD(ID_AA64SMFR0, F32F32, 32, 1) -FIELD(ID_AA64SMFR0, BI32I32, 33, 1) -FIELD(ID_AA64SMFR0, B16F32, 34, 1) -FIELD(ID_AA64SMFR0, F16F32, 35, 1) -FIELD(ID_AA64SMFR0, I8I32, 36, 4) -FIELD(ID_AA64SMFR0, F16F16, 42, 1) -FIELD(ID_AA64SMFR0, B16B16, 43, 1) -FIELD(ID_AA64SMFR0, I16I32, 44, 4) -FIELD(ID_AA64SMFR0, F64F64, 48, 1) -FIELD(ID_AA64SMFR0, I16I64, 52, 4) -FIELD(ID_AA64SMFR0, SMEVER, 56, 4) -FIELD(ID_AA64SMFR0, FA64, 63, 1) - -FIELD(ID_DFR0, COPDBG, 0, 4) -FIELD(ID_DFR0, COPSDBG, 4, 4) -FIELD(ID_DFR0, MMAPDBG, 8, 4) -FIELD(ID_DFR0, COPTRC, 12, 4) -FIELD(ID_DFR0, MMAPTRC, 16, 4) -FIELD(ID_DFR0, MPROFDBG, 20, 4) -FIELD(ID_DFR0, PERFMON, 24, 4) -FIELD(ID_DFR0, TRACEFILT, 28, 4) - -FIELD(ID_DFR1, MTPMU, 0, 4) -FIELD(ID_DFR1, HPMN0, 4, 4) - -FIELD(DBGDIDR, SE_IMP, 12, 1) -FIELD(DBGDIDR, NSUHD_IMP, 14, 1) -FIELD(DBGDIDR, VERSION, 16, 4) -FIELD(DBGDIDR, CTX_CMPS, 20, 4) -FIELD(DBGDIDR, BRPS, 24, 4) -FIELD(DBGDIDR, WRPS, 28, 4) - -FIELD(DBGDEVID, PCSAMPLE, 0, 4) -FIELD(DBGDEVID, WPADDRMASK, 4, 4) -FIELD(DBGDEVID, BPADDRMASK, 8, 4) -FIELD(DBGDEVID, VECTORCATCH, 12, 4) -FIELD(DBGDEVID, VIRTEXTNS, 16, 4) -FIELD(DBGDEVID, DOUBLELOCK, 20, 4) -FIELD(DBGDEVID, AUXREGS, 24, 4) -FIELD(DBGDEVID, CIDMASK, 28, 4) - -FIELD(DBGDEVID1, PCSROFFSET, 0, 4) - -FIELD(MVFR0, SIMDREG, 0, 4) -FIELD(MVFR0, FPSP, 4, 4) -FIELD(MVFR0, FPDP, 8, 4) -FIELD(MVFR0, FPTRAP, 12, 4) -FIELD(MVFR0, FPDIVIDE, 16, 4) -FIELD(MVFR0, FPSQRT, 20, 4) -FIELD(MVFR0, FPSHVEC, 24, 4) -FIELD(MVFR0, FPROUND, 28, 4) - -FIELD(MVFR1, FPFTZ, 0, 4) -FIELD(MVFR1, FPDNAN, 4, 4) -FIELD(MVFR1, SIMDLS, 8, 4) /* A-profile only */ -FIELD(MVFR1, SIMDINT, 12, 4) /* A-profile only */ -FIELD(MVFR1, SIMDSP, 16, 4) /* A-profile only */ -FIELD(MVFR1, SIMDHP, 20, 4) /* A-profile only */ -FIELD(MVFR1, MVE, 8, 4) /* M-profile only */ -FIELD(MVFR1, FP16, 20, 4) /* M-profile only */ -FIELD(MVFR1, FPHP, 24, 4) -FIELD(MVFR1, SIMDFMAC, 28, 4) - -FIELD(MVFR2, SIMDMISC, 0, 4) -FIELD(MVFR2, FPMISC, 4, 4) - FIELD(GPCCR, PPS, 0, 3) FIELD(GPCCR, IRGN, 8, 2) FIELD(GPCCR, ORGN, 10, 2) @@ -3065,8 +2655,7 @@ FIELD(TBFLAG_A64, ATA0, 31, 1) FIELD(TBFLAG_A64, NV, 32, 1) FIELD(TBFLAG_A64, NV1, 33, 1) FIELD(TBFLAG_A64, NV2, 34, 1) -/* Set if FEAT_NV2 RAM accesses use the EL2&0 translation regime */ -FIELD(TBFLAG_A64, NV2_MEM_E20, 35, 1) +FIELD(TBFLAG_A64, E2H, 35, 1) /* Set if FEAT_NV2 RAM accesses are big-endian */ FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1) FIELD(TBFLAG_A64, AH, 37, 1) /* FPCR.AH */ diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 2d331ff..8d2229f 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -247,10 +247,20 @@ static int arm_gdb_get_sysreg(CPUState *cs, GByteArray *buf, int reg) key = cpu->dyn_sysreg_feature.data.cpregs.keys[reg]; ri = get_arm_cp_reginfo(cpu->cp_regs, key); if (ri) { - if (cpreg_field_is_64bit(ri)) { + switch (cpreg_field_type(ri)) { + case MO_64: + if (ri->vhe_redir_to_el2 && + (arm_hcr_el2_eff(env) & HCR_E2H) && + arm_current_el(env) == 2) { + ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el2); + } else if (ri->vhe_redir_to_el01) { + ri = get_arm_cp_reginfo(cpu->cp_regs, ri->vhe_redir_to_el01); + } return gdb_get_reg64(buf, (uint64_t)read_raw_cp_reg(env, ri)); - } else { + case MO_32: return gdb_get_reg32(buf, (uint32_t)read_raw_cp_reg(env, ri)); + default: + g_assert_not_reached(); } } return 0; diff --git a/target/arm/helper.c b/target/arm/helper.c index c442947..aa730ad 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -40,26 +40,57 @@ static void switch_mode(CPUARMState *env, int mode); +int compare_u64(const void *a, const void *b) +{ + if (*(uint64_t *)a > *(uint64_t *)b) { + return 1; + } + if (*(uint64_t *)a < *(uint64_t *)b) { + return -1; + } + return 0; +} + +/* + * 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)) + uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri) { assert(ri->fieldoffset); - if (cpreg_field_is_64bit(ri)) { + switch (cpreg_field_type(ri)) { + case MO_64: return CPREG_FIELD64(env, ri); - } else { + case MO_32: return CPREG_FIELD32(env, ri); + default: + g_assert_not_reached(); } } void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { assert(ri->fieldoffset); - if (cpreg_field_is_64bit(ri)) { + switch (cpreg_field_type(ri)) { + case MO_64: CPREG_FIELD64(env, ri) = value; - } else { + break; + case MO_32: CPREG_FIELD32(env, ri) = value; + break; + default: + g_assert_not_reached(); } } +#undef CPREG_FIELD32 +#undef CPREG_FIELD64 + static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri) { return (char *)env + ri->fieldoffset; @@ -198,11 +229,11 @@ bool write_list_to_cpustate(ARMCPU *cpu) return ok; } -static void add_cpreg_to_list(gpointer key, gpointer opaque) +static void add_cpreg_to_list(gpointer key, gpointer value, gpointer opaque) { ARMCPU *cpu = opaque; uint32_t regidx = (uintptr_t)key; - const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); + const ARMCPRegInfo *ri = value; if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) { cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx); @@ -211,61 +242,49 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque) } } -static void count_cpreg(gpointer key, gpointer opaque) +static void count_cpreg(gpointer key, gpointer value, gpointer opaque) { ARMCPU *cpu = opaque; - const ARMCPRegInfo *ri; - - ri = g_hash_table_lookup(cpu->cp_regs, key); + const ARMCPRegInfo *ri = value; if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_ALIAS))) { cpu->cpreg_array_len++; } } -static gint cpreg_key_compare(gconstpointer a, gconstpointer b, gpointer d) -{ - uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a); - uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b); - - if (aidx > bidx) { - return 1; - } - if (aidx < bidx) { - return -1; - } - return 0; -} - void init_cpreg_list(ARMCPU *cpu) { /* * Initialise the cpreg_tuples[] array based on the cp_regs hash. * Note that we require cpreg_tuples[] to be sorted by key ID. */ - GList *keys; int arraylen; - keys = g_hash_table_get_keys(cpu->cp_regs); - keys = g_list_sort_with_data(keys, cpreg_key_compare, NULL); - cpu->cpreg_array_len = 0; - - g_list_foreach(keys, count_cpreg, cpu); + g_hash_table_foreach(cpu->cp_regs, count_cpreg, cpu); arraylen = cpu->cpreg_array_len; - cpu->cpreg_indexes = g_new(uint64_t, arraylen); - cpu->cpreg_values = g_new(uint64_t, arraylen); - cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen); - cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen); - cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len; + if (arraylen) { + cpu->cpreg_indexes = g_new(uint64_t, arraylen); + cpu->cpreg_values = g_new(uint64_t, arraylen); + cpu->cpreg_vmstate_indexes = g_new(uint64_t, arraylen); + cpu->cpreg_vmstate_values = g_new(uint64_t, arraylen); + } else { + cpu->cpreg_indexes = NULL; + cpu->cpreg_values = NULL; + cpu->cpreg_vmstate_indexes = NULL; + cpu->cpreg_vmstate_values = NULL; + } + cpu->cpreg_vmstate_array_len = arraylen; cpu->cpreg_array_len = 0; - g_list_foreach(keys, add_cpreg_to_list, cpu); + g_hash_table_foreach(cpu->cp_regs, add_cpreg_to_list, cpu); assert(cpu->cpreg_array_len == arraylen); - g_list_free(keys); + if (arraylen) { + qsort(cpu->cpreg_indexes, arraylen, sizeof(uint64_t), compare_u64); + } } bool arm_pan_enabled(CPUARMState *env) @@ -435,6 +454,8 @@ static const ARMCPRegInfo cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_CONTEXTIDR_EL1, .nv2_redirect_offset = 0x108 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 13, 0, 1), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 13, 0, 1), .secure = ARM_CP_SECSTATE_NS, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, @@ -652,9 +673,11 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { */ { .name = "WFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, }, - { .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, + { .name = "CPACR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access, .fgt = FGT_CPACR_EL1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 1, 2), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 0, 2), .nv2_redirect_offset = 0x100 | NV2_REDIR_NV1, .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1), .resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read }, @@ -937,12 +960,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_AFSR0_EL1, .nv2_redirect_offset = 0x128 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 1, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 1, 0), .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1, .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_AFSR1_EL1, .nv2_redirect_offset = 0x130 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 1, 1), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 1, 1), .type = ARM_CP_CONST, .resetvalue = 0 }, /* * MAIR can just read-as-written because we don't implement caches @@ -953,6 +980,8 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_MAIR_EL1, .nv2_redirect_offset = 0x140 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 2, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 2, 0), .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), .resetvalue = 0 }, { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64, @@ -1062,7 +1091,7 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { .resetvalue = 0 }, }; -static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *opaque) +static void arm_gt_cntfrq_reset(CPUARMState *env, const ARMCPRegInfo *ri) { ARMCPU *cpu = env_archcpu(env); @@ -1999,9 +2028,11 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .resetfn = arm_gt_cntfrq_reset, }, /* overall control: mostly access permissions */ - { .name = "CNTKCTL", .state = ARM_CP_STATE_BOTH, + { .name = "CNTKCTL_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 14, .crm = 1, .opc2 = 0, .access = PL1_RW, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 14, 1, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 14, 1, 0), .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl), .resetvalue = 0, }, @@ -2731,7 +2762,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { /* If the ASID changes (with a 64-bit write), we must flush the TLB. */ - if (cpreg_field_is_64bit(ri) && + if (cpreg_field_type(ri) == MO_64 && extract64(raw_read(env, ri) ^ value, 48, 16) != 0) { ARMCPU *cpu = env_archcpu(env); tlb_flush(CPU(cpu)); @@ -2792,6 +2823,8 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_FAR_EL1, .nv2_redirect_offset = 0x220 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 6, 0, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 6, 0, 0), .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, }; @@ -2802,12 +2835,16 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_ESR_EL1, .nv2_redirect_offset = 0x138 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 2, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 2, 0), .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_TTBR0_EL1, .nv2_redirect_offset = 0x200 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 0), .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), offsetof(CPUARMState, cp15.ttbr0_ns) } }, @@ -2816,6 +2853,8 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_TTBR1_EL1, .nv2_redirect_offset = 0x210 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 1), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 1), .writefn = vmsa_ttbr_write, .resetvalue = 0, .raw_writefn = raw_write, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) } }, @@ -2824,6 +2863,8 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_TCR_EL1, .nv2_redirect_offset = 0x120 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 2), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 2), .writefn = vmsa_tcr_el12_write, .raw_writefn = raw_write, .resetvalue = 0, @@ -3029,12 +3070,14 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri) } static const ARMCPRegInfo lpae_cp_reginfo[] = { - /* NOP AMAIR0/1 */ - { .name = "AMAIR0", .state = ARM_CP_STATE_BOTH, + /* AMAIR0 is mapped to AMAIR_EL1[31:0] */ + { .name = "AMAIR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_AMAIR_EL1, .nv2_redirect_offset = 0x148 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 3, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 3, 0), .type = ARM_CP_CONST, .resetvalue = 0 }, /* AMAIR1 is mapped to AMAIR_EL1[63:32] */ { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1, @@ -3550,12 +3593,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1, .access = PL1_RW, .accessfn = access_nv1, .nv2_redirect_offset = 0x230 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 4, 0, 1), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 4, 0, 1), .fieldoffset = offsetof(CPUARMState, elr_el[1]) }, { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_nv1, .nv2_redirect_offset = 0x160 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 4, 0, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 4, 0, 0), .fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_SVC]) }, /* * We rely on the access checks not allowing the guest to write to the @@ -4398,234 +4445,6 @@ static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri, return e2h_access(env, ri, isread); } -/* Test if system register redirection is to occur in the current state. */ -static bool redirect_for_e2h(CPUARMState *env) -{ - return arm_current_el(env) == 2 && (arm_hcr_el2_eff(env) & HCR_E2H); -} - -static uint64_t el2_e2h_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - CPReadFn *readfn; - - if (redirect_for_e2h(env)) { - /* Switch to the saved EL2 version of the register. */ - ri = ri->opaque; - readfn = ri->readfn; - } else { - readfn = ri->orig_readfn; - } - if (readfn == NULL) { - readfn = raw_read; - } - return readfn(env, ri); -} - -static void el2_e2h_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - CPWriteFn *writefn; - - if (redirect_for_e2h(env)) { - /* Switch to the saved EL2 version of the register. */ - ri = ri->opaque; - writefn = ri->writefn; - } else { - writefn = ri->orig_writefn; - } - if (writefn == NULL) { - writefn = raw_write; - } - writefn(env, ri, value); -} - -static uint64_t el2_e2h_e12_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ - return ri->orig_readfn(env, ri->opaque); -} - -static void el2_e2h_e12_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Pass the EL1 register accessor its ri, not the EL12 alias ri */ - return ri->orig_writefn(env, ri->opaque, value); -} - -static CPAccessResult el2_e2h_e12_access(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - if (arm_current_el(env) == 1) { - /* - * This must be a FEAT_NV access (will either trap or redirect - * to memory). None of the registers with _EL12 aliases want to - * apply their trap controls for this kind of access, so don't - * call the orig_accessfn or do the "UNDEF when E2H is 0" check. - */ - return CP_ACCESS_OK; - } - /* FOO_EL12 aliases only exist when E2H is 1; otherwise they UNDEF */ - if (!(arm_hcr_el2_eff(env) & HCR_E2H)) { - return CP_ACCESS_UNDEFINED; - } - if (ri->orig_accessfn) { - return ri->orig_accessfn(env, ri->opaque, isread); - } - return CP_ACCESS_OK; -} - -static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu) -{ - struct E2HAlias { - uint32_t src_key, dst_key, new_key; - const char *src_name, *dst_name, *new_name; - bool (*feature)(const ARMISARegisters *id); - }; - -#define K(op0, op1, crn, crm, op2) \ - ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2) - - static const struct E2HAlias aliases[] = { - { K(3, 0, 1, 0, 0), K(3, 4, 1, 0, 0), K(3, 5, 1, 0, 0), - "SCTLR", "SCTLR_EL2", "SCTLR_EL12" }, - { K(3, 0, 1, 0, 3), K(3, 4, 1, 0, 3), K(3, 5, 1, 0, 3), - "SCTLR2_EL1", "SCTLR2_EL2", "SCTLR2_EL12", isar_feature_aa64_sctlr2 }, - { K(3, 0, 1, 0, 2), K(3, 4, 1, 1, 2), K(3, 5, 1, 0, 2), - "CPACR", "CPTR_EL2", "CPACR_EL12" }, - { K(3, 0, 2, 0, 0), K(3, 4, 2, 0, 0), K(3, 5, 2, 0, 0), - "TTBR0_EL1", "TTBR0_EL2", "TTBR0_EL12" }, - { K(3, 0, 2, 0, 1), K(3, 4, 2, 0, 1), K(3, 5, 2, 0, 1), - "TTBR1_EL1", "TTBR1_EL2", "TTBR1_EL12" }, - { K(3, 0, 2, 0, 2), K(3, 4, 2, 0, 2), K(3, 5, 2, 0, 2), - "TCR_EL1", "TCR_EL2", "TCR_EL12" }, - { K(3, 0, 2, 0, 3), K(3, 4, 2, 0, 3), K(3, 5, 2, 0, 3), - "TCR2_EL1", "TCR2_EL2", "TCR2_EL12", isar_feature_aa64_tcr2 }, - { K(3, 0, 4, 0, 0), K(3, 4, 4, 0, 0), K(3, 5, 4, 0, 0), - "SPSR_EL1", "SPSR_EL2", "SPSR_EL12" }, - { K(3, 0, 4, 0, 1), K(3, 4, 4, 0, 1), K(3, 5, 4, 0, 1), - "ELR_EL1", "ELR_EL2", "ELR_EL12" }, - { K(3, 0, 5, 1, 0), K(3, 4, 5, 1, 0), K(3, 5, 5, 1, 0), - "AFSR0_EL1", "AFSR0_EL2", "AFSR0_EL12" }, - { K(3, 0, 5, 1, 1), K(3, 4, 5, 1, 1), K(3, 5, 5, 1, 1), - "AFSR1_EL1", "AFSR1_EL2", "AFSR1_EL12" }, - { K(3, 0, 5, 2, 0), K(3, 4, 5, 2, 0), K(3, 5, 5, 2, 0), - "ESR_EL1", "ESR_EL2", "ESR_EL12" }, - { K(3, 0, 6, 0, 0), K(3, 4, 6, 0, 0), K(3, 5, 6, 0, 0), - "FAR_EL1", "FAR_EL2", "FAR_EL12" }, - { K(3, 0, 10, 2, 0), K(3, 4, 10, 2, 0), K(3, 5, 10, 2, 0), - "MAIR_EL1", "MAIR_EL2", "MAIR_EL12" }, - { K(3, 0, 10, 3, 0), K(3, 4, 10, 3, 0), K(3, 5, 10, 3, 0), - "AMAIR0", "AMAIR_EL2", "AMAIR_EL12" }, - { K(3, 0, 12, 0, 0), K(3, 4, 12, 0, 0), K(3, 5, 12, 0, 0), - "VBAR", "VBAR_EL2", "VBAR_EL12" }, - { K(3, 0, 13, 0, 1), K(3, 4, 13, 0, 1), K(3, 5, 13, 0, 1), - "CONTEXTIDR_EL1", "CONTEXTIDR_EL2", "CONTEXTIDR_EL12" }, - { K(3, 0, 14, 1, 0), K(3, 4, 14, 1, 0), K(3, 5, 14, 1, 0), - "CNTKCTL", "CNTHCTL_EL2", "CNTKCTL_EL12" }, - - { K(3, 0, 1, 2, 0), K(3, 4, 1, 2, 0), K(3, 5, 1, 2, 0), - "ZCR_EL1", "ZCR_EL2", "ZCR_EL12", isar_feature_aa64_sve }, - { K(3, 0, 1, 2, 6), K(3, 4, 1, 2, 6), K(3, 5, 1, 2, 6), - "SMCR_EL1", "SMCR_EL2", "SMCR_EL12", isar_feature_aa64_sme }, - - { K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0), - "TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte }, - - { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7), - "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12", - isar_feature_aa64_scxtnum }, - - /* TODO: ARMv8.2-SPE -- PMSCR_EL2 */ - /* TODO: ARMv8.4-Trace -- TRFCR_EL2 */ - }; -#undef K - - size_t i; - - for (i = 0; i < ARRAY_SIZE(aliases); i++) { - const struct E2HAlias *a = &aliases[i]; - ARMCPRegInfo *src_reg, *dst_reg, *new_reg; - bool ok; - - if (a->feature && !a->feature(&cpu->isar)) { - continue; - } - - src_reg = g_hash_table_lookup(cpu->cp_regs, - (gpointer)(uintptr_t)a->src_key); - dst_reg = g_hash_table_lookup(cpu->cp_regs, - (gpointer)(uintptr_t)a->dst_key); - g_assert(src_reg != NULL); - g_assert(dst_reg != NULL); - - /* Cross-compare names to detect typos in the keys. */ - g_assert(strcmp(src_reg->name, a->src_name) == 0); - g_assert(strcmp(dst_reg->name, a->dst_name) == 0); - - /* None of the core system registers use opaque; we will. */ - g_assert(src_reg->opaque == NULL); - - /* Create alias before redirection so we dup the right data. */ - new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo)); - - new_reg->name = a->new_name; - new_reg->type |= ARM_CP_ALIAS; - /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ - new_reg->access &= PL2_RW | PL3_RW; - /* The new_reg op fields are as per new_key, not the target reg */ - new_reg->crn = (a->new_key & CP_REG_ARM64_SYSREG_CRN_MASK) - >> CP_REG_ARM64_SYSREG_CRN_SHIFT; - new_reg->crm = (a->new_key & CP_REG_ARM64_SYSREG_CRM_MASK) - >> CP_REG_ARM64_SYSREG_CRM_SHIFT; - new_reg->opc0 = (a->new_key & CP_REG_ARM64_SYSREG_OP0_MASK) - >> CP_REG_ARM64_SYSREG_OP0_SHIFT; - new_reg->opc1 = (a->new_key & CP_REG_ARM64_SYSREG_OP1_MASK) - >> CP_REG_ARM64_SYSREG_OP1_SHIFT; - new_reg->opc2 = (a->new_key & CP_REG_ARM64_SYSREG_OP2_MASK) - >> CP_REG_ARM64_SYSREG_OP2_SHIFT; - new_reg->opaque = src_reg; - new_reg->orig_readfn = src_reg->readfn ?: raw_read; - new_reg->orig_writefn = src_reg->writefn ?: raw_write; - new_reg->orig_accessfn = src_reg->accessfn; - if (!new_reg->raw_readfn) { - new_reg->raw_readfn = raw_read; - } - if (!new_reg->raw_writefn) { - new_reg->raw_writefn = raw_write; - } - new_reg->readfn = el2_e2h_e12_read; - new_reg->writefn = el2_e2h_e12_write; - new_reg->accessfn = el2_e2h_e12_access; - - /* - * If the _EL1 register is redirected to memory by FEAT_NV2, - * then it shares the offset with the _EL12 register, - * and which one is redirected depends on HCR_EL2.NV1. - */ - if (new_reg->nv2_redirect_offset) { - assert(new_reg->nv2_redirect_offset & NV2_REDIR_NV1); - new_reg->nv2_redirect_offset &= ~NV2_REDIR_NV1; - new_reg->nv2_redirect_offset |= NV2_REDIR_NO_NV1; - } - - ok = g_hash_table_insert(cpu->cp_regs, - (gpointer)(uintptr_t)a->new_key, new_reg); - g_assert(ok); - - src_reg->opaque = dst_reg; - src_reg->orig_readfn = src_reg->readfn ?: raw_read; - src_reg->orig_writefn = src_reg->writefn ?: raw_write; - if (!src_reg->raw_readfn) { - src_reg->raw_readfn = raw_read; - } - if (!src_reg->raw_writefn) { - src_reg->raw_writefn = raw_write; - } - src_reg->readfn = el2_e2h_read; - src_reg->writefn = el2_e2h_write; - } -} #endif static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri, @@ -4918,6 +4737,8 @@ static const ARMCPRegInfo zcr_reginfo[] = { { .name = "ZCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 0, .nv2_redirect_offset = 0x1e0 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 2, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 2, 0), .access = PL1_RW, .type = ARM_CP_SVE, .fieldoffset = offsetof(CPUARMState, vfp.zcr_el[1]), .writefn = zcr_write, .raw_writefn = raw_write }, @@ -5063,6 +4884,8 @@ static const ARMCPRegInfo sme_reginfo[] = { { .name = "SMCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 6, .nv2_redirect_offset = 0x1f0 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 2, 6), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 2, 6), .access = PL1_RW, .type = ARM_CP_SME, .fieldoffset = offsetof(CPUARMState, vfp.smcr_el[1]), .writefn = smcr_write, .raw_writefn = raw_write }, @@ -5184,7 +5007,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t pfr1 = GET_IDREG(&cpu->isar, ID_PFR1); if (env->gicv3state) { - pfr1 |= 1 << 28; + pfr1 = FIELD_DP64(pfr1, ID_PFR1, GIC, 1); } return pfr1; } @@ -5195,7 +5018,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri) uint64_t pfr0 = GET_IDREG(&cpu->isar, ID_AA64PFR0); if (env->gicv3state) { - pfr0 |= 1 << 24; + pfr0 = FIELD_DP64(pfr0, ID_AA64PFR0, GIC, 1); } return pfr0; } @@ -5371,7 +5194,7 @@ static const ARMCPRegInfo rndr_reginfo[] = { .access = PL0_R, .readfn = rndr_readfn }, }; -static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque, +static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { #ifdef CONFIG_TCG @@ -5508,6 +5331,8 @@ static const ARMCPRegInfo mte_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 6, .opc2 = 0, .access = PL1_RW, .accessfn = access_tfsr_el1, .nv2_redirect_offset = 0x190 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 5, 6, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 5, 6, 0), .fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) }, { .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64, .type = ARM_CP_NV2_REDIRECT, @@ -5683,6 +5508,8 @@ static const ARMCPRegInfo scxtnum_reginfo[] = { .access = PL1_RW, .accessfn = access_scxtnum_el1, .fgt = FGT_SCXTNUM_EL1, .nv2_redirect_offset = 0x188 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 13, 0, 7), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 13, 0, 7), .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) }, { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7, @@ -6027,6 +5854,8 @@ static const ARMCPRegInfo sctlr2_reginfo[] = { .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 1, .crm = 0, .access = PL1_RW, .accessfn = sctlr2_el1_access, .writefn = sctlr2_el1_write, .fgt = FGT_SCTLR_EL1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 0, 3), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 0, 3), .nv2_redirect_offset = 0x278 | NV2_REDIR_NV1, .fieldoffset = offsetof(CPUARMState, cp15.sctlr2_el[1]) }, { .name = "SCTLR2_EL2", .state = ARM_CP_STATE_AA64, @@ -6087,6 +5916,8 @@ static const ARMCPRegInfo tcr2_reginfo[] = { .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 2, .crm = 0, .access = PL1_RW, .accessfn = tcr2_el1_access, .writefn = tcr2_el1_write, .fgt = FGT_TCR_EL1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 0, 3), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 0, 3), .nv2_redirect_offset = 0x270 | NV2_REDIR_NV1, .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[1]) }, { .name = "TCR2_EL2", .state = ARM_CP_STATE_AA64, @@ -6278,11 +6109,11 @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = GET_IDREG(isar, ID_AA64PFR1)}, - { .name = "ID_AA64PFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + { .name = "ID_AA64PFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, + .resetvalue = GET_IDREG(isar, ID_AA64PFR2)}, { .name = "ID_AA64PFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, @@ -6510,6 +6341,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) R_ID_AA64PFR1_SSBS_MASK | R_ID_AA64PFR1_MTE_MASK | R_ID_AA64PFR1_SME_MASK }, + { .name = "ID_AA64PFR2_EL1", + .exported_bits = 0 }, { .name = "ID_AA64PFR*_EL1_RESERVED", .is_glob = true }, { .name = "ID_AA64ZFR0_EL1", @@ -7177,12 +7010,14 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_VBAR)) { static const ARMCPRegInfo vbar_cp_reginfo[] = { - { .name = "VBAR", .state = ARM_CP_STATE_BOTH, + { .name = "VBAR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .writefn = vbar_write, .accessfn = access_nv1, .fgt = FGT_VBAR_EL1, .nv2_redirect_offset = 0x250 | NV2_REDIR_NV1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 12, 0, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 12, 0, 0), .bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s), offsetof(CPUARMState, cp15.vbar_ns) }, .resetvalue = 0 }, @@ -7193,10 +7028,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) /* Generic registers whose values depend on the implementation */ { ARMCPRegInfo sctlr = { - .name = "SCTLR", .state = ARM_CP_STATE_BOTH, + .name = "SCTLR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, .fgt = FGT_SCTLR_EL1, + .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 1, 0, 0), + .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 1, 0, 0), .nv2_redirect_offset = 0x110 | NV2_REDIR_NV1, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), offsetof(CPUARMState, cp15.sctlr_ns) }, @@ -7331,61 +7168,40 @@ void register_cp_regs_for_features(ARMCPU *cpu) } define_pm_cpregs(cpu); +} -#ifndef CONFIG_USER_ONLY - /* - * Register redirections and aliases must be done last, - * after the registers from the other extensions have been defined. - */ - if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) { - define_arm_vh_e2h_redirects_aliases(cpu); +/* + * Copy a ARMCPRegInfo structure, allocating it along with the name + * and an optional suffix to the name. + */ +static ARMCPRegInfo *alloc_cpreg(const ARMCPRegInfo *in, const char *suffix) +{ + const char *name = in->name; + size_t name_len = strlen(name); + size_t suff_len = suffix ? strlen(suffix) : 0; + ARMCPRegInfo *out = g_malloc(sizeof(*in) + name_len + suff_len + 1); + char *p = (char *)(out + 1); + + *out = *in; + out->name = p; + + memcpy(p, name, name_len + 1); + if (suffix) { + memcpy(p + name_len, suffix, suff_len + 1); } -#endif + return out; } /* - * Private utility function for define_one_arm_cp_reg_with_opaque(): + * Private utility function for define_one_arm_cp_reg(): * add a single reginfo struct to the hash table. */ -static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, - void *opaque, CPState state, - CPSecureState secstate, - int crm, int opc1, int opc2, - const char *name) +static void add_cpreg_to_hashtable(ARMCPU *cpu, ARMCPRegInfo *r, + CPState state, CPSecureState secstate, + uint32_t key) { CPUARMState *env = &cpu->env; - uint32_t key; - ARMCPRegInfo *r2; - bool is64 = r->type & ARM_CP_64BIT; bool ns = secstate & ARM_CP_SECSTATE_NS; - int cp = r->cp; - size_t name_len; - bool make_const; - - switch (state) { - case ARM_CP_STATE_AA32: - /* We assume it is a cp15 register if the .cp field is left unset. */ - if (cp == 0 && r->state == ARM_CP_STATE_BOTH) { - cp = 15; - } - key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2); - break; - case ARM_CP_STATE_AA64: - /* - * To allow abbreviation of ARMCPRegInfo definitions, we treat - * cp == 0 as equivalent to the value for "standard guest-visible - * sysreg". STATE_BOTH definitions are also always "standard sysreg" - * in their AArch64 view (the .cp value may be non-zero for the - * benefit of the AArch32 view). - */ - if (cp == 0 || r->state == ARM_CP_STATE_BOTH) { - cp = CP_REG_ARM64_SYSREG_CP; - } - key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2); - break; - default: - g_assert_not_reached(); - } /* Overriding of an existing definition must be explicitly requested. */ if (!(r->type & ARM_CP_OVERRIDE)) { @@ -7395,84 +7211,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, } } - /* - * Eliminate registers that are not present because the EL is missing. - * Doing this here makes it easier to put all registers for a given - * feature into the same ARMCPRegInfo array and define them all at once. - */ - make_const = false; - if (arm_feature(env, ARM_FEATURE_EL3)) { - /* - * An EL2 register without EL2 but with EL3 is (usually) RES0. - * See rule RJFFP in section D1.1.3 of DDI0487H.a. - */ - int min_el = ctz32(r->access) / 2; - if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) { - if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) { - return; - } - make_const = !(r->type & ARM_CP_EL3_NO_EL2_KEEP); - } - } else { - CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2) - ? PL2_RW : PL1_RW); - if ((r->access & max_el) == 0) { - return; - } - } - - /* Combine cpreg and name into one allocation. */ - name_len = strlen(name) + 1; - r2 = g_malloc(sizeof(*r2) + name_len); - *r2 = *r; - r2->name = memcpy(r2 + 1, name, name_len); - - /* - * Update fields to match the instantiation, overwiting wildcards - * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH. - */ - r2->cp = cp; - r2->crm = crm; - r2->opc1 = opc1; - r2->opc2 = opc2; - r2->state = state; - r2->secure = secstate; - if (opaque) { - r2->opaque = opaque; - } - - if (make_const) { - /* This should not have been a very special register to begin. */ - int old_special = r2->type & ARM_CP_SPECIAL_MASK; - assert(old_special == 0 || old_special == ARM_CP_NOP); - /* - * Set the special function to CONST, retaining the other flags. - * This is important for e.g. ARM_CP_SVE so that we still - * take the SVE trap if CPTR_EL3.EZ == 0. - */ - r2->type = (r2->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST; - /* - * Usually, these registers become RES0, but there are a few - * special cases like VPIDR_EL2 which have a constant non-zero - * value with writes ignored. - */ - if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) { - r2->resetvalue = 0; - } - /* - * ARM_CP_CONST has precedence, so removing the callbacks and - * offsets are not strictly necessary, but it is potentially - * less confusing to debug later. - */ - r2->readfn = NULL; - r2->writefn = NULL; - r2->raw_readfn = NULL; - r2->raw_writefn = NULL; - r2->resetfn = NULL; - r2->fieldoffset = 0; - r2->bank_fieldoffsets[0] = 0; - r2->bank_fieldoffsets[1] = 0; - } else { + { bool isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]; if (isbanked) { @@ -7481,7 +7220,7 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, * Overwriting fieldoffset as the array is only used to define * banked registers but later only fieldoffset is used. */ - r2->fieldoffset = r->bank_fieldoffsets[ns]; + r->fieldoffset = r->bank_fieldoffsets[ns]; } if (state == ARM_CP_STATE_AA32) { if (isbanked) { @@ -7498,54 +7237,187 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r, */ if ((r->state == ARM_CP_STATE_BOTH && ns) || (arm_feature(env, ARM_FEATURE_V8) && !ns)) { - r2->type |= ARM_CP_ALIAS; + r->type |= ARM_CP_ALIAS; } } else if ((secstate != r->secure) && !ns) { /* * The register is not banked so we only want to allow * migration of the non-secure instance. */ - r2->type |= ARM_CP_ALIAS; - } - - if (HOST_BIG_ENDIAN && - r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) { - r2->fieldoffset += sizeof(uint32_t); + r->type |= ARM_CP_ALIAS; } } } /* - * By convention, for wildcarded registers only the first - * entry is used for migration; the others are marked as - * ALIAS so we don't try to transfer the register - * multiple times. Special registers (ie NOP/WFI) are - * never migratable and not even raw-accessible. + * For 32-bit AArch32 regs shared with 64-bit AArch64 regs, + * adjust the field offset for endianness. This had to be + * delayed until banked registers were resolved. */ - if (r2->type & ARM_CP_SPECIAL_MASK) { - r2->type |= ARM_CP_NO_RAW; + if (HOST_BIG_ENDIAN && + state == ARM_CP_STATE_AA32 && + r->state == ARM_CP_STATE_BOTH && + r->fieldoffset) { + r->fieldoffset += sizeof(uint32_t); } - if (((r->crm == CP_ANY) && crm != 0) || - ((r->opc1 == CP_ANY) && opc1 != 0) || - ((r->opc2 == CP_ANY) && opc2 != 0)) { - r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB; + + /* + * Special registers (ie NOP/WFI) are never migratable and + * are not even raw-accessible. + */ + if (r->type & ARM_CP_SPECIAL_MASK) { + r->type |= ARM_CP_NO_RAW; } /* + * Update fields to match the instantiation, overwiting wildcards + * such as ARM_CP_STATE_BOTH or ARM_CP_SECSTATE_BOTH. + */ + r->state = state; + r->secure = secstate; + + /* * Check that raw accesses are either forbidden or handled. Note that * we can't assert this earlier because the setup of fieldoffset for * banked registers has to be done first. */ - if (!(r2->type & ARM_CP_NO_RAW)) { - assert(!raw_accessors_invalid(r2)); + if (!(r->type & ARM_CP_NO_RAW)) { + assert(!raw_accessors_invalid(r)); } - g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2); + g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r); +} + +static void add_cpreg_to_hashtable_aa32(ARMCPU *cpu, ARMCPRegInfo *r) +{ + /* + * Under AArch32 CP registers can be common + * (same for secure and non-secure world) or banked. + */ + ARMCPRegInfo *r_s; + bool is64 = r->type & ARM_CP_64BIT; + uint32_t key = ENCODE_CP_REG(r->cp, is64, 0, r->crn, + r->crm, r->opc1, r->opc2); + + assert(!(r->type & ARM_CP_ADD_TLBI_NXS)); /* aa64 only */ + r->vhe_redir_to_el2 = 0; + r->vhe_redir_to_el01 = 0; + + switch (r->secure) { + case ARM_CP_SECSTATE_NS: + key |= CP_REG_AA32_NS_MASK; + /* fall through */ + case ARM_CP_SECSTATE_S: + add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, r->secure, key); + break; + case ARM_CP_SECSTATE_BOTH: + r_s = alloc_cpreg(r, "_S"); + add_cpreg_to_hashtable(cpu, r_s, ARM_CP_STATE_AA32, + ARM_CP_SECSTATE_S, key); + + key |= CP_REG_AA32_NS_MASK; + add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA32, + ARM_CP_SECSTATE_NS, key); + break; + default: + g_assert_not_reached(); + } } +static void add_cpreg_to_hashtable_aa64(ARMCPU *cpu, ARMCPRegInfo *r) +{ + uint32_t key = ENCODE_AA64_CP_REG(r->opc0, r->opc1, + r->crn, r->crm, r->opc2); + + if ((r->type & ARM_CP_ADD_TLBI_NXS) && + cpu_isar_feature(aa64_xs, cpu)) { + /* + * This is a TLBI insn which has an NXS variant. The + * NXS variant is at the same encoding except that + * crn is +1, and has the same behaviour except for + * fine-grained trapping. Add the NXS insn here and + * then fall through to add the normal register. + * add_cpreg_to_hashtable() copies the cpreg struct + * and name that it is passed, so it's OK to use + * a local struct here. + */ + ARMCPRegInfo *nxs_ri = alloc_cpreg(r, "NXS"); + uint32_t nxs_key; + + assert(nxs_ri->crn < 0xf); + nxs_ri->crn++; + /* Also increment the CRN field inside the key value */ + nxs_key = key + (1 << CP_REG_ARM64_SYSREG_CRN_SHIFT); + if (nxs_ri->fgt) { + nxs_ri->fgt |= R_FGT_NXS_MASK; + } + + add_cpreg_to_hashtable(cpu, nxs_ri, ARM_CP_STATE_AA64, + ARM_CP_SECSTATE_NS, nxs_key); + } + + if (!r->vhe_redir_to_el01) { + assert(!r->vhe_redir_to_el2); + } else if (!arm_feature(&cpu->env, ARM_FEATURE_EL2) || + !cpu_isar_feature(aa64_vh, cpu)) { + r->vhe_redir_to_el2 = 0; + r->vhe_redir_to_el01 = 0; + } else { + /* Create the FOO_EL12 alias. */ + ARMCPRegInfo *r2 = alloc_cpreg(r, "2"); + uint32_t key2 = r->vhe_redir_to_el01; + + /* + * Clear EL1 redirection on the FOO_EL1 reg; + * Clear EL2 redirection on the FOO_EL12 reg; + * Install redirection from FOO_EL12 back to FOO_EL1. + */ + r->vhe_redir_to_el01 = 0; + r2->vhe_redir_to_el2 = 0; + r2->vhe_redir_to_el01 = key; + + r2->type |= ARM_CP_ALIAS | ARM_CP_NO_RAW; + /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */ + r2->access &= PL2_RW | PL3_RW; + /* The new_reg op fields are as per new_key, not the target reg */ + r2->crn = (key2 & CP_REG_ARM64_SYSREG_CRN_MASK) + >> CP_REG_ARM64_SYSREG_CRN_SHIFT; + r2->crm = (key2 & CP_REG_ARM64_SYSREG_CRM_MASK) + >> CP_REG_ARM64_SYSREG_CRM_SHIFT; + r2->opc0 = (key2 & CP_REG_ARM64_SYSREG_OP0_MASK) + >> CP_REG_ARM64_SYSREG_OP0_SHIFT; + r2->opc1 = (key2 & CP_REG_ARM64_SYSREG_OP1_MASK) + >> CP_REG_ARM64_SYSREG_OP1_SHIFT; + r2->opc2 = (key2 & CP_REG_ARM64_SYSREG_OP2_MASK) + >> CP_REG_ARM64_SYSREG_OP2_SHIFT; + + /* Non-redirected access to this register will abort. */ + r2->readfn = NULL; + r2->writefn = NULL; + r2->raw_readfn = NULL; + r2->raw_writefn = NULL; + r2->accessfn = NULL; + r2->fieldoffset = 0; -void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, - const ARMCPRegInfo *r, void *opaque) + /* + * If the _EL1 register is redirected to memory by FEAT_NV2, + * then it shares the offset with the _EL12 register, + * and which one is redirected depends on HCR_EL2.NV1. + */ + if (r2->nv2_redirect_offset) { + assert(r2->nv2_redirect_offset & NV2_REDIR_NV1); + r2->nv2_redirect_offset &= ~NV2_REDIR_NV1; + r2->nv2_redirect_offset |= NV2_REDIR_NO_NV1; + } + add_cpreg_to_hashtable(cpu, r2, ARM_CP_STATE_AA64, + ARM_CP_SECSTATE_NS, key2); + } + + add_cpreg_to_hashtable(cpu, r, ARM_CP_STATE_AA64, + ARM_CP_SECSTATE_NS, key); +} + +void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *r) { /* * Define implementations of coprocessor registers. @@ -7571,21 +7443,27 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of * the register, if any. */ - int crm, opc1, opc2; int crmmin = (r->crm == CP_ANY) ? 0 : r->crm; int crmmax = (r->crm == CP_ANY) ? 15 : r->crm; int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1; int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1; int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2; int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2; - CPState state; + int cp = r->cp; + ARMCPRegInfo r_const; + CPUARMState *env = &cpu->env; - /* 64 bit registers have only CRm and Opc1 fields */ - assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn))); + /* + * AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless. + * Moreover, the encoding test just following in general prevents + * shared encoding so ARM_CP_STATE_BOTH won't work either. + */ + assert(r->state == ARM_CP_STATE_AA32 || !(r->type & ARM_CP_64BIT)); + /* AArch32 64-bit registers have only CRm and Opc1 fields. */ + assert(!(r->type & ARM_CP_64BIT) || !(r->opc2 || r->crn)); /* op0 only exists in the AArch64 encodings */ - assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0)); - /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */ - assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT)); + assert(r->state != ARM_CP_STATE_AA32 || r->opc0 == 0); + /* * This API is only for Arm's system coprocessors (14 and 15) or * (M-profile or v7A-and-earlier only) for implementation defined @@ -7596,21 +7474,25 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, */ switch (r->state) { case ARM_CP_STATE_BOTH: - /* 0 has a special meaning, but otherwise the same rules as AA32. */ - if (r->cp == 0) { + /* + * If the cp field is left unset, assume cp15. + * Otherwise apply the same rules as AA32. + */ + if (cp == 0) { + cp = 15; break; } /* fall through */ case ARM_CP_STATE_AA32: if (arm_feature(&cpu->env, ARM_FEATURE_V8) && !arm_feature(&cpu->env, ARM_FEATURE_M)) { - assert(r->cp >= 14 && r->cp <= 15); + assert(cp >= 14 && cp <= 15); } else { - assert(r->cp < 8 || (r->cp >= 14 && r->cp <= 15)); + assert(cp < 8 || (cp >= 14 && cp <= 15)); } break; case ARM_CP_STATE_AA64: - assert(r->cp == 0 || r->cp == CP_REG_ARM64_SYSREG_CP); + assert(cp == 0); break; default: g_assert_not_reached(); @@ -7675,75 +7557,104 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, } } - for (crm = crmmin; crm <= crmmax; crm++) { - for (opc1 = opc1min; opc1 <= opc1max; opc1++) { - for (opc2 = opc2min; opc2 <= opc2max; opc2++) { - for (state = ARM_CP_STATE_AA32; - state <= ARM_CP_STATE_AA64; state++) { - if (r->state != state && r->state != ARM_CP_STATE_BOTH) { - continue; - } - if ((r->type & ARM_CP_ADD_TLBI_NXS) && - cpu_isar_feature(aa64_xs, cpu)) { - /* - * This is a TLBI insn which has an NXS variant. The - * NXS variant is at the same encoding except that - * crn is +1, and has the same behaviour except for - * fine-grained trapping. Add the NXS insn here and - * then fall through to add the normal register. - * add_cpreg_to_hashtable() copies the cpreg struct - * and name that it is passed, so it's OK to use - * a local struct here. - */ - ARMCPRegInfo nxs_ri = *r; - g_autofree char *name = g_strdup_printf("%sNXS", r->name); - - assert(state == ARM_CP_STATE_AA64); - assert(nxs_ri.crn < 0xf); - nxs_ri.crn++; - if (nxs_ri.fgt) { - nxs_ri.fgt |= R_FGT_NXS_MASK; - } - add_cpreg_to_hashtable(cpu, &nxs_ri, opaque, state, - ARM_CP_SECSTATE_NS, - crm, opc1, opc2, name); - } - if (state == ARM_CP_STATE_AA32) { - /* - * Under AArch32 CP registers can be common - * (same for secure and non-secure world) or banked. - */ - char *name; - - switch (r->secure) { - case ARM_CP_SECSTATE_S: - case ARM_CP_SECSTATE_NS: - add_cpreg_to_hashtable(cpu, r, opaque, state, - r->secure, crm, opc1, opc2, - r->name); - break; - case ARM_CP_SECSTATE_BOTH: - name = g_strdup_printf("%s_S", r->name); - add_cpreg_to_hashtable(cpu, r, opaque, state, - ARM_CP_SECSTATE_S, - crm, opc1, opc2, name); - g_free(name); - add_cpreg_to_hashtable(cpu, r, opaque, state, - ARM_CP_SECSTATE_NS, - crm, opc1, opc2, r->name); - break; - default: - g_assert_not_reached(); - } - } else { - /* - * AArch64 registers get mapped to non-secure instance - * of AArch32 - */ - add_cpreg_to_hashtable(cpu, r, opaque, state, - ARM_CP_SECSTATE_NS, - crm, opc1, opc2, r->name); - } + /* + * Eliminate registers that are not present because the EL is missing. + * Doing this here makes it easier to put all registers for a given + * feature into the same ARMCPRegInfo array and define them all at once. + */ + if (arm_feature(env, ARM_FEATURE_EL3)) { + /* + * An EL2 register without EL2 but with EL3 is (usually) RES0. + * See rule RJFFP in section D1.1.3 of DDI0487H.a. + */ + int min_el = ctz32(r->access) / 2; + if (min_el == 2 && !arm_feature(env, ARM_FEATURE_EL2)) { + if (r->type & ARM_CP_EL3_NO_EL2_UNDEF) { + return; + } + if (!(r->type & ARM_CP_EL3_NO_EL2_KEEP)) { + /* This should not have been a very special register. */ + int old_special = r->type & ARM_CP_SPECIAL_MASK; + assert(old_special == 0 || old_special == ARM_CP_NOP); + + r_const = *r; + + /* + * Set the special function to CONST, retaining the other flags. + * This is important for e.g. ARM_CP_SVE so that we still + * take the SVE trap if CPTR_EL3.EZ == 0. + */ + r_const.type = (r->type & ~ARM_CP_SPECIAL_MASK) | ARM_CP_CONST; + /* + * Usually, these registers become RES0, but there are a few + * special cases like VPIDR_EL2 which have a constant non-zero + * value with writes ignored. + */ + if (!(r->type & ARM_CP_EL3_NO_EL2_C_NZ)) { + r_const.resetvalue = 0; + } + /* + * ARM_CP_CONST has precedence, so removing the callbacks and + * offsets are not strictly necessary, but it is potentially + * less confusing to debug later. + */ + r_const.readfn = NULL; + r_const.writefn = NULL; + r_const.raw_readfn = NULL; + r_const.raw_writefn = NULL; + r_const.resetfn = NULL; + r_const.fieldoffset = 0; + r_const.bank_fieldoffsets[0] = 0; + r_const.bank_fieldoffsets[1] = 0; + + r = &r_const; + } + } + } else { + CPAccessRights max_el = (arm_feature(env, ARM_FEATURE_EL2) + ? PL2_RW : PL1_RW); + if ((r->access & max_el) == 0) { + return; + } + } + + for (int crm = crmmin; crm <= crmmax; crm++) { + for (int opc1 = opc1min; opc1 <= opc1max; opc1++) { + for (int opc2 = opc2min; opc2 <= opc2max; opc2++) { + ARMCPRegInfo *r2 = alloc_cpreg(r, NULL); + ARMCPRegInfo *r3; + + /* + * By convention, for wildcarded registers only the first + * entry is used for migration; the others are marked as + * ALIAS so we don't try to transfer the register + * multiple times. + */ + if (crm != crmmin || opc1 != opc1min || opc2 != opc2min) { + r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB; + } + + /* Overwrite CP_ANY with the instantiation. */ + r2->crm = crm; + r2->opc1 = opc1; + r2->opc2 = opc2; + + switch (r->state) { + case ARM_CP_STATE_AA32: + add_cpreg_to_hashtable_aa32(cpu, r2); + break; + case ARM_CP_STATE_AA64: + add_cpreg_to_hashtable_aa64(cpu, r2); + break; + case ARM_CP_STATE_BOTH: + r3 = alloc_cpreg(r2, NULL); + r2->cp = cp; + add_cpreg_to_hashtable_aa32(cpu, r2); + r3->cp = 0; + add_cpreg_to_hashtable_aa64(cpu, r3); + break; + default: + g_assert_not_reached(); } } } @@ -7751,12 +7662,10 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, } /* Define a whole list of registers */ -void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs, - void *opaque, size_t len) +void define_arm_cp_regs_len(ARMCPU *cpu, const ARMCPRegInfo *regs, size_t len) { - size_t i; - for (i = 0; i < len; ++i) { - define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque); + for (size_t i = 0; i < len; ++i) { + define_one_arm_cp_reg(cpu, regs + i); } } @@ -7818,7 +7727,7 @@ uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri) return 0; } -void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque) +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *ri) { /* Helper coprocessor reset function for do-nothing-on-reset registers */ } diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index b77db99..0658a99 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -152,9 +152,6 @@ void hvf_arm_init_debug(void) g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps); } -#define HVF_SYSREG(crn, crm, op0, op1, op2) \ - ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2) - #define SYSREG_OP0_SHIFT 20 #define SYSREG_OP0_MASK 0x3 #define SYSREG_OP0(sysreg) ((sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK) @@ -397,156 +394,34 @@ static const struct hvf_reg_match hvf_fpreg_match[] = { { HV_SIMD_FP_REG_Q31, offsetof(CPUARMState, vfp.zregs[31]) }, }; -struct hvf_sreg_match { - int reg; - uint32_t key; - uint32_t cp_idx; -}; +/* + * QEMU uses KVM system register ids in the migration format. + * Conveniently, HVF uses the same encoding of the op* and cr* parameters + * within the low 16 bits of the ids. Thus conversion between the + * formats is trivial. + */ -static struct hvf_sreg_match hvf_sreg_match[] = { - { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 2, 0, 7) }, - - { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 4) }, - { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 5) }, - { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 2, 0, 6) }, - { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 2, 0, 7) }, - -#ifdef SYNC_NO_RAW_REGS - /* - * The registers below are manually synced on init because they are - * marked as NO_RAW. We still list them to make number space sync easier. - */ - { HV_SYS_REG_MDCCINT_EL1, HVF_SYSREG(0, 2, 2, 0, 0) }, - { HV_SYS_REG_MIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 0) }, - { HV_SYS_REG_MPIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 5) }, - { HV_SYS_REG_ID_AA64PFR0_EL1, HVF_SYSREG(0, 4, 3, 0, 0) }, -#endif - { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 1) }, - { HV_SYS_REG_ID_AA64DFR0_EL1, HVF_SYSREG(0, 5, 3, 0, 0) }, - { HV_SYS_REG_ID_AA64DFR1_EL1, HVF_SYSREG(0, 5, 3, 0, 1) }, - { HV_SYS_REG_ID_AA64ISAR0_EL1, HVF_SYSREG(0, 6, 3, 0, 0) }, - { HV_SYS_REG_ID_AA64ISAR1_EL1, HVF_SYSREG(0, 6, 3, 0, 1) }, -#ifdef SYNC_NO_MMFR0 - /* We keep the hardware MMFR0 around. HW limits are there anyway */ - { HV_SYS_REG_ID_AA64MMFR0_EL1, HVF_SYSREG(0, 7, 3, 0, 0) }, -#endif - { HV_SYS_REG_ID_AA64MMFR1_EL1, HVF_SYSREG(0, 7, 3, 0, 1) }, - { HV_SYS_REG_ID_AA64MMFR2_EL1, HVF_SYSREG(0, 7, 3, 0, 2) }, - /* Add ID_AA64MMFR3_EL1 here when HVF supports it */ - - { HV_SYS_REG_MDSCR_EL1, HVF_SYSREG(0, 2, 2, 0, 2) }, - { HV_SYS_REG_SCTLR_EL1, HVF_SYSREG(1, 0, 3, 0, 0) }, - { HV_SYS_REG_CPACR_EL1, HVF_SYSREG(1, 0, 3, 0, 2) }, - { HV_SYS_REG_TTBR0_EL1, HVF_SYSREG(2, 0, 3, 0, 0) }, - { HV_SYS_REG_TTBR1_EL1, HVF_SYSREG(2, 0, 3, 0, 1) }, - { HV_SYS_REG_TCR_EL1, HVF_SYSREG(2, 0, 3, 0, 2) }, - - { HV_SYS_REG_APIAKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 0) }, - { HV_SYS_REG_APIAKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 1) }, - { HV_SYS_REG_APIBKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 2) }, - { HV_SYS_REG_APIBKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 3) }, - { HV_SYS_REG_APDAKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 0) }, - { HV_SYS_REG_APDAKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 1) }, - { HV_SYS_REG_APDBKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 2) }, - { HV_SYS_REG_APDBKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 3) }, - { HV_SYS_REG_APGAKEYLO_EL1, HVF_SYSREG(2, 3, 3, 0, 0) }, - { HV_SYS_REG_APGAKEYHI_EL1, HVF_SYSREG(2, 3, 3, 0, 1) }, - - { HV_SYS_REG_SPSR_EL1, HVF_SYSREG(4, 0, 3, 0, 0) }, - { HV_SYS_REG_ELR_EL1, HVF_SYSREG(4, 0, 3, 0, 1) }, - { HV_SYS_REG_SP_EL0, HVF_SYSREG(4, 1, 3, 0, 0) }, - { HV_SYS_REG_AFSR0_EL1, HVF_SYSREG(5, 1, 3, 0, 0) }, - { HV_SYS_REG_AFSR1_EL1, HVF_SYSREG(5, 1, 3, 0, 1) }, - { HV_SYS_REG_ESR_EL1, HVF_SYSREG(5, 2, 3, 0, 0) }, - { HV_SYS_REG_FAR_EL1, HVF_SYSREG(6, 0, 3, 0, 0) }, - { HV_SYS_REG_PAR_EL1, HVF_SYSREG(7, 4, 3, 0, 0) }, - { HV_SYS_REG_MAIR_EL1, HVF_SYSREG(10, 2, 3, 0, 0) }, - { HV_SYS_REG_AMAIR_EL1, HVF_SYSREG(10, 3, 3, 0, 0) }, - { HV_SYS_REG_VBAR_EL1, HVF_SYSREG(12, 0, 3, 0, 0) }, - { HV_SYS_REG_CONTEXTIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 1) }, - { HV_SYS_REG_TPIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 4) }, - { HV_SYS_REG_CNTKCTL_EL1, HVF_SYSREG(14, 1, 3, 0, 0) }, - { HV_SYS_REG_CSSELR_EL1, HVF_SYSREG(0, 0, 3, 2, 0) }, - { HV_SYS_REG_TPIDR_EL0, HVF_SYSREG(13, 0, 3, 3, 2) }, - { HV_SYS_REG_TPIDRRO_EL0, HVF_SYSREG(13, 0, 3, 3, 3) }, - { HV_SYS_REG_CNTV_CTL_EL0, HVF_SYSREG(14, 3, 3, 3, 1) }, - { HV_SYS_REG_CNTV_CVAL_EL0, HVF_SYSREG(14, 3, 3, 3, 2) }, - { HV_SYS_REG_SP_EL1, HVF_SYSREG(4, 1, 3, 4, 0) }, +#define KVMID_TO_HVF(KVM) ((KVM) & 0xffff) +#define HVF_TO_KVMID(HVF) \ + (CP_REG_ARM64 | CP_REG_SIZE_U64 | CP_REG_ARM64_SYSREG | (HVF)) + +/* Verify this at compile-time. */ + +#define DEF_SYSREG(HVF_ID, ...) \ + QEMU_BUILD_BUG_ON(HVF_ID != KVMID_TO_HVF(KVMID_AA64_SYS_REG64(__VA_ARGS__))); + +#include "sysreg.c.inc" + +#undef DEF_SYSREG + +#define DEF_SYSREG(HVF_ID, op0, op1, crn, crm, op2) HVF_ID, + +static const hv_sys_reg_t hvf_sreg_list[] = { +#include "sysreg.c.inc" }; +#undef DEF_SYSREG + int hvf_get_registers(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); @@ -554,7 +429,7 @@ int hvf_get_registers(CPUState *cpu) hv_return_t ret; uint64_t val; hv_simd_fp_uchar16_t fpval; - int i; + int i, n; for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) { ret = hv_vcpu_get_reg(cpu->accel->fd, hvf_reg_match[i].reg, &val); @@ -583,14 +458,13 @@ int hvf_get_registers(CPUState *cpu) assert_hvf_ok(ret); pstate_write(env, val); - for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) { - if (hvf_sreg_match[i].cp_idx == -1) { - continue; - } + for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) { + uint64_t kvm_id = arm_cpu->cpreg_indexes[i]; + int hvf_id = KVMID_TO_HVF(kvm_id); if (cpu->accel->guest_debug_enabled) { /* Handle debug registers */ - switch (hvf_sreg_match[i].reg) { + switch (hvf_id) { case HV_SYS_REG_DBGBVR0_EL1: case HV_SYS_REG_DBGBCR0_EL1: case HV_SYS_REG_DBGWVR0_EL1: @@ -664,20 +538,22 @@ int hvf_get_registers(CPUState *cpu) * vCPU but simply keep the values from the previous * environment. */ - const ARMCPRegInfo *ri; - ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match[i].key); + uint32_t key = kvm_to_cpreg_id(kvm_id); + const ARMCPRegInfo *ri = + get_arm_cp_reginfo(arm_cpu->cp_regs, key); + val = read_raw_cp_reg(env, ri); - arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val; + arm_cpu->cpreg_values[i] = val; continue; } } } - ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, &val); + ret = hv_vcpu_get_sys_reg(cpu->accel->fd, hvf_id, &val); assert_hvf_ok(ret); - arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val; + arm_cpu->cpreg_values[i] = val; } assert(write_list_to_cpustate(arm_cpu)); @@ -693,7 +569,7 @@ int hvf_put_registers(CPUState *cpu) hv_return_t ret; uint64_t val; hv_simd_fp_uchar16_t fpval; - int i; + int i, n; for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) { val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset); @@ -720,14 +596,13 @@ int hvf_put_registers(CPUState *cpu) aarch64_save_sp(env, arm_current_el(env)); assert(write_cpustate_to_list(arm_cpu, false)); - for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) { - if (hvf_sreg_match[i].cp_idx == -1) { - continue; - } + for (i = 0, n = arm_cpu->cpreg_array_len; i < n; i++) { + uint64_t kvm_id = arm_cpu->cpreg_indexes[i]; + int hvf_id = KVMID_TO_HVF(kvm_id); if (cpu->accel->guest_debug_enabled) { /* Handle debug registers */ - switch (hvf_sreg_match[i].reg) { + switch (hvf_id) { case HV_SYS_REG_DBGBVR0_EL1: case HV_SYS_REG_DBGBCR0_EL1: case HV_SYS_REG_DBGWVR0_EL1: @@ -801,8 +676,8 @@ int hvf_put_registers(CPUState *cpu) } } - val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx]; - ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_sreg_match[i].reg, val); + val = arm_cpu->cpreg_values[i]; + ret = hv_vcpu_set_sys_reg(cpu->accel->fd, hvf_id, val); assert_hvf_ok(ret); } @@ -869,6 +744,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) } regs[] = { { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.idregs[ID_AA64PFR0_EL1_IDX] }, { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.idregs[ID_AA64PFR1_EL1_IDX] }, + /* Add ID_AA64PFR2_EL1 here when HVF supports it */ { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.idregs[ID_AA64DFR0_EL1_IDX] }, { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.idregs[ID_AA64DFR1_EL1_IDX] }, { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.idregs[ID_AA64ISAR0_EL1_IDX] }, @@ -1012,7 +888,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) { ARMCPU *arm_cpu = ARM_CPU(cpu); CPUARMState *env = &arm_cpu->env; - uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_match); + uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_list); uint32_t sregs_cnt = 0; uint64_t pfr; hv_return_t ret; @@ -1037,21 +913,22 @@ int hvf_arch_init_vcpu(CPUState *cpu) /* Populate cp list for all known sysregs */ for (i = 0; i < sregs_match_len; i++) { - const ARMCPRegInfo *ri; - uint32_t key = hvf_sreg_match[i].key; + hv_sys_reg_t hvf_id = hvf_sreg_list[i]; + uint64_t kvm_id = HVF_TO_KVMID(hvf_id); + uint32_t key = kvm_to_cpreg_id(kvm_id); + const ARMCPRegInfo *ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key); - ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key); if (ri) { assert(!(ri->type & ARM_CP_NO_RAW)); - hvf_sreg_match[i].cp_idx = sregs_cnt; - arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key); - } else { - hvf_sreg_match[i].cp_idx = -1; + arm_cpu->cpreg_indexes[sregs_cnt++] = kvm_id; } } arm_cpu->cpreg_array_len = sregs_cnt; arm_cpu->cpreg_vmstate_array_len = sregs_cnt; + /* cpreg tuples must be in strictly ascending order */ + qsort(arm_cpu->cpreg_indexes, sregs_cnt, sizeof(uint64_t), compare_u64); + assert(write_cpustate_to_list(arm_cpu, false)); /* Set CP_NO_RAW system registers on init */ @@ -1248,11 +1125,10 @@ static bool is_id_sysreg(uint32_t reg) static uint32_t hvf_reg2cp_reg(uint32_t reg) { - return ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, + return ENCODE_AA64_CP_REG((reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK, + (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK, (reg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK, (reg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK, - (reg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK, - (reg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK, (reg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK); } @@ -1277,7 +1153,7 @@ static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val) } else if (ri->readfn) { *val = ri->readfn(env, ri); } else { - *val = CPREG_FIELD64(env, ri); + *val = raw_read(env, ri); } trace_hvf_vgic_read(ri->name, *val); return true; @@ -1559,7 +1435,7 @@ static bool hvf_sysreg_write_cp(CPUState *cpu, uint32_t reg, uint64_t val) if (ri->writefn) { ri->writefn(env, ri, val); } else { - CPREG_FIELD64(env, ri) = val; + raw_write(env, ri, val); } trace_hvf_vgic_write(ri->name, val); diff --git a/target/arm/hvf/sysreg.c.inc b/target/arm/hvf/sysreg.c.inc new file mode 100644 index 0000000..067a860 --- /dev/null +++ b/target/arm/hvf/sysreg.c.inc @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +DEF_SYSREG(HV_SYS_REG_DBGBVR0_EL1, 2, 0, 0, 0, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR0_EL1, 2, 0, 0, 0, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR0_EL1, 2, 0, 0, 0, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR0_EL1, 2, 0, 0, 0, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR1_EL1, 2, 0, 0, 1, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR1_EL1, 2, 0, 0, 1, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR1_EL1, 2, 0, 0, 1, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR1_EL1, 2, 0, 0, 1, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR2_EL1, 2, 0, 0, 2, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR2_EL1, 2, 0, 0, 2, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR2_EL1, 2, 0, 0, 2, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR2_EL1, 2, 0, 0, 2, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR3_EL1, 2, 0, 0, 3, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR3_EL1, 2, 0, 0, 3, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR3_EL1, 2, 0, 0, 3, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR3_EL1, 2, 0, 0, 3, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR4_EL1, 2, 0, 0, 4, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR4_EL1, 2, 0, 0, 4, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR4_EL1, 2, 0, 0, 4, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR4_EL1, 2, 0, 0, 4, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR5_EL1, 2, 0, 0, 5, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR5_EL1, 2, 0, 0, 5, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR5_EL1, 2, 0, 0, 5, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR5_EL1, 2, 0, 0, 5, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR6_EL1, 2, 0, 0, 6, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR6_EL1, 2, 0, 0, 6, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR6_EL1, 2, 0, 0, 6, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR6_EL1, 2, 0, 0, 6, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR7_EL1, 2, 0, 0, 7, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR7_EL1, 2, 0, 0, 7, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR7_EL1, 2, 0, 0, 7, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR7_EL1, 2, 0, 0, 7, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR8_EL1, 2, 0, 0, 8, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR8_EL1, 2, 0, 0, 8, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR8_EL1, 2, 0, 0, 8, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR8_EL1, 2, 0, 0, 8, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR9_EL1, 2, 0, 0, 9, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR9_EL1, 2, 0, 0, 9, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR9_EL1, 2, 0, 0, 9, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR9_EL1, 2, 0, 0, 9, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR10_EL1, 2, 0, 0, 10, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR10_EL1, 2, 0, 0, 10, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR10_EL1, 2, 0, 0, 10, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR10_EL1, 2, 0, 0, 10, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR11_EL1, 2, 0, 0, 11, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR11_EL1, 2, 0, 0, 11, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR11_EL1, 2, 0, 0, 11, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR11_EL1, 2, 0, 0, 11, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR12_EL1, 2, 0, 0, 12, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR12_EL1, 2, 0, 0, 12, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR12_EL1, 2, 0, 0, 12, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR12_EL1, 2, 0, 0, 12, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR13_EL1, 2, 0, 0, 13, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR13_EL1, 2, 0, 0, 13, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR13_EL1, 2, 0, 0, 13, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR13_EL1, 2, 0, 0, 13, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR14_EL1, 2, 0, 0, 14, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR14_EL1, 2, 0, 0, 14, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR14_EL1, 2, 0, 0, 14, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR14_EL1, 2, 0, 0, 14, 7) + +DEF_SYSREG(HV_SYS_REG_DBGBVR15_EL1, 2, 0, 0, 15, 4) +DEF_SYSREG(HV_SYS_REG_DBGBCR15_EL1, 2, 0, 0, 15, 5) +DEF_SYSREG(HV_SYS_REG_DBGWVR15_EL1, 2, 0, 0, 15, 6) +DEF_SYSREG(HV_SYS_REG_DBGWCR15_EL1, 2, 0, 0, 15, 7) + +#ifdef SYNC_NO_RAW_REGS +/* + * The registers below are manually synced on init because they are + * marked as NO_RAW. We still list them to make number space sync easier. + */ +DEF_SYSREG(HV_SYS_REG_MDCCINT_EL1, 2, 0, 0, 2, 0) +DEF_SYSREG(HV_SYS_REG_MIDR_EL1, 3, 0, 0, 0, 0) +DEF_SYSREG(HV_SYS_REG_MPIDR_EL1, 3, 0, 0, 0, 5) +DEF_SYSREG(HV_SYS_REG_ID_AA64PFR0_EL1, 3, 0, 0, 4, 0) +#endif + +DEF_SYSREG(HV_SYS_REG_ID_AA64PFR1_EL1, 3, 0, 0, 4, 1) +/* Add ID_AA64PFR2_EL1 here when HVF supports it */ +DEF_SYSREG(HV_SYS_REG_ID_AA64DFR0_EL1, 3, 0, 0, 5, 0) +DEF_SYSREG(HV_SYS_REG_ID_AA64DFR1_EL1, 3, 0, 0, 5, 1) +DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0) +DEF_SYSREG(HV_SYS_REG_ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1) + +#ifdef SYNC_NO_MMFR0 +/* We keep the hardware MMFR0 around. HW limits are there anyway */ +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0) +#endif + +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1) +DEF_SYSREG(HV_SYS_REG_ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2) +/* Add ID_AA64MMFR3_EL1 here when HVF supports it */ + +DEF_SYSREG(HV_SYS_REG_MDSCR_EL1, 2, 0, 0, 2, 2) +DEF_SYSREG(HV_SYS_REG_SCTLR_EL1, 3, 0, 1, 0, 0) +DEF_SYSREG(HV_SYS_REG_CPACR_EL1, 3, 0, 1, 0, 2) +DEF_SYSREG(HV_SYS_REG_TTBR0_EL1, 3, 0, 2, 0, 0) +DEF_SYSREG(HV_SYS_REG_TTBR1_EL1, 3, 0, 2, 0, 1) +DEF_SYSREG(HV_SYS_REG_TCR_EL1, 3, 0, 2, 0, 2) + +DEF_SYSREG(HV_SYS_REG_APIAKEYLO_EL1, 3, 0, 2, 1, 0) +DEF_SYSREG(HV_SYS_REG_APIAKEYHI_EL1, 3, 0, 2, 1, 1) +DEF_SYSREG(HV_SYS_REG_APIBKEYLO_EL1, 3, 0, 2, 1, 2) +DEF_SYSREG(HV_SYS_REG_APIBKEYHI_EL1, 3, 0, 2, 1, 3) +DEF_SYSREG(HV_SYS_REG_APDAKEYLO_EL1, 3, 0, 2, 2, 0) +DEF_SYSREG(HV_SYS_REG_APDAKEYHI_EL1, 3, 0, 2, 2, 1) +DEF_SYSREG(HV_SYS_REG_APDBKEYLO_EL1, 3, 0, 2, 2, 2) +DEF_SYSREG(HV_SYS_REG_APDBKEYHI_EL1, 3, 0, 2, 2, 3) +DEF_SYSREG(HV_SYS_REG_APGAKEYLO_EL1, 3, 0, 2, 3, 0) +DEF_SYSREG(HV_SYS_REG_APGAKEYHI_EL1, 3, 0, 2, 3, 1) + +DEF_SYSREG(HV_SYS_REG_SPSR_EL1, 3, 0, 4, 0, 0) +DEF_SYSREG(HV_SYS_REG_ELR_EL1, 3, 0, 4, 0, 1) +DEF_SYSREG(HV_SYS_REG_SP_EL0, 3, 0, 4, 1, 0) +DEF_SYSREG(HV_SYS_REG_AFSR0_EL1, 3, 0, 5, 1, 0) +DEF_SYSREG(HV_SYS_REG_AFSR1_EL1, 3, 0, 5, 1, 1) +DEF_SYSREG(HV_SYS_REG_ESR_EL1, 3, 0, 5, 2, 0) +DEF_SYSREG(HV_SYS_REG_FAR_EL1, 3, 0, 6, 0, 0) +DEF_SYSREG(HV_SYS_REG_PAR_EL1, 3, 0, 7, 4, 0) +DEF_SYSREG(HV_SYS_REG_MAIR_EL1, 3, 0, 10, 2, 0) +DEF_SYSREG(HV_SYS_REG_AMAIR_EL1, 3, 0, 10, 3, 0) +DEF_SYSREG(HV_SYS_REG_VBAR_EL1, 3, 0, 12, 0, 0) +DEF_SYSREG(HV_SYS_REG_CONTEXTIDR_EL1, 3, 0, 13, 0, 1) +DEF_SYSREG(HV_SYS_REG_TPIDR_EL1, 3, 0, 13, 0, 4) +DEF_SYSREG(HV_SYS_REG_CNTKCTL_EL1, 3, 0, 14, 1, 0) +DEF_SYSREG(HV_SYS_REG_CSSELR_EL1, 3, 2, 0, 0, 0) +DEF_SYSREG(HV_SYS_REG_TPIDR_EL0, 3, 3, 13, 0, 2) +DEF_SYSREG(HV_SYS_REG_TPIDRRO_EL0, 3, 3, 13, 0, 3) +DEF_SYSREG(HV_SYS_REG_CNTV_CTL_EL0, 3, 3, 14, 3, 1) +DEF_SYSREG(HV_SYS_REG_CNTV_CVAL_EL0, 3, 3, 14, 3, 2) +DEF_SYSREG(HV_SYS_REG_SP_EL1, 3, 4, 4, 1, 0) diff --git a/target/arm/internals.h b/target/arm/internals.h index 0f7df97..1d958db 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -2004,4 +2004,7 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env); void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask); bool arm_pan_enabled(CPUARMState *env); +/* Compare uint64_t for qsort and bsearch. */ +int compare_u64(const void *a, const void *b); + #endif diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h index c44d23d..54ae5da 100644 --- a/target/arm/kvm-consts.h +++ b/target/arm/kvm-consts.h @@ -160,9 +160,6 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53); #define CP_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007 #define CP_REG_ARM64_SYSREG_OP2_SHIFT 0 -/* No kernel define but it's useful to QEMU */ -#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT) - MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64); MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK); MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT); @@ -180,4 +177,15 @@ MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT); #undef MISMATCH_CHECK +#define KVMID_AA64_SYS_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) | \ + ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) | \ + ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT)) + +#define KVMID_AA64_SYS_REG64(op0, op1, crn, crm, op2) \ + (KVMID_AA64_SYS_REG_(op0, op1, crn, crm, op2) | CP_REG_SIZE_U64) + #endif diff --git a/target/arm/kvm.c b/target/arm/kvm.c index c1ec665..b8a1c07 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -324,6 +324,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) err = 0; } else { err |= get_host_cpu_reg(fd, ahcf, ID_AA64PFR1_EL1_IDX); + err |= get_host_cpu_reg(fd, ahcf, ID_AA64PFR2_EL1_IDX); err |= get_host_cpu_reg(fd, ahcf, ID_AA64SMFR0_EL1_IDX); err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR0_EL1_IDX); err |= get_host_cpu_reg(fd, ahcf, ID_AA64DFR1_EL1_IDX); @@ -718,17 +719,6 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid, uint64_t group, memory_region_ref(kd->mr); } -static int compare_u64(const void *a, const void *b) -{ - if (*(uint64_t *)a > *(uint64_t *)b) { - return 1; - } - if (*(uint64_t *)a < *(uint64_t *)b) { - return -1; - } - return 0; -} - /* * cpreg_values are sorted in ascending order by KVM register ID * (see kvm_arm_init_cpreg_list). This allows us to cheaply find diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index 0189422..17f83f1 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -258,6 +258,11 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, DP_TBFLAG_A64(flags, TBII, tbii); DP_TBFLAG_A64(flags, TBID, tbid); + /* E2H is used by both VHE and NV2. */ + if (hcr & HCR_E2H) { + DP_TBFLAG_A64(flags, E2H, 1); + } + if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { int sve_el = sve_exception_el(env, el); @@ -390,9 +395,6 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, } if (hcr & HCR_NV2) { DP_TBFLAG_A64(flags, NV2, 1); - if (hcr & HCR_E2H) { - DP_TBFLAG_A64(flags, NV2_MEM_E20, 1); - } if (env->cp15.sctlr_el[2] & SCTLR_EE) { DP_TBFLAG_A64(flags, NV2_MEM_BE, 1); } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 37bedc3..a0e3300 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -2455,6 +2455,19 @@ static void gen_sysreg_undef(DisasContext *s, bool isread, gen_exception_insn(s, 0, EXCP_UDEF, syndrome); } +/* + * Look up @key, returning the cpreg, which must exist. + * Additionally, the new cpreg must also be accessible. + */ +static const ARMCPRegInfo * +redirect_cpreg(DisasContext *s, uint32_t key, bool isread) +{ + const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); + assert(ri); + assert(cp_access_ok(s->current_el, ri, isread)); + return ri; +} + /* MRS - move from system register * MSR (register) - move to system register * SYS @@ -2466,8 +2479,7 @@ static void handle_sys(DisasContext *s, bool isread, unsigned int op0, unsigned int op1, unsigned int op2, unsigned int crn, unsigned int crm, unsigned int rt) { - uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, - crn, crm, op0, op1, op2); + uint32_t key = ENCODE_AA64_CP_REG(op0, op1, crn, crm, op2); const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key); bool need_exit_tb = false; bool nv_trap_to_el2 = false; @@ -2561,6 +2573,27 @@ static void handle_sys(DisasContext *s, bool isread, } } + if (ri->vhe_redir_to_el2 && s->current_el == 2 && s->e2h) { + /* + * This one of the FOO_EL1 registers which redirect to FOO_EL2 + * from EL2 when HCR_EL2.E2H is set. + */ + key = ri->vhe_redir_to_el2; + ri = redirect_cpreg(s, key, isread); + } else if (ri->vhe_redir_to_el01 && s->current_el >= 2) { + /* + * This is one of the FOO_EL12 or FOO_EL02 registers. + * With !E2H, they all UNDEF. + * With E2H, from EL2 or EL3, they redirect to FOO_EL1/FOO_EL0. + */ + if (!s->e2h) { + gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt); + return; + } + key = ri->vhe_redir_to_el01; + ri = redirect_cpreg(s, key, isread); + } + if (ri->accessfn || (ri->fgt && s->fgt_active)) { /* Emit code to perform further access permissions checks at * runtime; this may result in an exception. @@ -2603,11 +2636,8 @@ static void handle_sys(DisasContext *s, bool isread, * We don't use the EL1 register's access function, and * fine-grained-traps on EL1 also do not apply here. */ - key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, - crn, crm, op0, 0, op2); - ri = get_arm_cp_reginfo(s->cp_regs, key); - assert(ri); - assert(cp_access_ok(s->current_el, ri, isread)); + key = ENCODE_AA64_CP_REG(op0, 0, crn, crm, op2); + ri = redirect_cpreg(s, key, isread); /* * We might not have done an update_pc earlier, so check we don't * need it. We could support this in future if necessary. @@ -10306,10 +10336,11 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA); dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); dc->naa = EX_TBFLAG_A64(tb_flags, NAA); + dc->e2h = EX_TBFLAG_A64(tb_flags, E2H); dc->nv = EX_TBFLAG_A64(tb_flags, NV); dc->nv1 = EX_TBFLAG_A64(tb_flags, NV1); dc->nv2 = EX_TBFLAG_A64(tb_flags, NV2); - dc->nv2_mem_e20 = EX_TBFLAG_A64(tb_flags, NV2_MEM_E20); + dc->nv2_mem_e20 = dc->nv2 && dc->e2h; dc->nv2_mem_be = EX_TBFLAG_A64(tb_flags, NV2_MEM_BE); dc->fpcr_ah = EX_TBFLAG_A64(tb_flags, AH); dc->fpcr_nep = EX_TBFLAG_A64(tb_flags, NEP); diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index ec4755a..f1a6e5e 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -150,6 +150,8 @@ typedef struct DisasContext { bool trap_eret; /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */ bool naa; + /* True if HCR_EL2.E2H is set */ + bool e2h; /* True if FEAT_NV HCR_EL2.NV is enabled */ bool nv; /* True if NV enabled and HCR_EL2.NV1 is set */ diff --git a/target/arm/trace-events b/target/arm/trace-events index 4438dce..72a2c7d 100644 --- a/target/arm/trace-events +++ b/target/arm/trace-events @@ -13,3 +13,13 @@ arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d" # kvm.c kvm_arm_fixup_msi_route(uint64_t iova, uint64_t gpa) "MSI iova = 0x%"PRIx64" is translated into 0x%"PRIx64 + +# cpu.c +arm_cpu_reset(uint64_t mp_aff) "cpu %" PRIu64 +arm_emulate_firmware_reset(uint64_t mp_aff, unsigned target_el) "cpu %" PRIu64 " @EL%u" + +# arm-powerctl.c +arm_powerctl_set_cpu_on(uint64_t mp_aff, unsigned target_el, const char *mode, uint64_t entry, uint64_t context_id) "cpu %" PRIu64 " (EL %u, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64 +arm_powerctl_set_cpu_on_and_reset(uint64_t mp_aff) "cpu %" PRIu64 +arm_powerctl_set_cpu_off(uint64_t mp_aff) "cpu %" PRIu64 +arm_powerctl_reset_cpu(uint64_t mp_aff) "cpu %" PRIu64 |