target/arm: Correctly implement Feat_DoubleLock
The architecture defines the OS DoubleLock as a register which (similarly to the OS Lock) suppresses debug events for use in CPU powerdown sequences. This functionality is required in Arm v7 and v8.0; from v8.2 it becomes optional and in v9 it must not be implemented. Currently in QEMU we implement the OSDLR_EL1 register as a NOP. This is wrong both for the "feature implemented" and the "feature not implemented" cases: if the feature is implemented then the DLK bit should read as written and cause suppression of debug exceptions, and if it is not implemented then the bit must be RAZ/WI. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		| @@ -500,6 +500,7 @@ typedef struct CPUArchState { | ||||
|         uint64_t dbgwcr[16]; /* watchpoint control registers */ | ||||
|         uint64_t mdscr_el1; | ||||
|         uint64_t oslsr_el1; /* OS Lock Status */ | ||||
|         uint64_t osdlr_el1; /* OS DoubleLock status */ | ||||
|         uint64_t mdcr_el2; | ||||
|         uint64_t mdcr_el3; | ||||
|         /* Stores the architectural value of the counter *the last time it was | ||||
| @@ -2253,6 +2254,15 @@ 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(MVFR0, SIMDREG, 0, 4) | ||||
| FIELD(MVFR0, FPSP, 4, 4) | ||||
| FIELD(MVFR0, FPDP, 8, 4) | ||||
| @@ -3731,6 +3741,11 @@ static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id) | ||||
|     return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8; | ||||
| } | ||||
|  | ||||
| static inline bool isar_feature_aa32_doublelock(const ARMISARegisters *id) | ||||
| { | ||||
|     return FIELD_EX32(id->dbgdevid, DBGDEVID, DOUBLELOCK) > 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 64-bit feature tests via id registers. | ||||
|  */ | ||||
| @@ -4155,6 +4170,11 @@ static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) | ||||
|     return FIELD_EX64(id->id_aa64smfr0, ID_AA64SMFR0, FA64); | ||||
| } | ||||
|  | ||||
| static inline bool isar_feature_aa64_doublelock(const ARMISARegisters *id) | ||||
| { | ||||
|     return FIELD_SEX64(id->id_aa64dfr0, ID_AA64DFR0, DOUBLELOCK) >= 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Feature tests for "does this exist in either 32-bit or 64-bit?" | ||||
|  */ | ||||
|   | ||||
| @@ -142,7 +142,7 @@ static bool aa32_generate_debug_exceptions(CPUARMState *env) | ||||
|  */ | ||||
| bool arm_generate_debug_exceptions(CPUARMState *env) | ||||
| { | ||||
|     if (env->cp15.oslsr_el1 & 1) { | ||||
|     if ((env->cp15.oslsr_el1 & 1) || (env->cp15.osdlr_el1 & 1)) { | ||||
|         return false; | ||||
|     } | ||||
|     if (is_a64(env)) { | ||||
| @@ -614,6 +614,21 @@ static void oslar_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||||
|     env->cp15.oslsr_el1 = deposit32(env->cp15.oslsr_el1, 1, 1, oslock); | ||||
| } | ||||
|  | ||||
| static void osdlr_write(CPUARMState *env, const ARMCPRegInfo *ri, | ||||
|                         uint64_t value) | ||||
| { | ||||
|     ARMCPU *cpu = env_archcpu(env); | ||||
|     /* | ||||
|      * Only defined bit is bit 0 (DLK); if Feat_DoubleLock is not | ||||
|      * implemented this is RAZ/WI. | ||||
|      */ | ||||
|     if(arm_feature(env, ARM_FEATURE_AARCH64) | ||||
|        ? cpu_isar_feature(aa64_doublelock, cpu) | ||||
|        : cpu_isar_feature(aa32_doublelock, cpu)) { | ||||
|         env->cp15.osdlr_el1 = value & 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static const ARMCPRegInfo debug_cp_reginfo[] = { | ||||
|     /* | ||||
|      * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped | ||||
| @@ -670,7 +685,8 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { | ||||
|     { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH, | ||||
|       .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4, | ||||
|       .access = PL1_RW, .accessfn = access_tdosa, | ||||
|       .type = ARM_CP_NOP }, | ||||
|       .writefn = osdlr_write, | ||||
|       .fieldoffset = offsetof(CPUARMState, cp15.osdlr_el1) }, | ||||
|     /* | ||||
|      * Dummy DBGVCR: Linux wants to clear this on startup, but we don't | ||||
|      * implement vector catch debug events yet. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user