xref: /openbsd/sys/arch/sparc64/sparc64/vm_machdep.c (revision 898184e3)
1 /*	$OpenBSD: vm_machdep.c,v 1.29 2013/01/16 19:04:43 miod Exp $	*/
2 /*	$NetBSD: vm_machdep.c,v 1.38 2001/06/30 00:02:20 eeh Exp $ */
3 
4 /*
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/param.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 #include <sys/user.h>
56 #include <sys/core.h>
57 #include <sys/malloc.h>
58 #include <sys/buf.h>
59 #include <sys/exec.h>
60 #include <sys/vnode.h>
61 #include <sys/signalvar.h>
62 
63 #include <uvm/uvm_extern.h>
64 
65 #include <machine/cpu.h>
66 #include <machine/frame.h>
67 #include <machine/trap.h>
68 #include <machine/bus.h>
69 
70 #include <sparc64/sparc64/cache.h>
71 
72 /*
73  * Map a user I/O request into kernel virtual address space.
74  * Note: the pages are already locked by uvm_vslock(), so we
75  * do not need to pass an access_type to pmap_enter().
76  */
77 void
78 vmapbuf(bp, len)
79 	struct buf *bp;
80 	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 	/*
92 	 * XXX:  It might be better to round/trunc to a
93 	 * segment boundary to avoid VAC problems!
94 	 */
95 	bp->b_saveaddr = bp->b_data;
96 	uva = trunc_page((vaddr_t)bp->b_data);
97 	off = (vaddr_t)bp->b_data - uva;
98 	len = round_page(off + len);
99 	kva = uvm_km_valloc_prefer_wait(kernel_map, len, uva);
100 	bp->b_data = (caddr_t)(kva + off);
101 
102 	upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
103 	kpmap = vm_map_pmap(kernel_map);
104 	do {
105 		if (pmap_extract(upmap, uva, &pa) == FALSE)
106 			panic("vmapbuf: null page frame");
107 		/* Now map the page into kernel space. */
108 		pmap_enter(pmap_kernel(), kva,
109 			pa /* | PMAP_NC */,
110 			VM_PROT_READ|VM_PROT_WRITE,
111 			VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
112 
113 		uva += PAGE_SIZE;
114 		kva += PAGE_SIZE;
115 		len -= PAGE_SIZE;
116 	} while (len);
117 	pmap_update(pmap_kernel());
118 }
119 
120 /*
121  * Unmap a previously-mapped user I/O request.
122  */
123 void
124 vunmapbuf(bp, len)
125 	struct buf *bp;
126 	vsize_t len;
127 {
128 	vaddr_t kva;
129 	vsize_t off;
130 
131 	if ((bp->b_flags & B_PHYS) == 0)
132 		panic("vunmapbuf");
133 
134 	kva = trunc_page((vaddr_t)bp->b_data);
135 	off = (vaddr_t)bp->b_data - kva;
136 	len = round_page(off + len);
137 
138 	pmap_remove(pmap_kernel(), kva, kva + len);
139 	pmap_update(pmap_kernel());
140 	uvm_km_free_wakeup(kernel_map, kva, len);
141 	bp->b_data = bp->b_saveaddr;
142 	bp->b_saveaddr = NULL;
143 }
144 
145 
146 /*
147  * The offset of the topmost frame in the kernel stack.
148  */
149 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
150 #define	STACK_OFFSET	BIAS
151 
152 #ifdef DEBUG
153 char cpu_forkname[] = "cpu_fork()";
154 #endif
155 
156 /*
157  * Finish a fork operation, with process p2 nearly set up.
158  * Copy and update the pcb and trap frame, making the child ready to run.
159  *
160  * Rig the child's kernel stack so that it will start out in
161  * proc_trampoline() and call child_return() with p2 as an
162  * argument. This causes the newly-created child process to go
163  * directly to user level with an apparent return value of 0 from
164  * fork(), while the parent process returns normally.
165  *
166  * p1 is the process being forked; if p1 == &proc0, we are creating
167  * a kernel thread, and the return path and argument are specified with
168  * `func' and `arg'.
169  *
170  * If an alternate user-level stack is requested (with non-zero values
171  * in both the stack and stacksize args), set up the user stack pointer
172  * accordingly.
173  */
174 void
175 cpu_fork(p1, p2, stack, stacksize, func, arg)
176 	struct proc *p1, *p2;
177 	void *stack;
178 	size_t stacksize;
179 	void (*func)(void *);
180 	void *arg;
181 {
182 	struct pcb *opcb = &p1->p_addr->u_pcb;
183 	struct pcb *npcb = &p2->p_addr->u_pcb;
184 	struct trapframe *tf2;
185 	struct rwindow *rp;
186 	extern struct proc proc0;
187 
188 	/*
189 	 * Save all user registers to p1's stack or, in the case of
190 	 * user registers and invalid stack pointers, to opcb.
191 	 * We then copy the whole pcb to p2; when switch() selects p2
192 	 * to run, it will run at the `proc_trampoline' stub, rather
193 	 * than returning at the copying code below.
194 	 *
195 	 * If process p1 has an FPU state, we must copy it.  If it is
196 	 * the FPU user, we must save the FPU state first.
197 	 */
198 
199 #ifdef NOTDEF_DEBUG
200 	printf("cpu_fork()\n");
201 #endif
202 	if (p1 == curproc) {
203 		write_user_windows();
204 
205 		/*
206 		 * We're in the kernel, so we don't really care about
207 		 * %ccr or %asi.  We do want to duplicate %pstate and %cwp.
208 		 */
209 		opcb->pcb_pstate = getpstate();
210 		opcb->pcb_cwp = getcwp();
211 	}
212 #ifdef DIAGNOSTIC
213 	else if (p1 != &proc0)
214 		panic("cpu_fork: curproc");
215 #endif
216 #ifdef DEBUG
217 	/* prevent us from having NULL lastcall */
218 	opcb->lastcall = cpu_forkname;
219 #else
220 	opcb->lastcall = NULL;
221 #endif
222 	bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
223 	if (p1->p_md.md_fpstate) {
224 		fpusave_proc(p1, 1);
225 		p2->p_md.md_fpstate = malloc(sizeof(struct fpstate64),
226 		    M_SUBPROC, M_WAITOK);
227 		bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
228 		    sizeof(struct fpstate64));
229 	} else
230 		p2->p_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 = p2->p_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, offset and
245 	 * with space reserved for the frame, and zero the frame pointer.
246 	 */
247 	if (stack != NULL) {
248 		tf2->tf_out[6] = (u_int64_t)(u_long)stack + stacksize
249 		    - (BIAS + CC64FSZ);
250 		tf2->tf_in[6] = 0;
251 	}
252 
253 	/* Duplicate efforts of syscall(), but slightly differently */
254 	if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
255 		/* jmp %g2 (or %g7, deprecated) on success */
256 		tf2->tf_npc = tf2->tf_global[2];
257 	} else {
258 		/*
259 		 * old system call convention: clear C on success
260 		 * note: proc_trampoline() sets a fresh psr when
261 		 * returning to user mode.
262 		 */
263 		/*tf2->tf_psr &= ~PSR_C;   -* success */
264 	}
265 
266 	/* Set return values in child mode */
267 	tf2->tf_out[0] = 0;
268 	tf2->tf_out[1] = 1;
269 
270 	/* Skip trap instruction. */
271 	tf2->tf_pc = tf2->tf_npc;
272 	tf2->tf_npc += 4;
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 	rp->rw_local[0] = (long)func;		/* Function to call */
278 	rp->rw_local[1] = (long)arg;		/* and its argument */
279 
280 	npcb->pcb_pc = (long)proc_trampoline - 8;
281 	npcb->pcb_sp = (long)rp - STACK_OFFSET;
282 
283 	/* Need to create a %tstate if we're forking from proc0. */
284 	if (p1 == &proc0)
285 		tf2->tf_tstate =
286 		    ((u_int64_t)ASI_PRIMARY_NO_FAULT << TSTATE_ASI_SHIFT) |
287 		    ((PSTATE_USER) << TSTATE_PSTATE_SHIFT);
288 	else
289 		/* Clear condition codes and disable FPU. */
290 		tf2->tf_tstate &=
291 		    ~((PSTATE_PEF << TSTATE_PSTATE_SHIFT) | TSTATE_CCR);
292 
293 #ifdef NOTDEF_DEBUG
294 	printf("cpu_fork: Copying over trapframe: otf=%p ntf=%p sp=%p opcb=%p npcb=%p\n",
295 	       (struct trapframe *)((char *)opcb + USPACE - sizeof(*tf2)), tf2, rp, opcb, npcb);
296 	printf("cpu_fork: tstate=%lx pc=%lx npc=%lx rsp=%lx\n",
297 	       (long)tf2->tf_tstate, (long)tf2->tf_pc, (long)tf2->tf_npc,
298 	       (long)(tf2->tf_out[6]));
299 	Debugger();
300 #endif
301 }
302 
303 /*
304  * These are the "function" entry points in locore.s to handle IPI's.
305  */
306 void	ipi_save_fpstate(void);
307 void	ipi_drop_fpstate(void);
308 
309 void
310 fpusave_cpu(struct cpu_info *ci, int save)
311 {
312 	struct proc *p;
313 
314 	KDASSERT(ci == curcpu());
315 
316 	p = ci->ci_fpproc;
317 	if (p == NULL)
318 		return;
319 
320 	if (save)
321 		savefpstate(p->p_md.md_fpstate);
322 	else
323 		clearfpstate();
324 
325 	ci->ci_fpproc = NULL;
326 }
327 
328 void
329 fpusave_proc(struct proc *p, int save)
330 {
331 	struct cpu_info *ci = curcpu();
332 
333 #ifdef MULTIPROCESSOR
334 	if (p == ci->ci_fpproc) {
335 		u_int64_t s = intr_disable();
336 		fpusave_cpu(ci, save);
337 		intr_restore(s);
338 		return;
339 	}
340 
341 	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
342 		if (ci == curcpu())
343 			continue;
344 		if (ci->ci_fpproc != p)
345 			continue;
346 		sparc64_send_ipi(ci->ci_itid,
347 		    save ? ipi_save_fpstate : ipi_drop_fpstate, (vaddr_t)p, 0);
348 		while(ci->ci_fpproc == p)
349 			sparc_membar(Sync);
350 		break;
351 	}
352 #else
353 	if (p == ci->ci_fpproc)
354 		fpusave_cpu(ci, save);
355 #endif
356 }
357 
358 /*
359  * cpu_exit is called as the last action during exit.
360  *
361  * We clean up a little and then call sched_exit() with the old proc
362  * as an argument.  sched_exit() schedules the old vmspace and stack
363  * to be freed, then selects a new process to run.
364  */
365 void
366 cpu_exit(struct proc *p)
367 {
368 	if (p->p_md.md_fpstate != NULL) {
369 		fpusave_proc(p, 0);
370 		free(p->p_md.md_fpstate, M_SUBPROC);
371 	}
372 
373 	pmap_deactivate(p);
374 	sched_exit(p);
375 }
376 
377 /*
378  * cpu_coredump is called to write a core dump header.
379  * (should this be defined elsewhere?  machdep.c?)
380  */
381 int
382 cpu_coredump(p, vp, cred, chdr)
383 	struct proc *p;
384 	struct vnode *vp;
385 	struct ucred *cred;
386 	struct core *chdr;
387 {
388 	int error;
389 	struct md_coredump md_core;
390 	struct coreseg cseg;
391 
392 	CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
393 	chdr->c_hdrsize = ALIGN(sizeof(*chdr));
394 	chdr->c_seghdrsize = ALIGN(sizeof(cseg));
395 	chdr->c_cpusize = sizeof(md_core);
396 
397 	md_core.md_tf = *p->p_md.md_tf;
398 	md_core.md_wcookie = p->p_addr->u_pcb.pcb_wcookie;
399 	if (p->p_md.md_fpstate) {
400 		fpusave_proc(p, 1);
401 		md_core.md_fpstate = *p->p_md.md_fpstate;
402 	} else
403 		bzero((caddr_t)&md_core.md_fpstate,
404 		      sizeof(md_core.md_fpstate));
405 
406 	CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
407 	cseg.c_addr = 0;
408 	cseg.c_size = chdr->c_cpusize;
409 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
410 	    (off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_UNIT, cred, NULL, p);
411 	if (error)
412 		return error;
413 
414 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
415 	    (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
416 	    IO_UNIT, cred, NULL, p);
417 	if (!error)
418 		chdr->c_nseg++;
419 
420 	return error;
421 }
422 
423