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