Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: vm_machdep.c,v 1.102 2019/02/11 07:51:46 macallan Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996-2002 Eduardo Horvath.  All rights reserved.
      5  * Copyright (c) 1996
      6  *	The President and Fellows of Harvard College. All rights reserved.
      7  * Copyright (c) 1992, 1993
      8  *	The Regents of the University of California.  All rights reserved.
      9  *
     10  * This software was developed by the Computer Systems Engineering group
     11  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     12  * contributed to Berkeley.
     13  *
     14  * All advertising materials mentioning features or use of this software
     15  * must display the following acknowledgement:
     16  *	This product includes software developed by the University of
     17  *	California, Lawrence Berkeley Laboratory.
     18  *	This product includes software developed by Harvard University.
     19  *
     20  * Redistribution and use in source and binary forms, with or without
     21  * modification, are permitted provided that the following conditions
     22  * are met:
     23  * 1. Redistributions of source code must retain the above copyright
     24  *    notice, this list of conditions and the following disclaimer.
     25  * 2. Redistributions in binary form must reproduce the above copyright
     26  *    notice, this list of conditions and the following disclaimer in the
     27  *    documentation and/or other materials provided with the distribution.
     28  * 3. All advertising materials mentioning features or use of this software
     29  *    must display the following acknowledgement:
     30  *	This product includes software developed by Harvard University.
     31  *	This product includes software developed by the University of
     32  *	California, Berkeley and its contributors.
     33  * 4. Neither the name of the University nor the names of its contributors
     34  *    may be used to endorse or promote products derived from this software
     35  *    without specific prior written permission.
     36  *
     37  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     47  * SUCH DAMAGE.
     48  *
     49  *	@(#)vm_machdep.c	8.2 (Berkeley) 9/23/93
     50  */
     51 
     52 #include <sys/cdefs.h>
     53 __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.102 2019/02/11 07:51:46 macallan Exp $");
     54 
     55 #include "opt_multiprocessor.h"
     56 
     57 #include <sys/param.h>
     58 #include <sys/systm.h>
     59 #include <sys/proc.h>
     60 #include <sys/core.h>
     61 #include <sys/buf.h>
     62 #include <sys/exec.h>
     63 #include <sys/vnode.h>
     64 #include <sys/cpu.h>
     65 
     66 #include <uvm/uvm_extern.h>
     67 
     68 #include <machine/cpu.h>
     69 #include <machine/frame.h>
     70 #include <machine/pcb.h>
     71 #include <machine/trap.h>
     72 #include <sys/bus.h>
     73 
     74 /*
     75  * Map a user I/O request into kernel virtual address space.
     76  * Note: the pages are already locked by uvm_vslock(), so we
     77  * do not need to pass an access_type to pmap_enter().
     78  */
     79 int
     80 vmapbuf(struct buf *bp, vsize_t len)
     81 {
     82 	struct pmap *upmap;
     83 	vaddr_t uva;	/* User VA (map from) */
     84 	vaddr_t kva;	/* Kernel VA (new to) */
     85 	paddr_t pa; 	/* physical address */
     86 	vsize_t off;
     87 
     88 	if ((bp->b_flags & B_PHYS) == 0)
     89 		panic("vmapbuf");
     90 
     91 	bp->b_saveaddr = bp->b_data;
     92 	uva = trunc_page((vaddr_t)bp->b_data);
     93 	off = (vaddr_t)bp->b_data - uva;
     94 	len = round_page(off + len);
     95 	kva = uvm_km_alloc(kernel_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA);
     96 	bp->b_data = (void *)(kva + off);
     97 
     98 	upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
     99 	do {
    100 		if (pmap_extract(upmap, uva, &pa) == FALSE)
    101 			panic("vmapbuf: null page frame");
    102 		/* Now map the page into kernel space. */
    103 		pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE, 0);
    104 
    105 		uva += PAGE_SIZE;
    106 		kva += PAGE_SIZE;
    107 		len -= PAGE_SIZE;
    108 	} while (len);
    109 	pmap_update(pmap_kernel());
    110 
    111 	return 0;
    112 }
    113 
    114 /*
    115  * Unmap a previously-mapped user I/O request.
    116  */
    117 void
    118 vunmapbuf(struct buf *bp, vsize_t len)
    119 {
    120 	vaddr_t kva;
    121 	vsize_t off;
    122 
    123 	if ((bp->b_flags & B_PHYS) == 0)
    124 		panic("vunmapbuf");
    125 
    126 	kva = trunc_page((vaddr_t)bp->b_data);
    127 	off = (vaddr_t)bp->b_data - kva;
    128 	len = round_page(off + len);
    129 	pmap_kremove(kva, len);
    130 	uvm_km_free(kernel_map, kva, len, UVM_KMF_VAONLY);
    131 	bp->b_data = bp->b_saveaddr;
    132 	bp->b_saveaddr = NULL;
    133 }
    134 
    135 void
    136 cpu_proc_fork(struct proc *p1, struct proc *p2)
    137 {
    138 
    139 	p2->p_md.md_flags = p1->p_md.md_flags;
    140 }
    141 
    142 
    143 /*
    144  * The offset of the topmost frame in the kernel stack.
    145  */
    146 #ifdef __arch64__
    147 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
    148 #define	STACK_OFFSET	BIAS
    149 #else
    150 #undef	trapframe
    151 #define	trapframe	trapframe64
    152 #undef	rwindow
    153 #define	rwindow		rwindow32
    154 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
    155 #define	STACK_OFFSET	0
    156 #endif
    157 
    158 #ifdef DEBUG
    159 char cpu_forkname[] = "cpu_lwp_fork()";
    160 #endif
    161 
    162 /*
    163  * Finish a fork operation, with lwp l2 nearly set up.
    164  * Copy and update the pcb and trap frame, making the child ready to run.
    165  *
    166  * Rig the child's kernel stack so that it will start out in
    167  * lwp_trampoline() and call child_return() with l2 as an
    168  * argument. This causes the newly-created child process to go
    169  * directly to user level with an apparent return value of 0 from
    170  * fork(), while the parent process returns normally.
    171  *
    172  * l1 is the process being forked; if l1 == &lwp0, we are creating
    173  * a kernel thread, and the return path and argument are specified with
    174  * `func' and `arg'.
    175  *
    176  * If an alternate user-level stack is requested (with non-zero values
    177  * in both the stack and stacksize args), set up the user stack pointer
    178  * accordingly.
    179  */
    180 void lwp_trampoline(void);
    181 void
    182 cpu_lwp_fork(register struct lwp *l1, register struct lwp *l2, void *stack, size_t stacksize, void (*func)(void *), void *arg)
    183 {
    184 	struct pcb *opcb = lwp_getpcb(l1);
    185 	struct pcb *npcb = lwp_getpcb(l2);
    186 	struct trapframe *tf2;
    187 	struct rwindow *rp;
    188 
    189 	/*
    190 	 * Save all user registers to l1's stack or, in the case of
    191 	 * user registers and invalid stack pointers, to opcb.
    192 	 * We then copy the whole pcb to l2; when switch() selects l2
    193 	 * to run, it will run at the `lwp_trampoline' stub, rather
    194 	 * than returning at the copying code below.
    195 	 *
    196 	 * If process l1 has an FPU state, we must copy it.  If it is
    197 	 * the FPU user, we must save the FPU state first.
    198 	 */
    199 
    200 #ifdef NOTDEF_DEBUG
    201 	printf("cpu_lwp_fork()\n");
    202 #endif
    203 	if (l1 == curlwp) {
    204 		write_user_windows();
    205 
    206 		/*
    207 		 * We're in the kernel, so we don't really care about
    208 		 * %ccr or %asi.  We do want to duplicate %pstate and %cwp.
    209 		 */
    210 		opcb->pcb_pstate = getpstate();
    211 		opcb->pcb_cwp = getcwp();
    212 	}
    213 #ifdef DIAGNOSTIC
    214 	else if (l1 != &lwp0)
    215 		panic("cpu_lwp_fork: curlwp");
    216 #endif
    217 #ifdef DEBUG
    218 	/* prevent us from having NULL lastcall */
    219 	opcb->lastcall = cpu_forkname;
    220 #else
    221 	opcb->lastcall = NULL;
    222 #endif
    223 	memcpy(npcb, opcb, sizeof(struct pcb));
    224        	if (l1->l_md.md_fpstate) {
    225        		fpusave_lwp(l1, true);
    226 		l2->l_md.md_fpstate = pool_cache_get(fpstate_cache, PR_WAITOK);
    227 		memcpy(l2->l_md.md_fpstate, l1->l_md.md_fpstate,
    228 		    sizeof(struct fpstate64));
    229 	} else
    230 		l2->l_md.md_fpstate = NULL;
    231 
    232 	/*
    233 	 * Setup (kernel) stack frame that will by-pass the child
    234 	 * out of the kernel. (The trap frame invariably resides at
    235 	 * the tippity-top of the u. area.)
    236 	 */
    237 	tf2 = l2->l_md.md_tf = (struct trapframe *)
    238 			((long)npcb + USPACE - sizeof(*tf2));
    239 
    240 	/* Copy parent's trapframe */
    241 	*tf2 = *(struct trapframe *)((long)opcb + USPACE - sizeof(*tf2));
    242 
    243 	/*
    244 	 * If specified, give the child a different stack.
    245 	 */
    246 	if (stack != NULL)
    247 		tf2->tf_out[6] = (uint64_t)(u_long)stack + stacksize;
    248 
    249 	/*
    250 	 * Need to create a %tstate if we are forking our first userland
    251 	 * process - in all other cases we inherit from the parent.
    252 	 */
    253 	if (l2->l_proc->p_pid == 1)
    254 		tf2->tf_tstate = (ASI_PRIMARY_NO_FAULT<<TSTATE_ASI_SHIFT) |
    255 		    ((PSTATE_USER)<<TSTATE_PSTATE_SHIFT);
    256 
    257 	/*
    258 	 * Set return values in child mode and clear condition code,
    259 	 * in case we end up running a signal handler before returning
    260 	 * to userland.
    261 	 */
    262 	tf2->tf_out[0] = 0;
    263 	tf2->tf_out[1] = 1;
    264 	tf2->tf_tstate &= ~TSTATE_CCR;
    265 
    266 	/* Construct kernel frame to return to in cpu_switch() */
    267 	rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
    268 	*rp = *(struct rwindow *)((u_long)opcb + TOPFRAMEOFF);
    269 
    270 	rp->rw_local[0] = (long)func;	/* Function to call */
    271 	rp->rw_local[1] = (long)arg;	/* and its argument */
    272 	rp->rw_local[2] = (long)l2;	/* new lwp */
    273 
    274 	npcb->pcb_pc = (long)lwp_trampoline - 8;
    275 	npcb->pcb_sp = (long)rp - STACK_OFFSET;
    276 }
    277 
    278 static inline void
    279 fpusave_cpu(bool save)
    280 {
    281 	struct lwp *l = fplwp;
    282 
    283 	if (l == NULL)
    284 		return;
    285 
    286 	if (save)
    287 		savefpstate(l->l_md.md_fpstate);
    288 	else
    289 		clearfpstate();
    290 
    291 	fplwp = NULL;
    292 }
    293 
    294 void
    295 fpusave_lwp(struct lwp *l, bool save)
    296 {
    297 #ifdef MULTIPROCESSOR
    298 	volatile struct cpu_info *ci;
    299 
    300 	if (l == fplwp) {
    301 		int s = intr_disable();
    302 		fpusave_cpu(save);
    303 		intr_restore(s);
    304 		return;
    305 	}
    306 
    307 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
    308 		int spincount, retrycount=0;
    309 
    310 		if (ci == curcpu() || !CPUSET_HAS(cpus_active, ci->ci_index))
    311 			continue;
    312 		if (ci->ci_fplwp != l)
    313 			continue;
    314 again:
    315 		sparc64_send_ipi(ci->ci_cpuid, save ?
    316 				 sparc64_ipi_save_fpstate :
    317 				 sparc64_ipi_drop_fpstate, (uintptr_t)l, 0);
    318 
    319 		spincount = 0;
    320 		while (ci->ci_fplwp == l) {
    321 			membar_Sync();
    322 			spincount++;
    323 			if (spincount > 10000000) {
    324 				printf("fpusave_lwp ipi didn't (%d)\n", retrycount);
    325 				retrycount++;
    326 				goto again;
    327 			}
    328 		}
    329 		if (retrycount > 0) printf("spincount %d\n", spincount);
    330 		break;
    331 	}
    332 #else
    333 	if (l == fplwp)
    334 		fpusave_cpu(save);
    335 #endif
    336 }
    337 
    338 
    339 void
    340 cpu_lwp_free(struct lwp *l, int proc)
    341 {
    342 
    343 	if (l->l_md.md_fpstate != NULL)
    344 		fpusave_lwp(l, false);
    345 }
    346 
    347 void
    348 cpu_lwp_free2(struct lwp *l)
    349 {
    350 	struct fpstate64 *fs;
    351 
    352 	if ((fs = l->l_md.md_fpstate) != NULL)
    353 		pool_cache_put(fpstate_cache, fs);
    354 }
    355 
    356 int
    357 cpu_lwp_setprivate(lwp_t *l, void *addr)
    358 {
    359 	struct trapframe *tf = l->l_md.md_tf;
    360 
    361 	tf->tf_global[7] = (uintptr_t)addr;
    362 
    363 	return 0;
    364 }
    365