aboutsummaryrefslogtreecommitdiff
path: root/target/arm/helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r--target/arm/helper.c391
1 files changed, 339 insertions, 52 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index b7bf45a..167f290 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -420,7 +420,9 @@ int alle1_tlbmask(CPUARMState *env)
*/
return (ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
+ ARMMMUIdxBit_E10_1_GCS |
ARMMMUIdxBit_E10_0 |
+ ARMMMUIdxBit_E10_0_GCS |
ARMMMUIdxBit_Stage2 |
ARMMMUIdxBit_Stage2_S);
}
@@ -764,12 +766,22 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
if (cpu_isar_feature(aa64_ecv, cpu)) {
valid_mask |= SCR_ECVEN;
}
+ if (cpu_isar_feature(aa64_gcs, cpu)) {
+ valid_mask |= SCR_GCSEN;
+ }
if (cpu_isar_feature(aa64_tcr2, cpu)) {
valid_mask |= SCR_TCR2EN;
}
if (cpu_isar_feature(aa64_sctlr2, cpu)) {
valid_mask |= SCR_SCTLR2EN;
}
+ if (cpu_isar_feature(aa64_s1pie, cpu) ||
+ cpu_isar_feature(aa64_s2pie, cpu)) {
+ valid_mask |= SCR_PIEN;
+ }
+ if (cpu_isar_feature(aa64_mec, cpu)) {
+ valid_mask |= SCR_MECEN;
+ }
} else {
valid_mask &= ~(SCR_RW | SCR_ST);
if (cpu_isar_feature(aa32_ras, cpu)) {
@@ -804,12 +816,17 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
*/
if (changed & (SCR_NS | SCR_NSE)) {
tlb_flush_by_mmuidx(env_cpu(env), (ARMMMUIdxBit_E10_0 |
+ ARMMMUIdxBit_E10_0_GCS |
ARMMMUIdxBit_E20_0 |
+ ARMMMUIdxBit_E20_0_GCS |
ARMMMUIdxBit_E10_1 |
- ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E10_1_PAN |
+ ARMMMUIdxBit_E10_1_GCS |
+ ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E2));
+ ARMMMUIdxBit_E20_2_GCS |
+ ARMMMUIdxBit_E2 |
+ ARMMMUIdxBit_E2_GCS));
}
}
@@ -2783,7 +2800,9 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
(arm_hcr_el2_eff(env) & HCR_E2H)) {
uint16_t mask = ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E20_0;
+ ARMMMUIdxBit_E20_2_GCS |
+ ARMMMUIdxBit_E20_0 |
+ ARMMMUIdxBit_E20_0_GCS;
tlb_flush_by_mmuidx(env_cpu(env), mask);
}
raw_write(env, ri, value);
@@ -3407,15 +3426,71 @@ static void mdcr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
}
}
+static CPAccessResult access_nv1_with_nvx(uint64_t hcr_nv)
+{
+ return hcr_nv == (HCR_NV | HCR_NV1) ? CP_ACCESS_TRAP_EL2 : CP_ACCESS_OK;
+}
+
static CPAccessResult access_nv1(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) == 1) {
- uint64_t hcr_nv = arm_hcr_el2_eff(env) & (HCR_NV | HCR_NV1 | HCR_NV2);
+ return access_nv1_with_nvx(arm_hcr_el2_nvx_eff(env));
+ }
+ 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 (hcr_nv == (HCR_NV | HCR_NV1)) {
- return CP_ACCESS_TRAP_EL2;
+ 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;
}
@@ -3591,7 +3666,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
{ .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),
@@ -3599,7 +3674,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
{ .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),
@@ -3888,6 +3963,16 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env)
return arm_hcr_el2_eff_secstate(env, arm_security_space_below_el3(env));
}
+uint64_t arm_hcr_el2_nvx_eff(CPUARMState *env)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+
+ if (!(hcr & HCR_NV)) {
+ return 0; /* CONSTRAINED UNPREDICTABLE wrt NV1 */
+ }
+ return hcr & (HCR_NV2 | HCR_NV1 | HCR_NV);
+}
+
/*
* Corresponds to ARM pseudocode function ELIsInHost().
*/
@@ -3940,6 +4025,9 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
if (cpu_isar_feature(aa64_sctlr2, cpu)) {
valid_mask |= HCRX_SCTLR2EN;
}
+ if (cpu_isar_feature(aa64_gcs, cpu)) {
+ valid_mask |= HCRX_GCSEN;
+ }
/* Clear RES0 bits. */
env->cp15.hcrx_el2 = value & valid_mask;
@@ -4010,6 +4098,9 @@ uint64_t arm_hcrx_el2_eff(CPUARMState *env)
if (cpu_isar_feature(aa64_sctlr2, cpu)) {
hcrx |= HCRX_SCTLR2EN;
}
+ if (cpu_isar_feature(aa64_gcs, cpu)) {
+ hcrx |= HCRX_GCSEN;
+ }
return hcrx;
}
if (arm_feature(env, ARM_FEATURE_EL3) && !(env->cp15.scr_el3 & SCR_HXEN)) {
@@ -4067,7 +4158,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .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,
@@ -4085,7 +4176,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .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,
@@ -4367,7 +4458,7 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
{ .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,
@@ -4378,7 +4469,7 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
{ .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,
@@ -5000,6 +5091,96 @@ static const ARMCPRegInfo nmi_reginfo[] = {
.resetfn = arm_cp_reset_ignore },
};
+static CPAccessResult mecid_access(CPUARMState *env,
+ const ARMCPRegInfo *ri, bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el == 2) {
+ if (arm_security_space(env) != ARMSS_Realm) {
+ return CP_ACCESS_UNDEFINED;
+ }
+
+ if (!(env->cp15.scr_el3 & SCR_MECEN)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ }
+
+ return CP_ACCESS_OK;
+}
+
+static void mecid_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ value = extract64(value, 0, MECID_WIDTH);
+ raw_write(env, ri, value);
+}
+
+static CPAccessResult cipae_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ switch (arm_security_space(env)) {
+ case ARMSS_Root: /* EL3 */
+ case ARMSS_Realm: /* Realm EL2 */
+ return CP_ACCESS_OK;
+ default:
+ return CP_ACCESS_UNDEFINED;
+ }
+}
+
+static const ARMCPRegInfo mec_reginfo[] = {
+ { .name = "MECIDR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 7, .crn = 10, .crm = 8,
+ .access = PL2_R, .type = ARM_CP_CONST | ARM_CP_NV_NO_TRAP,
+ .resetvalue = MECID_WIDTH - 1 },
+ { .name = "MECID_P0_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 0, .crn = 10, .crm = 8,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.mecid_p0_el2) },
+ { .name = "MECID_A0_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 1, .crn = 10, .crm = 8,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.mecid_a0_el2) },
+ { .name = "MECID_P1_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 2, .crn = 10, .crm = 8,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.mecid_p1_el2) },
+ { .name = "MECID_A1_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 3, .crn = 10, .crm = 8,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.mecid_a1_el2) },
+ { .name = "MECID_RL_A_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .opc2 = 1, .crn = 10, .crm = 10,
+ .access = PL3_RW, .accessfn = mecid_access,
+ .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.mecid_rl_a_el3) },
+ { .name = "VMECID_P_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 0, .crn = 10, .crm = 9,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.vmecid_p_el2) },
+ { .name = "VMECID_A_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 1, .crn = 10, .crm = 9,
+ .access = PL2_RW, .type = ARM_CP_NV_NO_TRAP,
+ .accessfn = mecid_access, .writefn = mecid_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.vmecid_a_el2) },
+ { .name = "DC_CIPAE", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 14, .opc2 = 0,
+ .access = PL2_W, .type = ARM_CP_NOP | ARM_CP_NV_NO_TRAP,
+ .accessfn = cipae_access },
+};
+
+static const ARMCPRegInfo mec_mte_reginfo[] = {
+ { .name = "DC_CIGDPAE", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 14, .opc2 = 7,
+ .access = PL2_W, .type = ARM_CP_NOP | ARM_CP_NV_NO_TRAP,
+ .accessfn = cipae_access },
+};
+
#ifndef CONFIG_USER_ONLY
/*
* We don't know until after realize whether there's a GICv3
@@ -5842,6 +6023,9 @@ static void sctlr2_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
uint64_t valid_mask = 0;
+ if (cpu_isar_feature(aa64_mec, env_archcpu(env))) {
+ valid_mask |= SCTLR2_EMEC;
+ }
value &= valid_mask;
raw_write(env, ri, value);
}
@@ -5851,6 +6035,9 @@ static void sctlr2_el3_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
uint64_t valid_mask = 0;
+ if (cpu_isar_feature(aa64_mec, env_archcpu(env))) {
+ valid_mask |= SCTLR2_EMEC;
+ }
value &= valid_mask;
raw_write(env, ri, value);
}
@@ -5902,8 +6089,12 @@ static CPAccessResult tcr2_el1_access(CPUARMState *env, const ARMCPRegInfo *ri,
static void tcr2_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ ARMCPU *cpu = env_archcpu(env);
uint64_t valid_mask = 0;
+ if (cpu_isar_feature(aa64_s1pie, cpu)) {
+ valid_mask |= TCR2_PIE;
+ }
value &= valid_mask;
raw_write(env, ri, value);
}
@@ -5911,8 +6102,15 @@ static void tcr2_el1_write(CPUARMState *env, const ARMCPRegInfo *ri,
static void tcr2_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
+ ARMCPU *cpu = env_archcpu(env);
uint64_t valid_mask = 0;
+ if (cpu_isar_feature(aa64_s1pie, cpu)) {
+ valid_mask |= TCR2_PIE;
+ }
+ if (cpu_isar_feature(aa64_mec, env_archcpu(env))) {
+ valid_mask |= TCR2_AMEC0 | TCR2_AMEC1;
+ }
value &= valid_mask;
raw_write(env, ri, value);
}
@@ -5933,6 +6131,64 @@ static const ARMCPRegInfo tcr2_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[2]) },
};
+static CPAccessResult pien_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_feature(env, ARM_FEATURE_EL3)
+ && !(env->cp15.scr_el3 & SCR_PIEN)
+ && arm_current_el(env) < 3) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult pien_el1_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ CPAccessResult ret = access_tvm_trvm(env, ri, isread);
+ if (ret == CP_ACCESS_OK) {
+ ret = pien_access(env, ri, isread);
+ }
+ return ret;
+}
+
+static const ARMCPRegInfo s1pie_reginfo[] = {
+ { .name = "PIR_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 10, .crm = 2,
+ .access = PL1_RW, .accessfn = pien_el1_access,
+ .fgt = FGT_NPIR_EL1, .nv2_redirect_offset = 0x2a0 | NV2_REDIR_NV1,
+ .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 2, 3),
+ .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 2, 3),
+ .fieldoffset = offsetof(CPUARMState, cp15.pir_el[1]) },
+ { .name = "PIR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 3, .crn = 10, .crm = 2,
+ .access = PL2_RW, .accessfn = pien_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.pir_el[2]) },
+ { .name = "PIR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .opc2 = 3, .crn = 10, .crm = 2,
+ .access = PL3_RW,
+ .fieldoffset = offsetof(CPUARMState, cp15.pir_el[3]) },
+ { .name = "PIRE0_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .opc2 = 2, .crn = 10, .crm = 2,
+ .access = PL1_RW, .accessfn = pien_el1_access,
+ .fgt = FGT_NPIRE0_EL1, .nv2_redirect_offset = 0x290 | NV2_REDIR_NV1,
+ .vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 10, 2, 2),
+ .vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 10, 2, 2),
+ .fieldoffset = offsetof(CPUARMState, cp15.pir_el[0]) },
+ { .name = "PIRE0_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 2, .crn = 10, .crm = 2,
+ .access = PL2_RW, .accessfn = pien_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.pire0_el2) },
+};
+
+static const ARMCPRegInfo s2pie_reginfo[] = {
+ { .name = "S2PIR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .opc2 = 5, .crn = 10, .crm = 2,
+ .access = PL2_RW, .accessfn = pien_access,
+ .nv2_redirect_offset = 0x2b0,
+ .fieldoffset = offsetof(CPUARMState, cp15.s2pir_el2) },
+};
+
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@@ -7165,6 +7421,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, tcr2_reginfo);
}
+ if (cpu_isar_feature(aa64_s1pie, cpu)) {
+ define_arm_cp_regs(cpu, s1pie_reginfo);
+ }
+ if (cpu_isar_feature(aa64_s2pie, cpu)) {
+ define_arm_cp_regs(cpu, s2pie_reginfo);
+ }
+ if (cpu_isar_feature(aa64_mec, cpu)) {
+ define_arm_cp_regs(cpu, mec_reginfo);
+ if (cpu_isar_feature(aa64_mte, cpu)) {
+ define_arm_cp_regs(cpu, mec_mte_reginfo);
+ }
+ }
+
if (cpu_isar_feature(any_predinv, cpu)) {
define_arm_cp_regs(cpu, predinv_reginfo);
}
@@ -7174,6 +7443,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
}
define_pm_cpregs(cpu);
+ define_gcs_cpregs(cpu);
}
/*
@@ -8800,7 +9070,7 @@ static int aarch64_regnum(CPUARMState *env, int aarch32_reg)
}
}
-static uint32_t cpsr_read_for_spsr_elx(CPUARMState *env)
+uint32_t cpsr_read_for_spsr_elx(CPUARMState *env)
{
uint32_t ret = cpsr_read(env);
@@ -8815,6 +9085,24 @@ static uint32_t cpsr_read_for_spsr_elx(CPUARMState *env)
return ret;
}
+void cpsr_write_from_spsr_elx(CPUARMState *env, uint32_t val)
+{
+ uint32_t mask;
+
+ /* Save SPSR_ELx.SS into PSTATE. */
+ env->pstate = (env->pstate & ~PSTATE_SS) | (val & PSTATE_SS);
+ val &= ~PSTATE_SS;
+
+ /* Move DIT to the correct location for CPSR */
+ if (val & PSTATE_DIT) {
+ val &= ~PSTATE_DIT;
+ val |= CPSR_DIT;
+ }
+
+ mask = aarch32_cpsr_valid_mask(env->features, &env_archcpu(env)->isar);
+ cpsr_write(env, val, mask, CPSRWriteRaw);
+}
+
static bool syndrome_is_sync_extabt(uint32_t syndrome)
{
/* Return true if this syndrome value is a synchronous external abort */
@@ -8847,8 +9135,8 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
vaddr addr = env->cp15.vbar_el[new_el];
- unsigned int new_mode = aarch64_pstate_mode(new_el, true);
- unsigned int old_mode;
+ uint64_t new_mode = aarch64_pstate_mode(new_el, true);
+ uint64_t old_mode;
unsigned int cur_el = arm_current_el(env);
int rt;
@@ -8891,8 +9179,13 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
} else {
addr += 0x600;
}
- } else if (pstate_read(env) & PSTATE_SP) {
- addr += 0x200;
+ } else {
+ if (pstate_read(env) & PSTATE_SP) {
+ addr += 0x200;
+ }
+ if (is_a64(env) && (env->cp15.gcscr_el[new_el] & GCSCR_EXLOCKEN)) {
+ new_mode |= PSTATE_EXLOCK;
+ }
}
switch (cs->exception_index) {
@@ -8996,7 +9289,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
* If NV2 is disabled, change SPSR when NV,NV1 == 1,0 (I_ZJRNN)
* If NV2 is enabled, change SPSR when NV is 1 (I_DBTLM)
*/
- old_mode = deposit32(old_mode, 2, 2, 2);
+ old_mode = deposit64(old_mode, 2, 2, 2);
}
}
} else {
@@ -9009,7 +9302,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
}
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = old_mode;
- qemu_log_mask(CPU_LOG_INT, "...with SPSR 0x%x\n", old_mode);
+ qemu_log_mask(CPU_LOG_INT, "...with SPSR 0x%" PRIx64 "\n", old_mode);
qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
env->elr_el[new_el]);
@@ -9063,7 +9356,8 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
env->pc = addr;
- qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
+ qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64
+ " PSTATE 0x%" PRIx64 "\n",
new_el, env->pc, pstate_read(env));
}
@@ -9119,7 +9413,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
- qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%x/0x%" PRIx32 "\n",
+ qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%x/0x%" PRIx64 "\n",
syn_get_ec(env->exception.syndrome),
env->exception.syndrome);
}
@@ -9309,21 +9603,34 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
bool el1_is_aa32)
{
uint64_t tcr = regime_tcr(env, mmu_idx);
- bool epd, hpd, tsz_oob, ds, ha, hd;
+ bool epd, hpd, tsz_oob, ds, ha, hd, pie = false;
int select, tsz, tbi, max_tsz, min_tsz, ps, sh;
ARMGranuleSize gran;
ARMCPU *cpu = env_archcpu(env);
bool stage2 = regime_is_stage2(mmu_idx);
+ int r_el = regime_el(mmu_idx);
if (!regime_has_2_ranges(mmu_idx)) {
select = 0;
tsz = extract32(tcr, 0, 6);
gran = tg0_to_gran_size(extract32(tcr, 14, 2));
if (stage2) {
- /* VTCR_EL2 */
- hpd = false;
+ /*
+ * Stage2 does not have hierarchical permissions.
+ * Thus disabling them makes things easier during ptw.
+ */
+ hpd = true;
+ pie = extract64(tcr, 36, 1) && cpu_isar_feature(aa64_s2pie, cpu);
} else {
hpd = extract32(tcr, 24, 1);
+ if (r_el == 3) {
+ pie = (extract64(tcr, 35, 1)
+ && cpu_isar_feature(aa64_s1pie, cpu));
+ } else {
+ pie = ((env->cp15.tcr2_el[2] & TCR2_PIE)
+ && (!arm_feature(env, ARM_FEATURE_EL3)
+ || (env->cp15.scr_el3 & SCR_TCR2EN)));
+ }
}
epd = false;
sh = extract32(tcr, 12, 2);
@@ -9360,10 +9667,16 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
ds = extract64(tcr, 59, 1);
if (e0pd && cpu_isar_feature(aa64_e0pd, cpu) &&
- regime_is_user(env, mmu_idx)) {
+ regime_is_user(mmu_idx)) {
epd = true;
}
+
+ pie = ((env->cp15.tcr2_el[r_el] & TCR2_PIE)
+ && (!arm_feature(env, ARM_FEATURE_EL3)
+ || (env->cp15.scr_el3 & SCR_TCR2EN))
+ && (r_el == 2 || (arm_hcrx_el2_eff(env) & HCRX_TCR2EN)));
}
+ hpd |= pie;
gran = sanitize_gran_size(cpu, gran, stage2);
@@ -9442,6 +9755,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
.ha = ha,
.hd = ha && hd,
.gran = gran,
+ .pie = pie,
};
}
@@ -9556,33 +9870,6 @@ int fp_exception_el(CPUARMState *env, int cur_el)
return 0;
}
-/* Return the exception level we're running at if this is our mmu_idx */
-int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
-{
- if (mmu_idx & ARM_MMU_IDX_M) {
- return mmu_idx & ARM_MMU_IDX_M_PRIV;
- }
-
- switch (mmu_idx) {
- case ARMMMUIdx_E10_0:
- case ARMMMUIdx_E20_0:
- case ARMMMUIdx_E30_0:
- return 0;
- case ARMMMUIdx_E10_1:
- case ARMMMUIdx_E10_1_PAN:
- return 1;
- case ARMMMUIdx_E2:
- case ARMMMUIdx_E20_2:
- case ARMMMUIdx_E20_2_PAN:
- return 2;
- case ARMMMUIdx_E3:
- case ARMMMUIdx_E30_3_PAN:
- return 3;
- default:
- g_assert_not_reached();
- }
-}
-
#ifndef CONFIG_TCG
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
{