return CP_ACCESS_OK;
}
+static CPAccessResult access_nv1_or_exlock_el1(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 1) {
+ uint64_t nvx = arm_hcr_el2_nvx_eff(env);
+
+ if (!isread &&
+ (env->pstate & PSTATE_EXLOCK) &&
+ (env->cp15.gcscr_el[1] & GCSCR_EXLOCKEN) &&
+ !(nvx & HCR_NV1)) {
+ return CP_ACCESS_EXLOCK;
+ }
+ return access_nv1_with_nvx(nvx);
+ }
+
+ /*
+ * At EL2, since VHE redirection is done at translation time,
+ * el_is_in_host is always false here, so EXLOCK does not apply.
+ */
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_exlock_el2(CPUARMState *env,
+ const ARMCPRegInfo *ri, bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el == 3) {
+ return CP_ACCESS_OK;
+ }
+
+ /*
+ * Access to the EL2 register from EL1 means NV is set, and
+ * EXLOCK has priority over an NV1 trap to EL2.
+ */
+ if (!isread &&
+ (env->pstate & PSTATE_EXLOCK) &&
+ (env->cp15.gcscr_el[el] & GCSCR_EXLOCKEN)) {
+ return CP_ACCESS_EXLOCK;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_exlock_el3(CPUARMState *env,
+ const ARMCPRegInfo *ri, bool isread)
+{
+ if (!isread &&
+ (env->pstate & PSTATE_EXLOCK) &&
+ (env->cp15.gcscr_el[3] & GCSCR_EXLOCKEN)) {
+ return CP_ACCESS_EXLOCK;
+ }
+ return CP_ACCESS_OK;
+}
+
#ifdef CONFIG_USER_ONLY
/*
* `IC IVAU` is handled to improve compatibility with JITs that dual-map their
{ .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
- .access = PL1_RW, .accessfn = access_nv1,
+ .access = PL1_RW, .accessfn = access_nv1_or_exlock_el1,
.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),
{ .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,
+ .access = PL1_RW, .accessfn = access_nv1_or_exlock_el1,
.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),
{ .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
- .access = PL2_RW,
+ .access = PL2_RW, .accessfn = access_exlock_el2,
.fieldoffset = offsetof(CPUARMState, elr_el[2]) },
{ .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH,
.type = ARM_CP_NV2_REDIRECT,
{ .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS | ARM_CP_NV2_REDIRECT,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
- .access = PL2_RW,
+ .access = PL2_RW, .accessfn = access_exlock_el2,
.fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_HYP]) },
{ .name = "VBAR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
{ .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
- .access = PL3_RW,
+ .access = PL3_RW, .accessfn = access_exlock_el3,
.fieldoffset = offsetof(CPUARMState, elr_el[3]) },
{ .name = "ESR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 5, .crm = 2, .opc2 = 0,
{ .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
- .access = PL3_RW,
+ .access = PL3_RW, .accessfn = access_exlock_el3,
.fieldoffset = offsetof(CPUARMState, banked_spsr[BANK_MON]) },
{ .name = "VBAR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 12, .crm = 0, .opc2 = 0,