- 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.
This commit is contained in:
parent
561087550e
commit
0c7bdc13f0
|
@ -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
|
||||
|
|
|
@ -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 <ryo@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() */;
|
||||
|
||||
|
|
|
@ -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.27 2020/04/13 05:40:25 maxv Exp $");
|
|||
#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.27 2020/04/13 05:40:25 maxv Exp $");
|
|||
#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 = NULL;
|
|||
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, uint32_t *insn)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <ryo@nerv.org>
|
||||
|
@ -89,6 +89,7 @@ void data_abort_handler(struct trapframe *, uint32_t);
|
|||
|
||||
/* 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);
|
||||
|
|
Loading…
Reference in New Issue