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.c207
1 files changed, 156 insertions, 51 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 50f61e42ca..85291d5b8e 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2608,6 +2608,39 @@ static uint64_t gt_get_countervalue(CPUARMState *env)
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / gt_cntfrq_period_ns(cpu);
}
+static void gt_update_irq(ARMCPU *cpu, int timeridx)
+{
+ CPUARMState *env = &cpu->env;
+ uint64_t cnthctl = env->cp15.cnthctl_el2;
+ ARMSecuritySpace ss = arm_security_space(env);
+ /* ISTATUS && !IMASK */
+ int irqstate = (env->cp15.c14_timer[timeridx].ctl & 6) == 4;
+
+ /*
+ * If bit CNTHCTL_EL2.CNT[VP]MASK is set, it overrides IMASK.
+ * It is RES0 in Secure and NonSecure state.
+ */
+ if ((ss == ARMSS_Root || ss == ARMSS_Realm) &&
+ ((timeridx == GTIMER_VIRT && (cnthctl & CNTHCTL_CNTVMASK)) ||
+ (timeridx == GTIMER_PHYS && (cnthctl & CNTHCTL_CNTPMASK)))) {
+ irqstate = 0;
+ }
+
+ qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
+ trace_arm_gt_update_irq(timeridx, irqstate);
+}
+
+void gt_rme_post_el_change(ARMCPU *cpu, void *ignored)
+{
+ /*
+ * Changing security state between Root and Secure/NonSecure, which may
+ * happen when switching EL, can change the effective value of CNTHCTL_EL2
+ * mask bits. Update the IRQ state accordingly.
+ */
+ gt_update_irq(cpu, GTIMER_VIRT);
+ gt_update_irq(cpu, GTIMER_PHYS);
+}
+
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
{
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
@@ -2623,13 +2656,9 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
/* Note that this must be unsigned 64 bit arithmetic: */
int istatus = count - offset >= gt->cval;
uint64_t nexttick;
- int irqstate;
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
- irqstate = (istatus && !(gt->ctl & 2));
- qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
-
if (istatus) {
/* Next transition is when count rolls back over to zero */
nexttick = UINT64_MAX;
@@ -2648,14 +2677,14 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
} else {
timer_mod(cpu->gt_timer[timeridx], nexttick);
}
- trace_arm_gt_recalc(timeridx, irqstate, nexttick);
+ trace_arm_gt_recalc(timeridx, nexttick);
} else {
/* Timer disabled: ISTATUS and timer output always clear */
gt->ctl &= ~4;
- qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0);
timer_del(cpu->gt_timer[timeridx]);
trace_arm_gt_recalc_disabled(timeridx);
}
+ gt_update_irq(cpu, timeridx);
}
static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -2759,10 +2788,8 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
* IMASK toggled: don't need to recalculate,
* just set the interrupt line based on ISTATUS
*/
- int irqstate = (oldval & 4) && !(value & 2);
-
- trace_arm_gt_imask_toggle(timeridx, irqstate);
- qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
+ trace_arm_gt_imask_toggle(timeridx);
+ gt_update_irq(cpu, timeridx);
}
}
@@ -2888,6 +2915,21 @@ static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
gt_ctl_write(env, ri, GTIMER_VIRT, value);
}
+static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ ARMCPU *cpu = env_archcpu(env);
+ uint32_t oldval = env->cp15.cnthctl_el2;
+
+ raw_write(env, ri, value);
+
+ if ((oldval ^ value) & CNTHCTL_CNTVMASK) {
+ gt_update_irq(cpu, GTIMER_VIRT);
+ } else if ((oldval ^ value) & CNTHCTL_CNTPMASK) {
+ gt_update_irq(cpu, GTIMER_PHYS);
+ }
+}
+
static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -3342,9 +3384,22 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
}
#ifdef CONFIG_TCG
+static int par_el1_shareability(GetPhysAddrResult *res)
+{
+ /*
+ * The PAR_EL1.SH field must be 0b10 for Device or Normal-NC
+ * memory -- see pseudocode PAREncodeShareability().
+ */
+ if (((res->cacheattrs.attrs & 0xf0) == 0) ||
+ res->cacheattrs.attrs == 0x44 || res->cacheattrs.attrs == 0x40) {
+ return 2;
+ }
+ return res->cacheattrs.shareability;
+}
+
static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
- bool is_secure)
+ ARMSecuritySpace ss)
{
bool ret;
uint64_t par64;
@@ -3352,8 +3407,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
ARMMMUFaultInfo fi = {};
GetPhysAddrResult res = {};
- ret = get_phys_addr_with_secure(env, value, access_type, mmu_idx,
- is_secure, &res, &fi);
+ /*
+ * I_MXTJT: Granule protection checks are not performed on the final address
+ * of a successful translation.
+ */
+ ret = get_phys_addr_with_space_nogpc(env, value, access_type, mmu_idx, ss,
+ &res, &fi);
/*
* ATS operations only do S1 or S1+S2 translations, so we never
@@ -3470,7 +3529,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
par64 |= (1 << 9); /* NS */
}
par64 |= (uint64_t)res.cacheattrs.attrs << 56; /* ATTR */
- par64 |= res.cacheattrs.shareability << 7; /* SH */
+ par64 |= par_el1_shareability(&res) << 7; /* SH */
} else {
uint32_t fsr = arm_fi_to_lfsc(&fi);
@@ -3518,7 +3577,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
uint64_t par64;
ARMMMUIdx mmu_idx;
int el = arm_current_el(env);
- bool secure = arm_is_secure_below_el3(env);
+ ARMSecuritySpace ss = arm_security_space(env);
switch (ri->opc2 & 6) {
case 0:
@@ -3526,10 +3585,9 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
switch (el) {
case 3:
mmu_idx = ARMMMUIdx_E3;
- secure = true;
break;
case 2:
- g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */
+ g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
/* fall through */
case 1:
if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
@@ -3547,10 +3605,9 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
switch (el) {
case 3:
mmu_idx = ARMMMUIdx_E10_0;
- secure = true;
break;
case 2:
- g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */
+ g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
mmu_idx = ARMMMUIdx_Stage1_E0;
break;
case 1:
@@ -3563,18 +3620,18 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
case 4:
/* stage 1+2 NonSecure PL1: ATS12NSOPR, ATS12NSOPW */
mmu_idx = ARMMMUIdx_E10_1;
- secure = false;
+ ss = ARMSS_NonSecure;
break;
case 6:
/* stage 1+2 NonSecure PL0: ATS12NSOUR, ATS12NSOUW */
mmu_idx = ARMMMUIdx_E10_0;
- secure = false;
+ ss = ARMSS_NonSecure;
break;
default:
g_assert_not_reached();
}
- par64 = do_ats_write(env, value, access_type, mmu_idx, secure);
+ par64 = do_ats_write(env, value, access_type, mmu_idx, ss);
A32_BANKED_CURRENT_REG_SET(env, par, par64);
#else
@@ -3591,7 +3648,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t par64;
/* There is no SecureEL2 for AArch32. */
- par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2, false);
+ par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2,
+ ARMSS_NonSecure);
A32_BANKED_CURRENT_REG_SET(env, par, par64);
#else
@@ -3600,6 +3658,22 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
#endif /* CONFIG_TCG */
}
+static CPAccessResult at_e012_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ /*
+ * R_NYXTL: instruction is UNDEFINED if it applies to an Exception level
+ * lower than EL3 and the combination SCR_EL3.{NSE,NS} is reserved. This can
+ * only happen when executing at EL3 because that combination also causes an
+ * illegal exception return. We don't need to check FEAT_RME either, because
+ * scr_write() ensures that the NSE bit is not set otherwise.
+ */
+ if ((env->cp15.scr_el3 & (SCR_NSE | SCR_NS)) == SCR_NSE) {
+ return CP_ACCESS_TRAP;
+ }
+ return CP_ACCESS_OK;
+}
+
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -3607,7 +3681,7 @@ static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
!(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) {
return CP_ACCESS_TRAP;
}
- return CP_ACCESS_OK;
+ return at_e012_access(env, ri, isread);
}
static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -3616,7 +3690,6 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
#ifdef CONFIG_TCG
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
ARMMMUIdx mmu_idx;
- int secure = arm_is_secure_below_el3(env);
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
@@ -3636,7 +3709,6 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
break;
case 6: /* AT S1E3R, AT S1E3W */
mmu_idx = ARMMMUIdx_E3;
- secure = true;
break;
default:
g_assert_not_reached();
@@ -3656,7 +3728,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
}
env->cp15.par_el[1] = do_ats_write(env, value, access_type,
- mmu_idx, secure);
+ mmu_idx, arm_security_space(env));
#else
/* Handled by hardware accelerator. */
g_assert_not_reached();
@@ -4650,6 +4722,21 @@ static int vae1_tlbmask(CPUARMState *env)
return mask;
}
+static int vae2_tlbmask(CPUARMState *env)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ uint16_t mask;
+
+ if (hcr & HCR_E2H) {
+ mask = ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E20_0;
+ } else {
+ mask = ARMMMUIdxBit_E2;
+ }
+ return mask;
+}
+
/* Return 56 if TBI is enabled, 64 otherwise. */
static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx,
uint64_t addr)
@@ -4676,6 +4763,25 @@ static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
return tlbbits_for_regime(env, mmu_idx, addr);
}
+static int vae2_tlbbits(CPUARMState *env, uint64_t addr)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ ARMMMUIdx mmu_idx;
+
+ /*
+ * Only the regime of the mmu_idx below is significant.
+ * Regime EL2&0 has two ranges with separate TBI configuration, while EL2
+ * only has one.
+ */
+ if (hcr & HCR_E2H) {
+ mmu_idx = ARMMMUIdx_E20_2;
+ } else {
+ mmu_idx = ARMMMUIdx_E2;
+ }
+
+ return tlbbits_for_regime(env, mmu_idx, addr);
+}
+
static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -4768,10 +4874,11 @@ static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri,
* flush-last-level-only.
*/
CPUState *cs = env_cpu(env);
- int mask = e2_tlbmask(env);
+ int mask = vae2_tlbmask(env);
uint64_t pageaddr = sextract64(value << 12, 0, 56);
+ int bits = vae2_tlbbits(env, pageaddr);
- tlb_flush_page_by_mmuidx(cs, pageaddr, mask);
+ tlb_flush_page_bits_by_mmuidx(cs, pageaddr, mask, bits);
}
static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -4825,11 +4932,11 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = env_cpu(env);
+ int mask = vae2_tlbmask(env);
uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = tlbbits_for_regime(env, ARMMMUIdx_E2, pageaddr);
+ int bits = vae2_tlbbits(env, pageaddr);
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_E2, bits);
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
}
static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -5001,11 +5108,6 @@ static void tlbi_aa64_rvae1is_write(CPUARMState *env,
do_rvae_write(env, value, vae1_tlbmask(env), true);
}
-static int vae2_tlbmask(CPUARMState *env)
-{
- return ARMMMUIdxBit_E2;
-}
-
static void tlbi_aa64_rvae2_write(CPUARMState *env,
const ARMCPRegInfo *ri,
uint64_t value)
@@ -5461,38 +5563,38 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E1R,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E1W,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E0R,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E0W,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5,
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6,
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7,
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
/* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */
{ .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 0,
@@ -5772,11 +5874,13 @@ static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri,
* Bits that are not included here:
* RW (read from SCR_EL3.RW as needed)
*/
-uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, bool secure)
+uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, ARMSecuritySpace space)
{
uint64_t ret = env->cp15.hcr_el2;
- if (!arm_is_el2_enabled_secstate(env, secure)) {
+ assert(space != ARMSS_Root);
+
+ if (!arm_is_el2_enabled_secstate(env, space)) {
/*
* "This register has no effect if EL2 is not enabled in the
* current Security state". This is ARMv8.4-SecEL2 speak for
@@ -5840,7 +5944,7 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env)
if (arm_feature(env, ARM_FEATURE_M)) {
return 0;
}
- return arm_hcr_el2_eff_secstate(env, arm_is_secure_below_el3(env));
+ return arm_hcr_el2_eff_secstate(env, arm_security_space_below_el3(env));
}
/*
@@ -6141,7 +6245,8 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
* reset values as IMPDEF. We choose to reset to 3 to comply with
* both ARMv7 and ARMv8.
*/
- .access = PL2_RW, .resetvalue = 3,
+ .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 3,
+ .writefn = gt_cnthctl_write, .raw_writefn = raw_write,
.fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) },
{ .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3,
@@ -8033,12 +8138,12 @@ static const ARMCPRegInfo ats1e1_reginfo[] = {
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E1RP,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
{ .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
.fgt = FGT_ATS1E1WP,
- .writefn = ats_write64 },
+ .accessfn = at_e012_access, .writefn = ats_write64 },
};
static const ARMCPRegInfo ats1cp_reginfo[] = {