xref: /netbsd-src/sys/arch/sparc64/sparc64/vm_machdep.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: vm_machdep.c,v 1.98 2011/10/08 08:49:07 nakayama 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.98 2011/10/08 08:49:07 nakayama 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, *kpmap;
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 	kpmap = vm_map_pmap(kernel_map);
100 	do {
101 		if (pmap_extract(upmap, uva, &pa) == FALSE)
102 			panic("vmapbuf: null page frame");
103 		/* Now map the page into kernel space. */
104 		pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE, 0);
105 
106 		uva += PAGE_SIZE;
107 		kva += PAGE_SIZE;
108 		len -= PAGE_SIZE;
109 	} while (len);
110 	pmap_update(pmap_kernel());
111 
112 	return 0;
113 }
114 
115 /*
116  * Unmap a previously-mapped user I/O request.
117  */
118 void
119 vunmapbuf(struct buf *bp, vsize_t len)
120 {
121 	vaddr_t kva;
122 	vsize_t off;
123 
124 	if ((bp->b_flags & B_PHYS) == 0)
125 		panic("vunmapbuf");
126 
127 	kva = trunc_page((vaddr_t)bp->b_data);
128 	off = (vaddr_t)bp->b_data - kva;
129 	len = round_page(off + len);
130 	pmap_kremove(kva, len);
131 	uvm_km_free(kernel_map, kva, len, UVM_KMF_VAONLY);
132 	bp->b_data = bp->b_saveaddr;
133 	bp->b_saveaddr = NULL;
134 }
135 
136 void
137 cpu_proc_fork(struct proc *p1, struct proc *p2)
138 {
139 
140 	p2->p_md.md_flags = p1->p_md.md_flags;
141 }
142 
143 
144 /*
145  * The offset of the topmost frame in the kernel stack.
146  */
147 #ifdef __arch64__
148 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
149 #define	STACK_OFFSET	BIAS
150 #else
151 #undef	trapframe
152 #define	trapframe	trapframe64
153 #undef	rwindow
154 #define	rwindow		rwindow32
155 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
156 #define	STACK_OFFSET	0
157 #endif
158 
159 #ifdef DEBUG
160 char cpu_forkname[] = "cpu_lwp_fork()";
161 #endif
162 
163 void setfunc_trampoline(void);
164 inline void
165 cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg)
166 {
167 	struct pcb *npcb = lwp_getpcb(l);
168 	struct rwindow *rp;
169 
170 	rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
171 	rp->rw_local[0] = (long)func;		/* Function to call */
172 	rp->rw_local[1] = (long)arg;		/* and its argument */
173 
174 	npcb->pcb_pc = (long)setfunc_trampoline - 8;
175 	npcb->pcb_sp = (long)rp - STACK_OFFSET;
176 }
177 
178 /*
179  * Finish a fork operation, with lwp l2 nearly set up.
180  * Copy and update the pcb and trap frame, making the child ready to run.
181  *
182  * Rig the child's kernel stack so that it will start out in
183  * lwp_trampoline() and call child_return() with l2 as an
184  * argument. This causes the newly-created child process to go
185  * directly to user level with an apparent return value of 0 from
186  * fork(), while the parent process returns normally.
187  *
188  * l1 is the process being forked; if l1 == &lwp0, we are creating
189  * a kernel thread, and the return path and argument are specified with
190  * `func' and `arg'.
191  *
192  * If an alternate user-level stack is requested (with non-zero values
193  * in both the stack and stacksize args), set up the user stack pointer
194  * accordingly.
195  */
196 void lwp_trampoline(void);
197 void
198 cpu_lwp_fork(register struct lwp *l1, register struct lwp *l2, void *stack, size_t stacksize, void (*func)(void *), void *arg)
199 {
200 	struct pcb *opcb = lwp_getpcb(l1);
201 	struct pcb *npcb = lwp_getpcb(l2);
202 	struct trapframe *tf2;
203 	struct rwindow *rp;
204 
205 	/*
206 	 * Save all user registers to l1's stack or, in the case of
207 	 * user registers and invalid stack pointers, to opcb.
208 	 * We then copy the whole pcb to l2; when switch() selects l2
209 	 * to run, it will run at the `lwp_trampoline' stub, rather
210 	 * than returning at the copying code below.
211 	 *
212 	 * If process l1 has an FPU state, we must copy it.  If it is
213 	 * the FPU user, we must save the FPU state first.
214 	 */
215 
216 #ifdef NOTDEF_DEBUG
217 	printf("cpu_lwp_fork()\n");
218 #endif
219 	if (l1 == curlwp) {
220 		write_user_windows();
221 
222 		/*
223 		 * We're in the kernel, so we don't really care about
224 		 * %ccr or %asi.  We do want to duplicate %pstate and %cwp.
225 		 */
226 		opcb->pcb_pstate = getpstate();
227 		opcb->pcb_cwp = getcwp();
228 	}
229 #ifdef DIAGNOSTIC
230 	else if (l1 != &lwp0)
231 		panic("cpu_lwp_fork: curlwp");
232 #endif
233 #ifdef DEBUG
234 	/* prevent us from having NULL lastcall */
235 	opcb->lastcall = cpu_forkname;
236 #else
237 	opcb->lastcall = NULL;
238 #endif
239 	memcpy(npcb, opcb, sizeof(struct pcb));
240        	if (l1->l_md.md_fpstate) {
241        		fpusave_lwp(l1, true);
242 		l2->l_md.md_fpstate = pool_cache_get(fpstate_cache, PR_WAITOK);
243 		memcpy(l2->l_md.md_fpstate, l1->l_md.md_fpstate,
244 		    sizeof(struct fpstate64));
245 	} else
246 		l2->l_md.md_fpstate = NULL;
247 
248 	/*
249 	 * Setup (kernel) stack frame that will by-pass the child
250 	 * out of the kernel. (The trap frame invariably resides at
251 	 * the tippity-top of the u. area.)
252 	 */
253 	tf2 = l2->l_md.md_tf = (struct trapframe *)
254 			((long)npcb + USPACE - sizeof(*tf2));
255 
256 	/* Copy parent's trapframe */
257 	*tf2 = *(struct trapframe *)((long)opcb + USPACE - sizeof(*tf2));
258 
259 	/*
260 	 * If specified, give the child a different stack.
261 	 */
262 	if (stack != NULL)
263 		tf2->tf_out[6] = (uint64_t)(u_long)stack + stacksize;
264 
265 	/*
266 	 * Set return values in child mode and clear condition code,
267 	 * in case we end up running a signal handler before returning
268 	 * to userland.
269 	 */
270 	tf2->tf_out[0] = 0;
271 	tf2->tf_out[1] = 1;
272 	tf2->tf_tstate &= ~TSTATE_CCR;
273 
274 	/* Construct kernel frame to return to in cpu_switch() */
275 	rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
276 	*rp = *(struct rwindow *)((u_long)opcb + TOPFRAMEOFF);
277 
278 	rp->rw_local[0] = (long)func;	/* Function to call */
279 	rp->rw_local[1] = (long)arg;	/* and its argument */
280 	rp->rw_local[2] = (long)l2;	/* new lwp */
281 
282 	npcb->pcb_pc = (long)lwp_trampoline - 8;
283 	npcb->pcb_sp = (long)rp - STACK_OFFSET;
284 }
285 
286 static inline void
287 fpusave_cpu(bool save)
288 {
289 	struct lwp *l = fplwp;
290 
291 	if (l == NULL)
292 		return;
293 
294 	if (save)
295 		savefpstate(l->l_md.md_fpstate);
296 	else
297 		clearfpstate();
298 
299 	fplwp = NULL;
300 }
301 
302 void
303 fpusave_lwp(struct lwp *l, bool save)
304 {
305 #ifdef MULTIPROCESSOR
306 	volatile struct cpu_info *ci;
307 
308 	if (l == fplwp) {
309 		int s = intr_disable();
310 		fpusave_cpu(save);
311 		intr_restore(s);
312 		return;
313 	}
314 
315 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
316 		int spincount;
317 
318 		if (ci == curcpu() || !CPUSET_HAS(cpus_active, ci->ci_index))
319 			continue;
320 		if (ci->ci_fplwp != l)
321 			continue;
322 		sparc64_send_ipi(ci->ci_cpuid, save ?
323 				 sparc64_ipi_save_fpstate :
324 				 sparc64_ipi_drop_fpstate, (uintptr_t)l, 0);
325 
326 		spincount = 0;
327 		while (ci->ci_fplwp == l) {
328 			membar_Sync();
329 			spincount++;
330 			if (spincount > 10000000)
331 				panic("fpusave_lwp ipi didn't");
332 		}
333 		break;
334 	}
335 #else
336 	if (l == fplwp)
337 		fpusave_cpu(save);
338 #endif
339 }
340 
341 
342 void
343 cpu_lwp_free(struct lwp *l, int proc)
344 {
345 
346 	if (l->l_md.md_fpstate != NULL)
347 		fpusave_lwp(l, false);
348 }
349 
350 void
351 cpu_lwp_free2(struct lwp *l)
352 {
353 	struct fpstate64 *fs;
354 
355 	if ((fs = l->l_md.md_fpstate) != NULL)
356 		pool_cache_put(fpstate_cache, fs);
357 }
358 
359 int
360 cpu_lwp_setprivate(lwp_t *l, void *addr)
361 {
362 	struct trapframe *tf = l->l_md.md_tf;
363 
364 	tf->tf_global[7] = (uintptr_t)addr;
365 
366 	return 0;
367 }
368