@@ -844,6 +844,16 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
+static CPAccessResult access_dbgvcr32(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* MCDR_EL3.TDMA doesn't apply for FEAT_NV traps */
+ if (arm_current_el(env) == 2 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
/*
* Check for traps to Debug Comms Channel registers. If FEAT_FGT
* is implemented then these are controlled by MDCR_EL2.TDCC for
@@ -1062,7 +1072,7 @@ static const ARMCPRegInfo debug_aa32_el1_reginfo[] = {
*/
{ .name = "DBGVCR32_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 2, .opc1 = 4, .crn = 0, .crm = 7, .opc2 = 0,
- .access = PL2_RW, .accessfn = access_tda,
+ .access = PL2_RW, .accessfn = access_dbgvcr32,
.type = ARM_CP_NOP | ARM_CP_EL3_NO_EL2_KEEP },
};
@@ -3324,6 +3324,11 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
+ if (arm_current_el(env) == 1) {
+ /* This must be a FEAT_NV access */
+ /* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */
+ return CP_ACCESS_OK;
+ }
if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
return CP_ACCESS_TRAP;
}
@@ -6014,7 +6019,7 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
static CPAccessResult access_hxen(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
- if (arm_current_el(env) < 3
+ if (arm_current_el(env) == 2
&& arm_feature(env, ARM_FEATURE_EL3)
&& !(env->cp15.scr_el3 & SCR_HXEN)) {
return CP_ACCESS_TRAP_EL3;
@@ -6539,6 +6544,15 @@ 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_TRAP_UNCATEGORIZED;
@@ -7015,10 +7029,21 @@ static CPAccessResult access_tpidr2(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
-static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri,
- bool isread)
+static CPAccessResult access_smprimap(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /* If EL1 this is a FEAT_NV access and CPTR_EL3.ESM doesn't apply */
+ if (arm_current_el(env) == 2
+ && arm_feature(env, ARM_FEATURE_EL3)
+ && !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_smpri(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
{
- /* TODO: FEAT_FGT for SMPRI_EL1 but not SMPRIMAP_EL2 */
if (arm_current_el(env) < 3
&& arm_feature(env, ARM_FEATURE_EL3)
&& !FIELD_EX64(env->cp15.cptr_el[3], CPTR_EL3, ESM)) {
@@ -7137,12 +7162,12 @@ static const ARMCPRegInfo sme_reginfo[] = {
*/
{ .name = "SMPRI_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 1, .crm = 2, .opc2 = 4,
- .access = PL1_RW, .accessfn = access_esm,
+ .access = PL1_RW, .accessfn = access_smpri,
.fgt = FGT_NSMPRI_EL1,
.type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "SMPRIMAP_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 2, .opc2 = 5,
- .access = PL2_RW, .accessfn = access_esm,
+ .access = PL2_RW, .accessfn = access_smprimap,
.type = ARM_CP_CONST, .resetvalue = 0 },
};
@@ -7792,7 +7817,33 @@ static CPAccessResult access_mte(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
+ if (el < 2 && arm_is_el2_enabled(env)) {
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ }
+ if (el < 3 &&
+ arm_feature(env, ARM_FEATURE_EL3) &&
+ !(env->cp15.scr_el3 & SCR_ATA)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+static CPAccessResult access_tfsr_el2(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /*
+ * TFSR_EL2: similar to generic access_mte(), but we need to
+ * account for FEAT_NV. At EL1 this must be a FEAT_NV access;
+ * we will trap to EL2 and the HCR/SCR traps do not apply.
+ */
+ int el = arm_current_el(env);
+
+ if (el == 1) {
+ return CP_ACCESS_OK;
+ }
if (el < 2 && arm_is_el2_enabled(env)) {
uint64_t hcr = arm_hcr_el2_eff(env);
if (!(hcr & HCR_ATA) && (!(hcr & HCR_E2H) || !(hcr & HCR_TGE))) {
@@ -7828,7 +7879,7 @@ static const ARMCPRegInfo mte_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[1]) },
{ .name = "TFSR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 6, .opc2 = 0,
- .access = PL2_RW, .accessfn = access_mte,
+ .access = PL2_RW, .accessfn = access_tfsr_el2,
.fieldoffset = offsetof(CPUARMState, cp15.tfsr_el[2]) },
{ .name = "TFSR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 5, .crm = 6, .opc2 = 0,