Module Name:    src
Committed By:   ryo
Date:           Wed Jul  1 08:01:07 UTC 2020

Modified Files:
        src/sys/arch/aarch64/aarch64: aarch64_machdep.c cpu.c trap.c
        src/sys/arch/aarch64/include: armreg.h cpu.h machdep.h

Log Message:
- On some systems with a different cache line size (and DIC,IDC) per CPU, trap 
"mrs Xt,ctr_el0" instruction
  to return the minimum cache line size of the system to userland.
- add CLIDR_EL1 and CTR_EL0 to struct aarch64_sysctl_cpu_id.

On most systems, cache line size is the same for all CPUs, so this mechanism 
won't be required.
Rather, this is primarily for errata support, which will be committed later.


To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/sys/arch/aarch64/aarch64/aarch64_machdep.c
cvs rdiff -u -r1.51 -r1.52 src/sys/arch/aarch64/aarch64/cpu.c
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/aarch64/aarch64/trap.c
cvs rdiff -u -r1.49 -r1.50 src/sys/arch/aarch64/include/armreg.h
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/aarch64/include/cpu.h
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/aarch64/include/machdep.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/aarch64/aarch64/aarch64_machdep.c
diff -u src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.43 src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.44
--- src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.43	Sun Jun 21 17:25:03 2020
+++ src/sys/arch/aarch64/aarch64/aarch64_machdep.c	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: aarch64_machdep.c,v 1.43 2020/06/21 17:25:03 jmcneill Exp $ */
+/* $NetBSD: aarch64_machdep.c,v 1.44 2020/07/01 08:01:07 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.43 2020/06/21 17:25:03 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.44 2020/07/01 08:01:07 ryo Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_cpuoptions.h"
@@ -523,6 +523,8 @@ machdep_init(void)
 {
 	/* clear cpu reset hook for early boot */
 	cpu_reset_address0 = NULL;
+
+	configure_cpu_traps();
 }
 
 #ifdef MODULAR

Index: src/sys/arch/aarch64/aarch64/cpu.c
diff -u src/sys/arch/aarch64/aarch64/cpu.c:1.51 src/sys/arch/aarch64/aarch64/cpu.c:1.52
--- src/sys/arch/aarch64/aarch64/cpu.c:1.51	Wed Jul  1 07:59:16 2020
+++ src/sys/arch/aarch64/aarch64/cpu.c	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.51 2020/07/01 07:59:16 ryo Exp $ */
+/* $NetBSD: cpu.c,v 1.52 2020/07/01 08:01:07 ryo Exp $ */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <r...@nerv.org>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.51 2020/07/01 07:59:16 ryo Exp $");
+__KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.52 2020/07/01 08:01:07 ryo Exp $");
 
 #include "locators.h"
 #include "opt_arm_debug.h"
@@ -503,6 +503,9 @@ cpu_setup_id(struct cpu_info *ci)
 	id->ac_mvfr1     = reg_mvfr1_el1_read();
 	id->ac_mvfr2     = reg_mvfr2_el1_read();
 
+	id->ac_clidr     = reg_clidr_el1_read();
+	id->ac_ctr       = reg_ctr_el0_read();
+
 	/* Only in ARMv8.2. */
 	id->ac_aa64zfr0  = 0 /* reg_id_aa64zfr0_el1_read() */;
 

Index: src/sys/arch/aarch64/aarch64/trap.c
diff -u src/sys/arch/aarch64/aarch64/trap.c:1.27 src/sys/arch/aarch64/aarch64/trap.c:1.28
--- src/sys/arch/aarch64/aarch64/trap.c:1.27	Mon Apr 13 05:40:25 2020
+++ src/sys/arch/aarch64/aarch64/trap.c	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.27 2020/04/13 05:40:25 maxv Exp $ */
+/* $NetBSD: trap.c,v 1.28 2020/07/01 08:01:07 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.27 2020/04/13 05:40:25 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.28 2020/07/01 08:01:07 ryo Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -42,6 +42,7 @@ __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.2
 #include <sys/types.h>
 #include <sys/atomic.h>
 #include <sys/cpu.h>
+#include <sys/evcnt.h>
 #ifdef KDB
 #include <sys/kdb.h>
 #endif
@@ -50,6 +51,7 @@ __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.2
 #include <sys/signal.h>
 #include <sys/signalvar.h>
 #include <sys/siginfo.h>
+#include <sys/xcall.h>
 
 #ifdef ARM_INTR_IMPL
 #include ARM_INTR_IMPL
@@ -88,6 +90,12 @@ dtrace_trap_func_t		dtrace_trap_func = N
 int (*dtrace_invop_jump_addr)(struct trapframe *);
 #endif
 
+enum emul_arm_result {
+	EMUL_ARM_SUCCESS = 0,
+	EMUL_ARM_UNKNOWN,
+	EMUL_ARM_FAULT,
+};
+
 const char * const trap_names[] = {
 	[ESR_EC_UNKNOWN]	= "Unknown Reason (Illegal Instruction)",
 	[ESR_EC_SERROR]		= "SError Interrupt",
@@ -247,6 +255,142 @@ trap_el1h_sync(struct trapframe *tf)
 	}
 }
 
+/*
+ * There are some systems with different cache line sizes for each cpu.
+ * Userland programs can be preempted between CPUs at any time, so in such
+ * a system, the minimum cache line size must be visible to userland.
+ */
+#define CTR_EL0_USR_MASK	\
+	(CTR_EL0_DIC | CTR_EL0_IDC | CTR_EL0_DMIN_LINE | CTR_EL0_IMIN_LINE)
+uint64_t ctr_el0_usr __read_mostly;
+
+static xcfunc_t
+configure_cpu_traps0(void *arg1, void *arg2)
+{
+	struct cpu_info * const ci = curcpu();
+	uint64_t sctlr;
+	uint64_t ctr_el0_raw = reg_ctr_el0_read();
+
+#ifdef DEBUG_FORCE_TRAP_CTR_EL0
+	goto need_ctr_trap;
+#endif
+
+	if ((__SHIFTOUT(ctr_el0_raw, CTR_EL0_DMIN_LINE) >
+	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_DMIN_LINE)) ||
+	    (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IMIN_LINE) >
+	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_IMIN_LINE)))
+		goto need_ctr_trap;
+
+	if ((__SHIFTOUT(ctr_el0_raw, CTR_EL0_DIC) == 1 &&
+	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_DIC) == 0) ||
+	    (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IDC) == 1 &&
+	     __SHIFTOUT(ctr_el0_usr, CTR_EL0_IDC) == 0))
+		goto need_ctr_trap;
+
+#if 0 /* XXX: To do or not to do */
+	/*
+	 * IDC==0, but (LoC==0 || LoUIS==LoUU==0)?
+	 * Would it be better to show IDC=1 to userland?
+	 */
+	if (__SHIFTOUT(ctr_el0_raw, CTR_EL0_IDC) == 0 &&
+	    __SHIFTOUT(ctr_el0_usr, CTR_EL0_IDC) == 1)
+		goto need_ctr_trap;
+#endif
+
+	return 0;
+
+ need_ctr_trap:
+	evcnt_attach_dynamic(&ci->ci_uct_trap, EVCNT_TYPE_MISC, NULL,
+	    ci->ci_cpuname, "ctr_el0 trap");
+
+	/* trap CTR_EL0 access from EL0 on this cpu */
+	sctlr = reg_sctlr_el1_read();
+	sctlr &= ~SCTLR_UCT;
+	reg_sctlr_el1_write(sctlr);
+
+	return 0;
+}
+
+void
+configure_cpu_traps(void)
+{
+	CPU_INFO_ITERATOR cii;
+	struct cpu_info *ci;
+	uint64_t where;
+
+	/* remember minimum cache line size out of all CPUs */
+	for (CPU_INFO_FOREACH(cii, ci)) {
+		uint64_t ctr_el0_cpu = ci->ci_id.ac_ctr;
+		uint64_t clidr = ci->ci_id.ac_clidr;
+
+		if (__SHIFTOUT(clidr, CLIDR_LOC) == 0 ||
+		    (__SHIFTOUT(clidr, CLIDR_LOUIS) == 0 &&
+		     __SHIFTOUT(clidr, CLIDR_LOUU) == 0)) {
+			/* this means the same as IDC=1 */
+			ctr_el0_cpu |= CTR_EL0_IDC;
+		}
+
+		/*
+		 * if DIC==1, there is no need to icache sync. however,
+		 * to calculate the minimum cacheline, in this case
+		 * ICacheLine is treated as the maximum.
+		 */
+		if (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_DIC) == 1)
+			ctr_el0_cpu |= CTR_EL0_IMIN_LINE;
+
+		if (cii == 0) {
+			ctr_el0_usr = ctr_el0_cpu;
+			continue;
+		}
+
+		/* keep minimum cache line size, and worst DIC/IDC */
+		ctr_el0_usr &= (ctr_el0_cpu & CTR_EL0_DIC) | ~CTR_EL0_DIC;
+		ctr_el0_usr &= (ctr_el0_cpu & CTR_EL0_IDC) | ~CTR_EL0_IDC;
+		if (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_DMIN_LINE) <
+		    __SHIFTOUT(ctr_el0_usr, CTR_EL0_DMIN_LINE)) {
+			ctr_el0_usr &= ~CTR_EL0_DMIN_LINE;
+			ctr_el0_usr |= ctr_el0_cpu & CTR_EL0_DMIN_LINE;
+		}
+		if ((ctr_el0_cpu & CTR_EL0_DIC) == 0 &&
+		    (__SHIFTOUT(ctr_el0_cpu, CTR_EL0_IMIN_LINE) <
+		    __SHIFTOUT(ctr_el0_usr, CTR_EL0_IMIN_LINE))) {
+			ctr_el0_usr &= ~CTR_EL0_IMIN_LINE;
+			ctr_el0_usr |= ctr_el0_cpu & CTR_EL0_IMIN_LINE;
+		}
+	}
+
+	where = xc_broadcast(0,
+	    (xcfunc_t)configure_cpu_traps0, NULL, NULL);
+	xc_wait(where);
+}
+
+static enum emul_arm_result
+emul_aarch64_insn(struct trapframe *tf)
+{
+	uint32_t insn;
+
+	if (ufetch_32((uint32_t *)tf->tf_pc, &insn))
+		return EMUL_ARM_FAULT;
+
+	if ((insn & 0xffffffe0) == 0xd53b0020) {
+		/* mrs x?,ctr_el0 */
+		unsigned int Xt = insn & 31;
+		if (Xt != 31) {	/* !xzr */
+			uint64_t ctr_el0 = reg_ctr_el0_read();
+			ctr_el0 &= ~CTR_EL0_USR_MASK;
+			ctr_el0 |= (ctr_el0_usr & CTR_EL0_USR_MASK);
+			tf->tf_reg[Xt] = ctr_el0;
+		}
+		curcpu()->ci_uct_trap.ev_count++;
+
+	} else {
+		return EMUL_ARM_UNKNOWN;
+	}
+
+	tf->tf_pc += 4;
+	return EMUL_ARM_SUCCESS;
+}
+
 void
 trap_el0_sync(struct trapframe *tf)
 {
@@ -300,8 +444,23 @@ trap_el0_sync(struct trapframe *tf)
 		userret(l);
 		break;
 
+	case ESR_EC_SYS_REG:
+		switch (emul_aarch64_insn(tf)) {
+		case EMUL_ARM_SUCCESS:
+			break;
+		case EMUL_ARM_UNKNOWN:
+			goto unknown;
+		case EMUL_ARM_FAULT:
+			do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
+			    (void *)tf->tf_pc, esr);
+			break;
+		}
+		userret(l);
+		break;
+
 	default:
 	case ESR_EC_UNKNOWN:
+ unknown:
 #ifdef DDB
 		if (sigill_debug) {
 			/* show illegal instruction */
@@ -386,12 +545,6 @@ fetch_arm_insn(struct trapframe *tf, uin
 	return 4;
 }
 
-enum emul_arm_result {
-	EMUL_ARM_SUCCESS = 0,
-	EMUL_ARM_UNKNOWN,
-	EMUL_ARM_FAULT,
-};
-
 static enum emul_arm_result
 emul_arm_insn(struct trapframe *tf)
 {

Index: src/sys/arch/aarch64/include/armreg.h
diff -u src/sys/arch/aarch64/include/armreg.h:1.49 src/sys/arch/aarch64/include/armreg.h:1.50
--- src/sys/arch/aarch64/include/armreg.h:1.49	Sun Jun 14 16:10:18 2020
+++ src/sys/arch/aarch64/include/armreg.h	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: armreg.h,v 1.49 2020/06/14 16:10:18 riastradh Exp $ */
+/* $NetBSD: armreg.h,v 1.50 2020/07/01 08:01:07 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -1614,6 +1614,10 @@ struct aarch64_sysctl_cpu_id {
 	uint32_t ac_mvfr0;	/* Media and VFP Feature Register 0 */
 	uint32_t ac_mvfr1;	/* Media and VFP Feature Register 1 */
 	uint32_t ac_mvfr2;	/* Media and VFP Feature Register 2 */
+	uint32_t ac_pad;
+
+	uint64_t ac_clidr;	/* Cacle Level ID Register */
+	uint64_t ac_ctr;	/* Cache Type Register */
 };
 
 #endif /* _AARCH64_ARMREG_H_ */

Index: src/sys/arch/aarch64/include/cpu.h
diff -u src/sys/arch/aarch64/include/cpu.h:1.24 src/sys/arch/aarch64/include/cpu.h:1.25
--- src/sys/arch/aarch64/include/cpu.h:1.24	Wed Jul  1 07:59:16 2020
+++ src/sys/arch/aarch64/include/cpu.h	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.24 2020/07/01 07:59:16 ryo Exp $ */
+/* $NetBSD: cpu.h,v 1.25 2020/07/01 08:01:07 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -97,6 +97,7 @@ struct cpu_info {
 	struct evcnt ci_vfp_reuse;
 	struct evcnt ci_vfp_save;
 	struct evcnt ci_vfp_release;
+	struct evcnt ci_uct_trap;
 
 	/* FDT or similar supplied "cpu capacity" */
 	uint32_t ci_capacity_dmips_mhz;

Index: src/sys/arch/aarch64/include/machdep.h
diff -u src/sys/arch/aarch64/include/machdep.h:1.12 src/sys/arch/aarch64/include/machdep.h:1.13
--- src/sys/arch/aarch64/include/machdep.h:1.12	Mon Jun 29 23:22:27 2020
+++ src/sys/arch/aarch64/include/machdep.h	Wed Jul  1 08:01:07 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.h,v 1.12 2020/06/29 23:22:27 riastradh Exp $	*/
+/*	$NetBSD: machdep.h,v 1.13 2020/07/01 08:01:07 ryo Exp $	*/
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <r...@nerv.org>
@@ -89,6 +89,7 @@ void data_abort_handler(struct trapframe
 
 /* trap.c */
 void lwp_trampoline(void);
+void configure_cpu_traps(void);
 void cpu_dosoftints(void);
 void cpu_switchto_softint(struct lwp *, int);
 void dosoftints(void);

Reply via email to