Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F106272714
D47814.id147076.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D47814.id147076.diff
View Options
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -42,6 +42,7 @@
#include <machine/atomic.h>
#include <machine/cpu.h>
+#include <machine/cpu_feat.h>
#include <machine/cpufunc.h>
#include <machine/elf.h>
#include <machine/md_var.h>
@@ -76,6 +77,8 @@
SYSCTL_INT(_machdep_cache, OID_AUTO, allow_idc, CTLFLAG_RDTUN, &allow_idc, 0,
"Allow optimizations based on the IDC cache bit");
+static bool emulate_ctr = false;
+
static void check_cpu_regs(u_int cpu, struct cpu_desc *desc,
struct cpu_desc *prev_desc);
static uint64_t update_special_reg_field(uint64_t user_reg, u_int type,
@@ -2070,6 +2073,8 @@
USER_REG(ID_AA64ZFR0_EL1, id_aa64zfr0, true),
+ USER_REG(CTR_EL0, ctr, true),
+
#ifdef COMPAT_FREEBSD32
USER_REG(ID_ISAR5_EL1, id_isar5, false),
@@ -2081,6 +2086,134 @@
#define CPU_DESC_FIELD(desc, idx) \
*(uint64_t *)((char *)&(desc) + user_regs[(idx)].offset)
+static bool
+user_ctr_has_neoverse_n1_1542419(uint32_t midr, uint64_t ctr)
+{
+ /* Skip non-Neoverse-N1 */
+ if (!CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, CPU_IMPL_ARM,
+ CPU_PART_NEOVERSE_N1, 0, 0))
+ return (false);
+
+ switch (CPU_VAR(midr)) {
+ default:
+ break;
+ case 4:
+ /* Fixed in r4p1 */
+ if (CPU_REV(midr) > 0)
+ break;
+ /* FALLTHROUGH */
+ case 3:
+ /* If DIC is enabled (coherent icache) then we are affected */
+ return (CTR_DIC_VAL(ctr) != 0);
+ }
+
+ return (false);
+}
+
+static bool
+user_ctr_check(const struct cpu_feat *feat __unused, u_int midr __unused)
+{
+ if (emulate_ctr)
+ return (true);
+
+ if (user_ctr_has_neoverse_n1_1542419(midr, READ_SPECIALREG(ctr_el0)))
+ return (true);
+
+ return (false);
+}
+
+static bool
+user_ctr_has_errata(const struct cpu_feat *feat __unused, u_int midr,
+ u_int *errata_id)
+{
+ if (user_ctr_has_neoverse_n1_1542419(midr, READ_SPECIALREG(ctr_el0))) {
+ *errata_id = 1542419;
+ return (true);
+ }
+
+ return (false);
+}
+
+static void
+user_ctr_enable(const struct cpu_feat *feat __unused,
+ bool has_errata, u_int errata_id __unused)
+{
+ MPASS(emulate_ctr || has_errata);
+
+ if (has_errata && errata_id == 1542419 && PCPU_GET(cpuid) == 0) {
+ /* Clear fields we will change */
+ user_cpu_desc.ctr &= ~(CTR_DIC_MASK | CTR_ILINE_WIDTH);
+
+ /*
+ * Set DIC to none so userspace will execute an 'ic ivau'
+ * instruction that can be trapped by EL3.
+ */
+ user_cpu_desc.ctr |= CTR_DIC_NONE;
+ /*
+ * Set the i-cache line size to be page size to reduce the
+ * number of times userspace needs to execute the 'ic ivau'
+ * instruction. The ctr_el0.IminLine is log2 the number of
+ * 4-byte words the instruction covers. As PAGE_SHIFT is log2
+ * of the number of bytes in a page we need to subtract 2.
+ */
+ user_cpu_desc.ctr |= (PAGE_SHIFT - 2) << CTR_ILINE_SHIFT;
+
+ l_user_cpu_desc.ctr = user_cpu_desc.ctr;
+ }
+
+ WRITE_SPECIALREG(sctlr_el1,
+ READ_SPECIALREG(sctlr_el1) & ~SCTLR_UCT);
+ isb();
+}
+
+static struct cpu_feat user_ctr = {
+ .feat_name = "Trap CTR_EL0",
+ .feat_check = user_ctr_check,
+ .feat_has_errata = user_ctr_has_errata,
+ .feat_enable = user_ctr_enable,
+ .feat_flags = CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU,
+};
+DATA_SET(cpu_feat_set, user_ctr);
+
+static int
+user_ctr_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
+ uint32_t esr)
+{
+ uint64_t value;
+ int reg;
+
+ if ((insn & MRS_MASK) != MRS_VALUE)
+ return (0);
+
+ /* Check if this is the ctr_el0 register */
+ /* TODO: Add macros to armreg.h */
+ if (mrs_Op0(insn) != 3 || mrs_Op1(insn) != 3 || mrs_CRn(insn) != 0 ||
+ mrs_CRm(insn) != 0 || mrs_Op2(insn) != 1)
+ return (0);
+
+ if (SV_CURPROC_ABI() == SV_ABI_FREEBSD)
+ value = user_cpu_desc.ctr;
+ else
+ value = l_user_cpu_desc.ctr;
+ /*
+ * We will handle this instruction, move to the next so we
+ * don't trap here again.
+ */
+ frame->tf_elr += INSN_SIZE;
+
+ reg = MRS_REGISTER(insn);
+ /* If reg is 31 then write to xzr, i.e. do nothing */
+ if (reg == 31)
+ return (1);
+
+ if (reg < nitems(frame->tf_x))
+ frame->tf_x[reg] = value;
+ else if (reg == 30)
+ frame->tf_lr = value;
+
+ return (1);
+}
+
static int
user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
uint32_t esr)
@@ -2491,6 +2624,7 @@
panic("CPU does not support LSE atomic instructions");
#endif
+ install_undef_handler(true, user_ctr_handler);
install_undef_handler(true, user_mrs_handler);
}
SYSINIT(identify_cpu, SI_SUB_CPU, SI_ORDER_MIDDLE, identify_cpu_sysinit, NULL);
@@ -3023,6 +3157,12 @@
}
if (desc->ctr != prev_desc->ctr) {
+ /*
+ * If the cache is different on different cores we should
+ * emulate for userspace to provide a uniform value
+ */
+ emulate_ctr = true;
+
/*
* If the cache type register is different we may
* have a different l1 cache type.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 29, 8:12 AM (8 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14913928
Default Alt Text
D47814.id147076.diff (4 KB)
Attached To
Mode
D47814: arm64: Add support for emulating CTR_EL0
Attached
Detach File
Event Timeline
Log In to Comment