From 2fef4a9239f881729bf148d7a57caa1ebe22d91f Mon Sep 17 00:00:00 2001 From: visa Date: Thu, 20 Apr 2017 15:42:26 +0000 Subject: [PATCH] Make TCB address available to userspace via the UserLocal register. This lets programs get the address without a system call on OCTEON II and later. Add UserLocal load emulation for systems that do not implement the RDHWR instruction or the UserLocal register. OK guenther@ --- sys/arch/mips64/include/cpu.h | 28 +++++++++++++++++++- sys/arch/mips64/include/mips_cpu.h | 8 +++++- sys/arch/mips64/include/mips_opcode.h | 9 ++++++- sys/arch/mips64/include/tcb.h | 18 ++++++++++--- sys/arch/mips64/mips64/context.S | 17 +++++++++++- sys/arch/mips64/mips64/cpu.c | 3 ++- sys/arch/mips64/mips64/genassym.cf | 3 ++- sys/arch/mips64/mips64/trap.c | 38 ++++++++++++++++++++++++++- sys/arch/octeon/octeon/machdep.c | 14 +++++++++- 9 files changed, 127 insertions(+), 11 deletions(-) diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h index 0f31d10fdad..5213837ace9 100644 --- a/sys/arch/mips64/include/cpu.h +++ b/sys/arch/mips64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.115 2017/04/07 14:17:38 visa Exp $ */ +/* $OpenBSD: cpu.h,v 1.116 2017/04/20 15:42:26 visa Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -414,6 +414,7 @@ void cp0_calibrate(struct cpu_info *); #if defined(_KERNEL) && !defined(_LOCORE) extern register_t protosr; +extern int cpu_has_userlocal; struct exec_package; struct user; @@ -495,6 +496,31 @@ void cp0_set_pagegrain(uint32_t); void cp0_set_trapbase(register_t); u_int cp1_get_prid(void); +static inline uint32_t +cp0_get_hwrena(void) +{ + uint32_t value; + __asm__ volatile ("mfc0 %0, $7" : "=r" (value)); + return value; +} + +static inline void +cp0_set_hwrena(uint32_t value) +{ + __asm__ volatile ("mtc0 %0, $7" : : "r" (value)); +} + +static inline void +cp0_set_userlocal(void *value) +{ + __asm__ volatile ( + " .set push\n" + " .set mips64r2\n" + " dmtc0 %0, $4, 2\n" + " .set pop\n" + : : "r" (value)); +} + /* * Cache routines (may be overridden) */ diff --git a/sys/arch/mips64/include/mips_cpu.h b/sys/arch/mips64/include/mips_cpu.h index 990aa40abdb..9fc30c272e0 100644 --- a/sys/arch/mips64/include/mips_cpu.h +++ b/sys/arch/mips64/include/mips_cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mips_cpu.h,v 1.4 2016/08/14 08:23:52 visa Exp $ */ +/* $OpenBSD: mips_cpu.h,v 1.5 2017/04/20 15:42:26 visa Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -218,6 +218,7 @@ #define COP_0_CONFIG $16 /* MIPS64 release 2 */ +#define COP_0_USERLOCAL $4, 2 #define COP_0_TLB_PG_GRAIN $5, 1 #define COP_0_EBASE $15, 1 @@ -326,6 +327,11 @@ #define PGRAIN_ESP 0x10000000 #define PGRAIN_IEC 0x08000000 +/* + * HWREna register + */ +#define HWRENA_ULR 0x20000000u + #endif /* _KERNEL || _STANDALONE */ #endif /* !_MIPS64_CPUREGS_H_ */ diff --git a/sys/arch/mips64/include/mips_opcode.h b/sys/arch/mips64/include/mips_opcode.h index cf04aa23a43..9c90ec6a29f 100644 --- a/sys/arch/mips64/include/mips_opcode.h +++ b/sys/arch/mips64/include/mips_opcode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mips_opcode.h,v 1.8 2012/09/29 21:37:03 miod Exp $ */ +/* $OpenBSD: mips_opcode.h,v 1.9 2017/04/20 15:42:26 visa Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -170,6 +170,8 @@ typedef union { #define OP_LDL 032 #define OP_LDR 033 +#define OP_SPECIAL3 037 + #define OP_LB 040 #define OP_LH 041 #define OP_LWL 042 @@ -337,4 +339,9 @@ typedef union { #define OP_NMADD 06 #define OP_NMSUB 07 +/* + * Values for the 'func' field when 'op' == OP_SPECIAL3. + */ +#define OP_RDHWR 073 + #endif /* !_MIPS64_MIPS_OPCODE_H_ */ diff --git a/sys/arch/mips64/include/tcb.h b/sys/arch/mips64/include/tcb.h index 9596c9aba71..3c1ab597ea7 100644 --- a/sys/arch/mips64/include/tcb.h +++ b/sys/arch/mips64/include/tcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcb.h,v 1.2 2017/04/13 03:52:25 guenther Exp $ */ +/* $OpenBSD: tcb.h,v 1.3 2017/04/20 15:42:26 visa Exp $ */ /* * Copyright (c) 2011 Philip Guenther @@ -21,8 +21,20 @@ #ifdef _KERNEL -/* Not a real register; just saved in struct mdproc */ -#define TCB_SET(p, addr) ((p)->p_md.md_tcb = (addr)) +static inline void +__mips64_set_tcb(struct proc *p, void *tcb) +{ +#ifdef CPU_MIPS64R2 + extern int cpu_has_userlocal; + + if (cpu_has_userlocal) + cp0_set_userlocal(tcb); +#endif + + p->p_md.md_tcb = tcb; +} + +#define TCB_SET(p, addr) __mips64_set_tcb(p, addr) #define TCB_GET(p) ((p)->p_md.md_tcb) #else /* _KERNEL */ diff --git a/sys/arch/mips64/mips64/context.S b/sys/arch/mips64/mips64/context.S index 7c38d6cf93a..7843e76ae52 100644 --- a/sys/arch/mips64/mips64/context.S +++ b/sys/arch/mips64/mips64/context.S @@ -1,4 +1,4 @@ -/* $OpenBSD: context.S,v 1.58 2017/04/02 03:51:13 visa Exp $ */ +/* $OpenBSD: context.S,v 1.59 2017/04/20 15:42:26 visa Exp $ */ /* * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -285,6 +285,21 @@ ctx3: dmtc0 v0, COP_0_DIAG #endif +#ifdef CPU_MIPS64R2 + /* + * Restore UserLocal register. + */ + lw t1, cpu_has_userlocal + beq t1, zero, 1f + nop + .set push + .set mips64r2 + ld t0, P_TCB(s0) + dmtc0 t0, COP_0_USERLOCAL + .set pop +1: +#endif /* CPU_MIPS64R2 */ + /* * Restore registers and return. */ diff --git a/sys/arch/mips64/mips64/cpu.c b/sys/arch/mips64/mips64/cpu.c index 36466fbc67e..570d5eb63ac 100644 --- a/sys/arch/mips64/mips64/cpu.c +++ b/sys/arch/mips64/mips64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.64 2017/04/07 14:17:38 visa Exp $ */ +/* $OpenBSD: cpu.c,v 1.65 2017/04/20 15:42:26 visa Exp $ */ /* * Copyright (c) 1997-2004 Opsycon AB (www.opsycon.se) @@ -51,6 +51,7 @@ struct cpuset cpus_running; #endif vaddr_t cache_valias_mask; +int cpu_has_userlocal; struct cfattach cpu_ca = { sizeof(struct device), cpumatch, cpuattach diff --git a/sys/arch/mips64/mips64/genassym.cf b/sys/arch/mips64/mips64/genassym.cf index d1e399db392..c5b3c0c67c5 100644 --- a/sys/arch/mips64/mips64/genassym.cf +++ b/sys/arch/mips64/mips64/genassym.cf @@ -1,4 +1,4 @@ -# $OpenBSD: genassym.cf,v 1.14 2016/12/22 15:33:36 visa Exp $ +# $OpenBSD: genassym.cf,v 1.15 2017/04/20 15:42:26 visa Exp $ # # Copyright (c) 1997 Per Fogelstrom / Opsycon AB # @@ -43,6 +43,7 @@ member p_cpu member p_stat member p_vmspace member P_ASTPENDING p_md.md_astpending +member P_TCB p_md.md_tcb struct pcb member pcb_regs diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index 817686c30e1..247d0444cfd 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.122 2017/01/21 05:42:03 guenther Exp $ */ +/* $OpenBSD: trap.c,v 1.123 2017/04/20 15:42:26 visa Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -68,6 +68,7 @@ #include #include #include +#include #include #ifdef DDB @@ -715,9 +716,44 @@ fault_common_no_miss: } case T_RES_INST+T_USER: + { + register_t *regs = (register_t *)trapframe; + caddr_t va; + InstFmt inst; + + /* Compute the instruction's address. */ + va = (caddr_t)trapframe->pc; + if (trapframe->cause & CR_BR_DELAY) + va += 4; + + /* Get the faulting instruction. */ + if (copyin(va, &inst, sizeof(inst)) != 0) { + i = SIGBUS; + typ = BUS_OBJERR; + break; + } + + /* Emulate "RDHWR rt, UserLocal". */ + if (inst.RType.op == OP_SPECIAL3 && + inst.RType.rs == 0 && + inst.RType.rd == 29 && + inst.RType.shamt == 0 && + inst.RType.func == OP_RDHWR) { + regs[inst.RType.rt] = (register_t)TCB_GET(p); + + /* Figure out where to continue. */ + if (trapframe->cause & CR_BR_DELAY) + trapframe->pc = MipsEmulateBranch(trapframe, + trapframe->pc, 0, 0); + else + trapframe->pc += 4; + return; + } + i = SIGILL; typ = ILL_ILLOPC; break; + } case T_COP_UNUSABLE+T_USER: /* diff --git a/sys/arch/octeon/octeon/machdep.c b/sys/arch/octeon/octeon/machdep.c index 29c24d79593..5d5c099a034 100644 --- a/sys/arch/octeon/octeon/machdep.c +++ b/sys/arch/octeon/octeon/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.85 2017/04/07 14:17:38 visa Exp $ */ +/* $OpenBSD: machdep.c,v 1.86 2017/04/20 15:42:26 visa Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -619,8 +619,20 @@ octeon_ioclock_speed(void) void octeon_tlb_init(void) { + uint32_t hwrena = 0; uint32_t pgrain = 0; + /* + * If the UserLocal register is available, let userspace + * access it using the RDHWR instruction. + */ + if (cp0_get_config_3() & CONFIG3_ULRI) { + cp0_set_userlocal(NULL); + hwrena |= HWRENA_ULR; + cpu_has_userlocal = 1; + } + cp0_set_hwrena(hwrena); + #ifdef MIPS_PTE64 pgrain |= PGRAIN_ELPA; #endif -- 2.20.1