xref: /netbsd-src/sys/arch/sparc/sparc/vm_machdep.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: vm_machdep.c,v 1.28 1996/08/02 13:44:48 pk Exp $ */
2 
3 /*
4  * Copyright (c) 1996
5  *	The President and Fellows of Harvard College. All rights reserved.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Lawrence Berkeley Laboratory.
17  *	This product includes software developed by Harvard University.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. All advertising materials mentioning features or use of this software
28  *    must display the following acknowledgement:
29  *	This product includes software developed by Harvard University.
30  *	This product includes software developed by the University of
31  *	California, Berkeley and its contributors.
32  * 4. Neither the name of the University nor the names of its contributors
33  *    may be used to endorse or promote products derived from this software
34  *    without specific prior written permission.
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  *
48  *	@(#)vm_machdep.c	8.2 (Berkeley) 9/23/93
49  */
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/proc.h>
54 #include <sys/user.h>
55 #include <sys/core.h>
56 #include <sys/malloc.h>
57 #include <sys/buf.h>
58 #include <sys/exec.h>
59 #include <sys/vnode.h>
60 #include <sys/map.h>
61 
62 #include <vm/vm.h>
63 #include <vm/vm_kern.h>
64 
65 #include <machine/cpu.h>
66 #include <machine/frame.h>
67 #include <machine/trap.h>
68 
69 #include <sparc/sparc/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 	register vm_offset_t pa;
80 
81 	if (size & CLOFSET || (int)from & CLOFSET || (int)to & CLOFSET)
82 		panic("pagemove 1");
83 	while (size > 0) {
84 		pa = pmap_extract(pmap_kernel(), (vm_offset_t)from);
85 		if (pa == 0)
86 			panic("pagemove 2");
87 		pmap_remove(pmap_kernel(),
88 		    (vm_offset_t)from, (vm_offset_t)from + PAGE_SIZE);
89 		pmap_enter(pmap_kernel(),
90 		    (vm_offset_t)to, pa, VM_PROT_READ|VM_PROT_WRITE, 1);
91 		from += PAGE_SIZE;
92 		to += PAGE_SIZE;
93 		size -= PAGE_SIZE;
94 	}
95 }
96 
97 /*
98  * Wrapper for dvma_mapin() in kernel space,
99  * so drivers need not include VM goo to get at kernel_map.
100  */
101 caddr_t
102 kdvma_mapin(va, len, canwait)
103 	caddr_t	va;
104 	int	len, canwait;
105 {
106 	return ((caddr_t)dvma_mapin(kernel_map, (vm_offset_t)va, len, canwait));
107 }
108 
109 caddr_t
110 dvma_malloc(len, kaddr, flags)
111 	size_t	len;
112 	void	*kaddr;
113 	int	flags;
114 {
115 	vm_offset_t	kva;
116 	vm_offset_t	dva;
117 
118 	len = round_page(len);
119 	kva = (vm_offset_t)malloc(len, M_DEVBUF, flags);
120 	if (kva == NULL)
121 		return (NULL);
122 
123 	*(vm_offset_t *)kaddr = kva;
124 	dva = dvma_mapin(kernel_map, kva, len, (flags & M_NOWAIT) ? 0 : 1);
125 	if (dva == NULL) {
126 		free((void *)kva, M_DEVBUF);
127 		return (NULL);
128 	}
129 	return (caddr_t)dva;
130 }
131 
132 void
133 dvma_free(dva, len, kaddr)
134 	caddr_t	dva;
135 	size_t	len;
136 	void	*kaddr;
137 {
138 	vm_offset_t	kva = *(vm_offset_t *)kaddr;
139 
140 	dvma_mapout((vm_offset_t)dva, kva, round_page(len));
141 	free((void *)kva, M_DEVBUF);
142 }
143 
144 /*
145  * Map a range [va, va+len] of wired virtual addresses in the given map
146  * to a kernel address in DVMA space.
147  */
148 vm_offset_t
149 dvma_mapin(map, va, len, canwait)
150 	struct vm_map	*map;
151 	vm_offset_t	va;
152 	int		len, canwait;
153 {
154 	vm_offset_t	kva, tva;
155 	register int npf, s;
156 	register vm_offset_t pa;
157 	long off, pn;
158 #if defined(SUN4M)
159 	extern int has_iocache;
160 #endif
161 
162 	off = (int)va & PGOFSET;
163 	va -= off;
164 	len = round_page(len + off);
165 	npf = btoc(len);
166 
167 #if defined(SUN4M)
168 	if (!has_iocache)
169 	    kvm_uncache((caddr_t)va, len >> PGSHIFT);
170 #endif
171 
172 	s = splimp();
173 	for (;;) {
174 
175 		pn = rmalloc(dvmamap, npf);
176 
177 		if (pn != 0)
178 			break;
179 		if (canwait) {
180 			(void)tsleep(dvmamap, PRIBIO+1, "physio", 0);
181 			continue;
182 		}
183 		splx(s);
184 		return NULL;
185 	}
186 	splx(s);
187 
188 	kva = tva = rctov(pn);
189 
190 	while (npf--) {
191 		pa = pmap_extract(vm_map_pmap(map), va);
192 		if (pa == 0)
193 			panic("dvma_mapin: null page frame");
194 		pa = trunc_page(pa);
195 
196 #if defined(SUN4M)
197 		if (cputyp == CPU_SUN4M) {
198 			iommu_enter(tva, pa);
199 		} else
200 #endif
201 		{
202 			/*
203 			 * pmap_enter distributes this mapping to all
204 			 * contexts... maybe we should avoid this extra work
205 			 */
206 #ifdef notyet
207 #if defined(SUN4)
208 			if (have_iocache)
209 				pa |= PG_IOC;
210 #endif
211 #endif
212 			pmap_enter(pmap_kernel(), tva,
213 				   pa | PMAP_NC,
214 				   VM_PROT_READ|VM_PROT_WRITE, 1);
215 		}
216 
217 		tva += PAGE_SIZE;
218 		va += PAGE_SIZE;
219 	}
220 	return kva + off;
221 }
222 
223 /*
224  * Remove double map of `va' in DVMA space at `kva'.
225  */
226 void
227 dvma_mapout(kva, va, len)
228 	vm_offset_t	kva, va;
229 	int		len;
230 {
231 	register int s, off;
232 
233 	off = (int)kva & PGOFSET;
234 	kva -= off;
235 	len = round_page(len + off);
236 
237 #if defined(SUN4M)
238 	if (cputyp == CPU_SUN4M)
239 		iommu_remove(kva, len);
240 	else
241 #endif
242 		pmap_remove(pmap_kernel(), kva, kva + len);
243 
244 	s = splimp();
245 	rmfree(dvmamap, btoc(len), vtorc(kva));
246 	wakeup(dvmamap);
247 	splx(s);
248 
249 	if (vactype != VAC_NONE)
250 		cache_flush((caddr_t)va, len);
251 }
252 
253 /*
254  * Map an IO request into kernel virtual address space.
255  */
256 /*ARGSUSED*/
257 void
258 vmapbuf(bp, sz)
259 	register struct buf *bp;
260 	vm_size_t sz;
261 {
262 	register vm_offset_t addr, kva, pa;
263 	register vm_size_t size, off;
264 	register int npf;
265 	struct proc *p;
266 	register struct vm_map *map;
267 
268 	if ((bp->b_flags & B_PHYS) == 0)
269 		panic("vmapbuf");
270 	p = bp->b_proc;
271 	map = &p->p_vmspace->vm_map;
272 	bp->b_saveaddr = bp->b_data;
273 	addr = (vm_offset_t)bp->b_saveaddr;
274 	off = addr & PGOFSET;
275 	size = round_page(bp->b_bcount + off);
276 	kva = kmem_alloc_wait(kernel_map, size);
277 	bp->b_data = (caddr_t)(kva + off);
278 	addr = trunc_page(addr);
279 	npf = btoc(size);
280 	while (npf--) {
281 		pa = pmap_extract(vm_map_pmap(map), (vm_offset_t)addr);
282 		if (pa == 0)
283 			panic("vmapbuf: null page frame");
284 
285 		/*
286 		 * pmap_enter distributes this mapping to all
287 		 * contexts... maybe we should avoid this extra work
288 		 */
289 		pmap_enter(pmap_kernel(), kva,
290 			   pa | PMAP_NC,
291 			   VM_PROT_READ|VM_PROT_WRITE, 1);
292 
293 		addr += PAGE_SIZE;
294 		kva += PAGE_SIZE;
295 	}
296 }
297 
298 /*
299  * Free the io map addresses associated with this IO operation.
300  */
301 /*ARGSUSED*/
302 void
303 vunmapbuf(bp, sz)
304 	register struct buf *bp;
305 	vm_size_t sz;
306 {
307 	register vm_offset_t kva = (vm_offset_t)bp->b_data;
308 	register vm_size_t size, off;
309 
310 	if ((bp->b_flags & B_PHYS) == 0)
311 		panic("vunmapbuf");
312 
313 	kva = (vm_offset_t)bp->b_data;
314 	off = kva & PGOFSET;
315 	size = round_page(bp->b_bcount + off);
316 	kmem_free_wakeup(kernel_map, trunc_page(kva), size);
317 	bp->b_data = bp->b_saveaddr;
318 	bp->b_saveaddr = NULL;
319 	if (vactype != VAC_NONE)
320 		cache_flush(bp->b_un.b_addr, bp->b_bcount - bp->b_resid);
321 }
322 
323 
324 /*
325  * The offset of the topmost frame in the kernel stack.
326  */
327 #define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame))
328 
329 /*
330  * Finish a fork operation, with process p2 nearly set up.
331  * Copy and update the pcb, making the child ready to run, and marking
332  * it so that it can return differently than the parent.
333  *
334  * This function relies on the fact that the pcb is
335  * the first element in struct user.
336  */
337 void
338 cpu_fork(p1, p2)
339 	register struct proc *p1, *p2;
340 {
341 	register struct pcb *opcb = &p1->p_addr->u_pcb;
342 	register struct pcb *npcb = &p2->p_addr->u_pcb;
343 	register struct trapframe *tf2;
344 	register struct rwindow *rp;
345 
346 	/*
347 	 * Save all user registers to p1's stack or, in the case of
348 	 * user registers and invalid stack pointers, to opcb.
349 	 * We then copy the whole pcb to p2; when switch() selects p2
350 	 * to run, it will run at the `proc_trampoline' stub, rather
351 	 * than returning at the copying code below.
352 	 *
353 	 * If process p1 has an FPU state, we must copy it.  If it is
354 	 * the FPU user, we must save the FPU state first.
355 	 */
356 
357 	write_user_windows();
358 	opcb->pcb_psr = getpsr();
359 	bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
360 	if (p1->p_md.md_fpstate) {
361 		if (p1 == fpproc)
362 			savefpstate(p1->p_md.md_fpstate);
363 		p2->p_md.md_fpstate = malloc(sizeof(struct fpstate),
364 		    M_SUBPROC, M_WAITOK);
365 		bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
366 		    sizeof(struct fpstate));
367 	} else
368 		p2->p_md.md_fpstate = NULL;
369 
370 	/*
371 	 * Setup (kernel) stack frame that will by-pass the child
372 	 * out of the kernel. (The trap frame invariably resides at
373 	 * the tippity-top of the u. area.)
374 	 */
375 	tf2 = p2->p_md.md_tf = (struct trapframe *)
376 			((int)npcb + USPACE - sizeof(*tf2));
377 
378 	/* Copy parent's trapframe */
379 	*tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2));
380 
381 	/* Duplicate efforts of syscall(), but slightly differently */
382 	if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
383 		/* jmp %g2 (or %g7, deprecated) on success */
384 		tf2->tf_npc = tf2->tf_global[2];
385 	} else {
386 		/*
387 		 * old system call convention: clear C on success
388 		 * note: proc_trampoline() sets a fresh psr when
389 		 * returning to user mode.
390 		 */
391 		/*tf2->tf_psr &= ~PSR_C;   -* success */
392 	}
393 
394 	/* Set return values in child mode */
395 	tf2->tf_out[0] = 0;
396 	tf2->tf_out[1] = 1;
397 
398 	/* Construct kernel frame to return to in cpu_switch() */
399 	rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF);
400 	rp->rw_local[0] = (int)child_return;	/* Function to call */
401 	rp->rw_local[1] = (int)p2;		/* and its argument */
402 
403 	npcb->pcb_pc = (int)proc_trampoline - 8;
404 	npcb->pcb_sp = (int)rp;
405 	npcb->pcb_psr &= ~PSR_CWP;	/* Run in window #0 */
406 	npcb->pcb_wim = 1;		/* Fence at window #1 */
407 
408 }
409 
410 /*
411  * cpu_set_kpc:
412  *
413  * Arrange for in-kernel execution of a process to continue at the
414  * named pc, as if the code at that address were called as a function
415  * with the current process's process pointer as an argument.
416  *
417  * Note that it's assumed that when the named process returns,
418  * we immediately return to user mode.
419  *
420  * (Note that cpu_fork(), above, uses an open-coded version of this.)
421  */
422 void
423 cpu_set_kpc(p, pc)
424 	struct proc *p;
425 	void (*pc) __P((struct proc *));
426 {
427 	struct pcb *pcb;
428 	struct rwindow *rp;
429 
430 	pcb = &p->p_addr->u_pcb;
431 
432 	rp = (struct rwindow *)((u_int)pcb + TOPFRAMEOFF);
433 	rp->rw_local[0] = (int)pc;		/* Function to call */
434 	rp->rw_local[1] = (int)p;		/* and its argument */
435 
436 	/*
437 	 * Frob PCB:
438 	 *	- arrange to return to proc_trampoline() from cpu_switch()
439 	 *	- point it at the stack frame constructed above
440 	 *	- make it run in a clear set of register windows
441 	 */
442 	pcb->pcb_pc = (int)proc_trampoline - 8;
443 	pcb->pcb_sp = (int)rp;
444 	pcb->pcb_psr &= ~PSR_CWP;	/* Run in window #0 */
445 	pcb->pcb_wim = 1;		/* Fence at window #1 */
446 }
447 
448 /*
449  * cpu_exit is called as the last action during exit.
450  * We release the address space and machine-dependent resources,
451  * including the memory for the user structure and kernel stack.
452  * Since the latter is also the interrupt stack, we release it
453  * from assembly code after switching to a temporary pcb+stack.
454  */
455 void
456 cpu_exit(p)
457 	struct proc *p;
458 {
459 	register struct fpstate *fs;
460 
461 	if ((fs = p->p_md.md_fpstate) != NULL) {
462 		if (p == fpproc) {
463 			savefpstate(fs);
464 			fpproc = NULL;
465 		}
466 		free((void *)fs, M_SUBPROC);
467 	}
468 	vmspace_free(p->p_vmspace);
469 	switchexit(kernel_map, p->p_addr, USPACE);
470 	/* NOTREACHED */
471 }
472 
473 /*
474  * cpu_coredump is called to write a core dump header.
475  * (should this be defined elsewhere?  machdep.c?)
476  */
477 int
478 cpu_coredump(p, vp, cred, chdr)
479 	struct proc *p;
480 	struct vnode *vp;
481 	struct ucred *cred;
482 	struct core *chdr;
483 {
484 	int error;
485 	struct md_coredump md_core;
486 	struct coreseg cseg;
487 
488 	CORE_SETMAGIC(*chdr, COREMAGIC, MID_SPARC, 0);
489 	chdr->c_hdrsize = ALIGN(sizeof(*chdr));
490 	chdr->c_seghdrsize = ALIGN(sizeof(cseg));
491 	chdr->c_cpusize = sizeof(md_core);
492 
493 	md_core.md_tf = *p->p_md.md_tf;
494 	if (p->p_md.md_fpstate) {
495 		if (p == fpproc)
496 			savefpstate(p->p_md.md_fpstate);
497 		md_core.md_fpstate = *p->p_md.md_fpstate;
498 	} else
499 		bzero((caddr_t)&md_core.md_fpstate, sizeof(struct fpstate));
500 
501 	CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_SPARC, CORE_CPU);
502 	cseg.c_addr = 0;
503 	cseg.c_size = chdr->c_cpusize;
504 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
505 	    (off_t)chdr->c_hdrsize, UIO_SYSSPACE,
506 	    IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
507 	if (error)
508 		return error;
509 
510 	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
511 	    (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
512 	    IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
513 	if (!error)
514 		chdr->c_nseg++;
515 
516 	return error;
517 }
518