Make TCB address available to userspace via the UserLocal register.
authorvisa <visa@openbsd.org>
Thu, 20 Apr 2017 15:42:26 +0000 (15:42 +0000)
committervisa <visa@openbsd.org>
Thu, 20 Apr 2017 15:42:26 +0000 (15:42 +0000)
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
sys/arch/mips64/include/mips_cpu.h
sys/arch/mips64/include/mips_opcode.h
sys/arch/mips64/include/tcb.h
sys/arch/mips64/mips64/context.S
sys/arch/mips64/mips64/cpu.c
sys/arch/mips64/mips64/genassym.cf
sys/arch/mips64/mips64/trap.c
sys/arch/octeon/octeon/machdep.c

index 0f31d10..5213837 100644 (file)
@@ -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)
  */
index 990aa40..9fc30c2 100644 (file)
@@ -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
 #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
 
 #define        PGRAIN_ESP              0x10000000
 #define        PGRAIN_IEC              0x08000000
 
+/*
+ * HWREna register
+ */
+#define        HWRENA_ULR              0x20000000u
+
 #endif /* _KERNEL || _STANDALONE */
 
 #endif /* !_MIPS64_CPUREGS_H_ */
index cf04aa2..9c90ec6 100644 (file)
@@ -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_ */
index 9596c9a..3c1ab59 100644 (file)
@@ -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 <guenther@openbsd.org>
 
 #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 */
index 7c38d6c..7843e76 100644 (file)
@@ -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.
         */
index 36466fb..570d5eb 100644 (file)
@@ -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
index d1e399d..c5b3c0c 100644 (file)
@@ -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
index 817686c..247d044 100644 (file)
@@ -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 <machine/frame.h>
 #include <machine/mips_opcode.h>
 #include <machine/regnum.h>
+#include <machine/tcb.h>
 #include <machine/trap.h>
 
 #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:
                /*
index 29c24d7..5d5c099 100644 (file)
@@ -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