xref: /netbsd/sys/arch/sparc64/sparc64/vm_machdep.c (revision c4a72b64)
1 /*	$NetBSD: vm_machdep.c,v 1.46 2002/09/25 22:21:23 thorpej 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/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 
62 #include <uvm/uvm_extern.h>
63 
64 #include <machine/cpu.h>
65 #include <machine/frame.h>
66 #include <machine/trap.h>
67 #include <machine/bus.h>
68 
69 #include <sparc64/sparc64/cache.h>
70 
71 /*
72  * Move pages from one kernel virtual address to another.
73  */
74 void
75 pagemove(from, to, size)
76 	register caddr_t from, to;
77 	size_t size;
78 {
79 	paddr_t pa;
80 
81 	if (size & PGOFSET || (long)from & PGOFSET || (long)to & PGOFSET)
82 		panic("pagemove 1");
83 
84 	while (size > 0) {
85 		if (pmap_extract(pmap_kernel(), (vaddr_t)from, &pa) == FALSE)
86 			panic("pagemove 2");
87 		pmap_kremove((vaddr_t)from, PAGE_SIZE);
88 		pmap_kenter_pa((vaddr_t)to, pa, VM_PROT_READ | VM_PROT_WRITE);
89 		from += PAGE_SIZE;
90 		to += PAGE_SIZE;
91 		size -= PAGE_SIZE;
92 	}
93 	pmap_update(pmap_kernel());
94 }
95 
96 /*
97  * Map a user I/O request into kernel virtual address space.
98  * Note: the pages are already locked by uvm_vslock(), so we
99  * do not need to pass an access_type to pmap_enter().
100  */
101 void
102 vmapbuf(bp, len)
103 	struct buf *bp;
104 	vsize_t len;
105 {
106 	struct pmap *upmap, *kpmap;
107 	vaddr_t uva;	/* User VA (map from) */
108 	vaddr_t kva;	/* Kernel VA (new to) */
109 	paddr_t pa; 	/* physical address */
110 	vsize_t off;
111 
112 	if ((bp->b_flags & B_PHYS) == 0)
113 		panic("vmapbuf");
114 
115 	bp->b_saveaddr = bp->b_data;
116 	uva = trunc_page((vaddr_t)bp->b_data);
117 	off = (vaddr_t)bp->b_data - uva;
118 	len = round_page(off + len);
119 	kva = uvm_km_valloc_wait(kernel_map, len);
120 	bp->b_data = (caddr_t)(kva + off);
121 
122 	upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
123 	kpmap = vm_map_pmap(kernel_map);
124 	do {
125 		if (pmap_extract(upmap, uva, &pa) == FALSE)
126 			panic("vmapbuf: null page frame");
127 		/* Now map the page into kernel space. */
128 		pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE);
129 
130 		uva += PAGE_SIZE;
131 		kva += PAGE_SIZE;
132 		len -= PAGE_SIZE;
133 	} while (len);
134 	pmap_update(pmap_kernel());
135 }
136 
137 /*
138  * Unmap a previously-mapped user I/O request.
139  */
140 void
141 vunmapbuf(bp, len)
142 	struct buf *bp;
143 	vsize_t len;
144 {
145 	vaddr_t kva;
146 	vsize_t off;
147 
148 	if ((bp->b_flags & B_PHYS) == 0)
149 		panic("vunmapbuf");
150 
151 	kva = trunc_page((vaddr_t)bp->b_data);
152 	off = (vaddr_t)bp->b_data - kva;
153 	len = round_page(off + len);
154 	pmap_kremove(kva, len);
155 	uvm_km_free_wakeup(kernel_map, kva, len);
156 	bp->b_data = bp->b_saveaddr;
157 	bp->b_saveaddr = NULL;
158 }
159 
160 
161 /*
162  * The offset of the topmost frame in the kernel stack.
163  */
164 #ifdef __arch64__
165 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
166 #define	STACK_OFFSET	BIAS
167 #else
168 #undef	trapframe
169 #define	trapframe	trapframe64
170 #undef	rwindow
171 #define	rwindow		rwindow32
172 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-CC64FSZ)
173 #define	STACK_OFFSET	0
174 #endif
175 
176 #ifdef DEBUG
177 char cpu_forkname[] = "cpu_fork()";
178 #endif
179 
180 /*
181  * Finish a fork operation, with process p2 nearly set up.
182  * Copy and update the pcb and trap frame, making the child ready to run.
183  *
184  * Rig the child's kernel stack so that it will start out in
185  * proc_trampoline() and call child_return() with p2 as an
186  * argument. This causes the newly-created child process to go
187  * directly to user level with an apparent return value of 0 from
188  * fork(), while the parent process returns normally.
189  *
190  * p1 is the process being forked; if p1 == &proc0, we are creating
191  * a kernel thread, and the return path and argument are specified with
192  * `func' and `arg'.
193  *
194  * If an alternate user-level stack is requested (with non-zero values
195  * in both the stack and stacksize args), set up the user stack pointer
196  * accordingly.
197  */
198 void
199 cpu_fork(p1, p2, stack, stacksize, func, arg)
200 	register struct proc *p1, *p2;
201 	void *stack;
202 	size_t stacksize;
203 	void (*func) __P((void *));
204 	void *arg;
205 {
206 	struct pcb *opcb = &p1->p_addr->u_pcb;
207 	struct pcb *npcb = &p2->p_addr->u_pcb;
208 	struct trapframe *tf2;
209 	struct rwindow *rp;
210 	extern struct proc proc0;
211 
212 	/*
213 	 * Save all user registers to p1's stack or, in the case of
214 	 * user registers and invalid stack pointers, to opcb.
215 	 * We then copy the whole pcb to p2; when switch() selects p2
216 	 * to run, it will run at the `proc_trampoline' stub, rather
217 	 * than returning at the copying code below.
218 	 *
219 	 * If process p1 has an FPU state, we must copy it.  If it is
220 	 * the FPU user, we must save the FPU state first.
221 	 */
222 
223 	if (p1 == curproc) {
224 		write_user_windows();
225 
226 		/*
227 		 * We're in the kernel, so we don't really care about
228 		 * %ccr or %asi.  We do want to duplicate %pstate and %cwp.
229 		 */
230 		opcb->pcb_pstate = getpstate();
231 		opcb->pcb_cwp = getcwp();
232 	}
233 #ifdef DIAGNOSTIC
234 	else if (p1 != &proc0)
235 		panic("cpu_fork: curproc");
236 #endif
237 #ifdef DEBUG
238 	/* prevent us from having NULL lastcall */
239 	opcb->lastcall = cpu_forkname;
240 #else
241 	opcb->lastcall = NULL;
242 #endif
243 	bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
244        	if (p1->p_md.md_fpstate) {
245 		if (p1 == fpproc) {
246 			savefpstate(p1->p_md.md_fpstate);
247 			fpproc = NULL;
248 		}
249 		p2->p_md.md_fpstate = malloc(sizeof(struct fpstate64),
250 		    M_SUBPROC, M_WAITOK);
251 		bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
252 		    sizeof(struct fpstate64));
253 	} else
254 		p2->p_md.md_fpstate = NULL;
255 
256 	if (p1->p_flag & P_32)
257 		p2->p_flag |= P_32;
258 
259 	/*
260 	 * Setup (kernel) stack frame that will by-pass the child
261 	 * out of the kernel. (The trap frame invariably resides at
262 	 * the tippity-top of the u. area.)
263 	 */
264 	tf2 = p2->p_md.md_tf = (struct trapframe *)
265 			((long)npcb + USPACE - sizeof(*tf2));
266 
267 	/* Copy parent's trapframe */
268 	*tf2 = *(struct trapframe *)((long)opcb + USPACE - sizeof(*tf2));
269 
270 	/*
271 	 * If specified, give the child a different stack.
272 	 */
273 	if (stack != NULL)
274 		tf2->tf_out[6] = (u_int64_t)(u_long)stack + stacksize;
275 
276 	/* Duplicate efforts of syscall(), but slightly differently */
277 	if (tf2->tf_global[1] & SYSCALL_G7RFLAG) {
278 		/* jmp %g2 (or %g7, deprecated) on success */
279 		tf2->tf_npc = tf2->tf_global[7];
280 	} else if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
281 		/* jmp %g2 (or %g7, deprecated) on success */
282 		tf2->tf_npc = tf2->tf_global[2];
283 	} else {
284 		/*
285 		 * old system call convention: clear C on success
286 		 * note: proc_trampoline() sets a fresh psr when
287 		 * returning to user mode.
288 		 */
289 		/*tf2->tf_psr &= ~PSR_C;   -* success */
290 	}
291 
292 	/* Set return values in child mode */
293 	tf2->tf_out[0] = 0;
294 	tf2->tf_out[1] = 1;
295 
296 	/* Construct kernel frame to return to in cpu_switch() */
297 	rp = (struct rwindow *)((u_long)npcb + TOPFRAMEOFF);
298 	*rp = *(struct rwindow *)((u_long)opcb + TOPFRAMEOFF);
299 	rp->rw_local[0] = (long)func;		/* Function to call */
300 	rp->rw_local[1] = (long)arg;		/* and its argument */
301 
302 	npcb->pcb_pc = (long)proc_trampoline - 8;
303 	npcb->pcb_sp = (long)rp - STACK_OFFSET;
304 
305 	/* Need to create a %tstate if we're forking from proc0 */
306 	if (p1 == &proc0)
307 		tf2->tf_tstate = (ASI_PRIMARY_NO_FAULT<<TSTATE_ASI_SHIFT) |
308 			((PSTATE_USER)<<TSTATE_PSTATE_SHIFT);
309 	else
310 		tf2->tf_tstate &= ~(PSTATE_PEF<<TSTATE_PSTATE_SHIFT);
311 
312 #ifdef NOTDEF_DEBUG
313 	printf("cpu_fork: Copying over trapframe: otf=%p ntf=%p sp=%p opcb=%p npcb=%p\n",
314 	       (struct trapframe *)((int)opcb + USPACE - sizeof(*tf2)), tf2, rp, opcb, npcb);
315 	printf("cpu_fork: tstate=%x:%x pc=%x:%x npc=%x:%x rsp=%x\n",
316 	       (long)(tf2->tf_tstate>>32), (long)tf2->tf_tstate,
317 	       (long)(tf2->tf_pc>>32), (long)tf2->tf_pc,
318 	       (long)(tf2->tf_npc>>32), (long)tf2->tf_npc,
319 	       (long)(tf2->tf_out[6]));
320 	Debugger();
321 #endif
322 }
323 
324 /*
325  * cpu_exit is called as the last action during exit.
326  *
327  * We clean up a little and then call switchexit() with the old proc
328  * as an argument.  switchexit() switches to the idle context, schedules
329  * the old vmspace and stack to be freed, then selects a new process to
330  * run.
331  */
332 void
333 cpu_exit(p)
334 	struct proc *p;
335 {
336 	register struct fpstate64 *fs;
337 
338 	if ((fs = p->p_md.md_fpstate) != NULL) {
339 		if (p == fpproc) {
340 			savefpstate(fs);
341 			fpproc = NULL;
342 		}
343 		free((void *)fs, M_SUBPROC);
344 	}
345 	switchexit(p);
346 	/* NOTREACHED */
347 }
348 
349 /*
350  * cpu_coredump is called to write a core dump header.
351  * (should this be defined elsewhere?  machdep.c?)
352  */
353 int
354 cpu_coredump(p, vp, cred, chdr)
355 	struct proc *p;
356 	struct vnode *vp;
357 	struct ucred *cred;
358 	struct core *chdr;
359 {
360 	int error;
361 	struct md_coredump md_core;
362 	struct coreseg cseg;
363 
364 	CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
365 	chdr->c_hdrsize = ALIGN(sizeof(*chdr));
366 	chdr->c_seghdrsize = ALIGN(sizeof(cseg));
367 	chdr->c_cpusize = sizeof(md_core);
368 
369 	/* Copy important fields over. */
370 	md_core.md_tf.tf_tstate = p->p_md.md_tf->tf_tstate;
371 	md_core.md_tf.tf_pc = p->p_md.md_tf->tf_pc;
372 	md_core.md_tf.tf_npc = p->p_md.md_tf->tf_npc;
373 	md_core.md_tf.tf_y = p->p_md.md_tf->tf_y;
374 	md_core.md_tf.tf_tt = p->p_md.md_tf->tf_tt;
375 	md_core.md_tf.tf_pil = p->p_md.md_tf->tf_pil;
376 	md_core.md_tf.tf_oldpil = p->p_md.md_tf->tf_oldpil;
377 
378 	md_core.md_tf.tf_global[0] = p->p_md.md_tf->tf_global[0];
379 	md_core.md_tf.tf_global[1] = p->p_md.md_tf->tf_global[1];
380 	md_core.md_tf.tf_global[2] = p->p_md.md_tf->tf_global[2];
381 	md_core.md_tf.tf_global[3] = p->p_md.md_tf->tf_global[3];
382 	md_core.md_tf.tf_global[4] = p->p_md.md_tf->tf_global[4];
383 	md_core.md_tf.tf_global[5] = p->p_md.md_tf->tf_global[5];
384 	md_core.md_tf.tf_global[6] = p->p_md.md_tf->tf_global[6];
385 	md_core.md_tf.tf_global[7] = p->p_md.md_tf->tf_global[7];
386 
387 	md_core.md_tf.tf_out[0] = p->p_md.md_tf->tf_out[0];
388 	md_core.md_tf.tf_out[1] = p->p_md.md_tf->tf_out[1];
389 	md_core.md_tf.tf_out[2] = p->p_md.md_tf->tf_out[2];
390 	md_core.md_tf.tf_out[3] = p->p_md.md_tf->tf_out[3];
391 	md_core.md_tf.tf_out[4] = p->p_md.md_tf->tf_out[4];
392 	md_core.md_tf.tf_out[5] = p->p_md.md_tf->tf_out[5];
393 	md_core.md_tf.tf_out[6] = p->p_md.md_tf->tf_out[6];
394 	md_core.md_tf.tf_out[7] = p->p_md.md_tf->tf_out[7];
395 
396 #ifdef DEBUG
397 	md_core.md_tf.tf_local[0] = p->p_md.md_tf->tf_local[0];
398 	md_core.md_tf.tf_local[1] = p->p_md.md_tf->tf_local[1];
399 	md_core.md_tf.tf_local[2] = p->p_md.md_tf->tf_local[2];
400 	md_core.md_tf.tf_local[3] = p->p_md.md_tf->tf_local[3];
401 	md_core.md_tf.tf_local[4] = p->p_md.md_tf->tf_local[4];
402 	md_core.md_tf.tf_local[5] = p->p_md.md_tf->tf_local[5];
403 	md_core.md_tf.tf_local[6] = p->p_md.md_tf->tf_local[6];
404 	md_core.md_tf.tf_local[7] = p->p_md.md_tf->tf_local[7];
405 
406 	md_core.md_tf.tf_in[0] = p->p_md.md_tf->tf_in[0];
407 	md_core.md_tf.tf_in[1] = p->p_md.md_tf->tf_in[1];
408 	md_core.md_tf.tf_in[2] = p->p_md.md_tf->tf_in[2];
409 	md_core.md_tf.tf_in[3] = p->p_md.md_tf->tf_in[3];
410 	md_core.md_tf.tf_in[4] = p->p_md.md_tf->tf_in[4];
411 	md_core.md_tf.tf_in[5] = p->p_md.md_tf->tf_in[5];
412 	md_core.md_tf.tf_in[6] = p->p_md.md_tf->tf_in[6];
413 	md_core.md_tf.tf_in[7] = p->p_md.md_tf->tf_in[7];
414 #endif
415 	if (p->p_md.md_fpstate) {
416 		if (p == fpproc) {
417 			savefpstate(p->p_md.md_fpstate);
418 			fpproc = NULL;
419 		}
420 		md_core.md_fpstate = *p->p_md.md_fpstate;
421 	} else
422 		bzero((caddr_t)&md_core.md_fpstate,
423 		      sizeof(md_core.md_fpstate));
424 
425 	CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
426 	cseg.c_addr = 0;
427 	cseg.c_size = chdr->c_cpusize;
428 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
429 	    (off_t)chdr->c_hdrsize, UIO_SYSSPACE,
430 	    IO_NODELOCKED|IO_UNIT, cred, NULL, p);
431 	if (error)
432 		return error;
433 
434 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
435 	    (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
436 	    IO_NODELOCKED|IO_UNIT, cred, NULL, p);
437 	if (!error)
438 		chdr->c_nseg++;
439 
440 	return error;
441 }
442 
443