The FEAT_DoubleFault extension adds the following:
* All external aborts on instruction fetches and translation table
walks for instruction fetches must be synchronous. For QEMU this
is already true.
* SCR_EL3 has a new bit NMEA which disables the masking of SError
interrupts by PSTATE.A when the SError interrupt is taken to EL3.
For QEMU we only need to make the bit writable, because we have no
sources of SError interrupts.
* SCR_EL3 has a new bit EASE which causes synchronous external
aborts taken to EL3 to be taken at the same entry point as SError.
(Note that this does not mean that they are SErrors for purposes
of PSTATE.A masking or that the syndrome register reports them as
SErrors: it just means that the vector offset is different.)
* The existing SCTLR_EL3.IESB has an effective value of 1 when
SCR_EL3.NMEA is 1. For QEMU this is a no-op because we don't need
different behaviour based on IESB (we don't need to do anything to
ensure that error exceptions are synchronized).
So for QEMU the things we need to change are:
* Make SCR_EL3.{NMEA,EASE} writable
* When taking a synchronous external abort at EL3, adjust the
vector entry point if SCR_EL3.EASE is set
* Advertise the feature in the ID registers
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id:
20220531151431.949322-1-peter.maydell@linaro.org
- FEAT_Debugv8p2 (Debug changes for v8.2)
- FEAT_Debugv8p4 (Debug changes for v8.4)
- FEAT_DotProd (Advanced SIMD dot product instructions)
+- FEAT_DoubleFault (Double Fault Extension)
- FEAT_FCMA (Floating-point complex number instructions)
- FEAT_FHM (Floating-point half-precision multiplication instructions)
- FEAT_FP16 (Half-precision floating-point data processing)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0;
}
+static inline bool isar_feature_aa64_doublefault(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) >= 2;
+}
+
static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
t = cpu->isar.id_aa64pfr0;
t = FIELD_DP64(t, ID_AA64PFR0, FP, 1); /* FEAT_FP16 */
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1); /* FEAT_FP16 */
- t = FIELD_DP64(t, ID_AA64PFR0, RAS, 1); /* FEAT_RAS */
+ t = FIELD_DP64(t, ID_AA64PFR0, RAS, 2); /* FEAT_RASv1p1 + FEAT_DoubleFault */
t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */
t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */
* we do for EL2 with the virtualization=on property.
*/
t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */
- t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 1); /* FEAT_RASv1p1 */
+ t = FIELD_DP64(t, ID_AA64PFR1, RAS_FRAC, 0); /* FEAT_RASv1p1 + FEAT_DoubleFault */
t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
cpu->isar.id_aa64pfr1 = t;
if (cpu_isar_feature(aa64_scxtnum, cpu)) {
valid_mask |= SCR_ENSCXT;
}
+ if (cpu_isar_feature(aa64_doublefault, cpu)) {
+ valid_mask |= SCR_EASE | SCR_NMEA;
+ }
} else {
valid_mask &= ~(SCR_RW | SCR_ST);
if (cpu_isar_feature(aa32_ras, cpu)) {
return ret;
}
+static bool syndrome_is_sync_extabt(uint32_t syndrome)
+{
+ /* Return true if this syndrome value is a synchronous external abort */
+ switch (syn_get_ec(syndrome)) {
+ case EC_INSNABORT:
+ case EC_INSNABORT_SAME_EL:
+ case EC_DATAABORT:
+ case EC_DATAABORT_SAME_EL:
+ /* Look at fault status code for all the synchronous ext abort cases */
+ switch (syndrome & 0x3f) {
+ case 0x10:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
/* Handle exception entry to a target EL which is using AArch64 */
static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
{
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
+ /*
+ * FEAT_DoubleFault allows synchronous external aborts taken to EL3
+ * to be taken to the SError vector entrypoint.
+ */
+ if (new_el == 3 && (env->cp15.scr_el3 & SCR_EASE) &&
+ syndrome_is_sync_extabt(env->exception.syndrome)) {
+ addr += 0x180;
+ }
env->cp15.far_el[new_el] = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
env->cp15.far_el[new_el]);