Commit 05460849 authored by James Morse's avatar James Morse Committed by Catalin Marinas
Browse files

arm64: errata: Hide CTR_EL0.DIC on systems affected by Neoverse-N1 #1542419



Cores affected by Neoverse-N1 #1542419 could execute a stale instruction
when a branch is updated to point to freshly generated instructions.

To workaround this issue we need user-space to issue unnecessary
icache maintenance that we can trap. Start by hiding CTR_EL0.DIC.

Reviewed-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 4f5cafb5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | Neoverse-N1     | #1349291        | N/A                         |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | Neoverse-N1     | #1542419        | ARM64_ERRATUM_1542419       |
+----------------+-----------------+-----------------+-----------------------------+
| ARM            | MMU-500         | #841119,826419  | N/A                         |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
+16 −0
Original line number Diff line number Diff line
@@ -558,6 +558,22 @@ config ARM64_ERRATUM_1463225

	  If unsure, say Y.

config ARM64_ERRATUM_1542419
	bool "Neoverse-N1: workaround mis-ordering of instruction fetches"
	default y
	help
	  This option adds a workaround for ARM Neoverse-N1 erratum
	  1542419.

	  Affected Neoverse-N1 cores could execute a stale instruction when
	  modified by another CPU. The workaround depends on a firmware
	  counterpart.

	  Workaround the issue by hiding the DIC feature from EL0. This
	  forces user-space to perform cache maintenance.

	  If unsure, say Y.

config CAVIUM_ERRATUM_22375
	bool "Cavium erratum 22375, 24313"
	default y
+2 −1
Original line number Diff line number Diff line
@@ -52,7 +52,8 @@
#define ARM64_HAS_IRQ_PRIO_MASKING		42
#define ARM64_HAS_DCPODP			43
#define ARM64_WORKAROUND_1463225		44
#define ARM64_WORKAROUND_1542419		45

#define ARM64_NCAPS				45
#define ARM64_NCAPS				46

#endif /* __ASM_CPUCAPS_H */
+31 −1
Original line number Diff line number Diff line
@@ -87,13 +87,21 @@ has_mismatched_cache_type(const struct arm64_cpu_capabilities *entry,
}

static void
cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused)
cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
{
	u64 mask = arm64_ftr_reg_ctrel0.strict_mask;
	bool enable_uct_trap = false;

	/* Trap CTR_EL0 access on this CPU, only if it has a mismatch */
	if ((read_cpuid_cachetype() & mask) !=
	    (arm64_ftr_reg_ctrel0.sys_val & mask))
		enable_uct_trap = true;

	/* ... or if the system is affected by an erratum */
	if (cap->capability == ARM64_WORKAROUND_1542419)
		enable_uct_trap = true;

	if (enable_uct_trap)
		sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
}

@@ -623,6 +631,18 @@ check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope)
	return (need_wa > 0);
}

static bool __maybe_unused
has_neoverse_n1_erratum_1542419(const struct arm64_cpu_capabilities *entry,
				int scope)
{
	u32 midr = read_cpuid_id();
	bool has_dic = read_cpuid_cachetype() & BIT(CTR_DIC_SHIFT);
	const struct midr_range range = MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1);

	WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
	return is_midr_in_range(midr, &range) && has_dic;
}

#ifdef CONFIG_HARDEN_EL2_VECTORS

static const struct midr_range arm64_harden_el2_vectors[] = {
@@ -851,6 +871,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
		.matches = has_cortex_a76_erratum_1463225,
	},
#endif
#ifdef CONFIG_ARM64_ERRATUM_1542419
	{
		/* we depend on the firmware portion for correctness */
		.desc = "ARM erratum 1542419 (kernel portion)",
		.capability = ARM64_WORKAROUND_1542419,
		.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
		.matches = has_neoverse_n1_erratum_1542419,
		.cpu_enable = cpu_enable_trap_ctr_access,
	},
#endif
	{
	}
+3 −0
Original line number Diff line number Diff line
@@ -470,6 +470,9 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs)
	int rt = ESR_ELx_SYS64_ISS_RT(esr);
	unsigned long val = arm64_ftr_reg_user_value(&arm64_ftr_reg_ctrel0);

	if (cpus_have_const_cap(ARM64_WORKAROUND_1542419))
		val &= ~BIT(CTR_DIC_SHIFT);

	pt_regs_write_reg(regs, rt, val);

	arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);