vm_machdep.c revision 12417
1/*-
2 * Copyright (c) 1982, 1986 The Regents of the University of California.
3 * Copyright (c) 1989, 1990 William Jolitz
4 * Copyright (c) 1994 John Dyson
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department, and William Jolitz.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *	from: @(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
40 *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
41 *	$Id: vm_machdep.c,v 1.44 1995/11/18 06:54:11 bde Exp $
42 */
43
44#include "npx.h"
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/proc.h>
48#include <sys/malloc.h>
49#include <sys/buf.h>
50#include <sys/vnode.h>
51#include <sys/user.h>
52
53#include <machine/clock.h>
54#include <machine/cpu.h>
55#include <machine/md_var.h>
56
57#include <vm/vm.h>
58#include <vm/vm_kern.h>
59#include <vm/vm_page.h>
60
61#include <i386/isa/isa.h>
62
63extern void	pagemove __P((caddr_t from, caddr_t to, int size));
64extern void	setredzone __P((u_short *pte, caddr_t vaddr));
65extern void	vm_fault_quick __P((caddr_t v, int prot));
66
67#ifdef BOUNCE_BUFFERS
68extern vm_offset_t
69		vm_bounce_kva __P((int size, int waitok));
70extern void	vm_bounce_kva_free __P((vm_offset_t addr, vm_offset_t size,
71					int now));
72extern vm_offset_t
73		vm_bounce_page_find __P((int count));
74extern void	vm_bounce_page_free __P((vm_offset_t pa, int count));
75
76volatile int	kvasfreecnt;
77
78caddr_t		bouncememory;
79int		bouncepages, bpwait;
80vm_offset_t	*bouncepa;
81int		bmwait, bmfreeing;
82
83#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
84int		bounceallocarraysize;
85unsigned	*bounceallocarray;
86int		bouncefree;
87
88#define SIXTEENMEG (4096*4096)
89#define MAXBKVA 1024
90int		maxbkva = MAXBKVA*NBPG;
91
92/* special list that can be used at interrupt time for eventual kva free */
93struct kvasfree {
94	vm_offset_t addr;
95	vm_offset_t size;
96} kvaf[MAXBKVA];
97
98/*
99 * get bounce buffer pages (count physically contiguous)
100 * (only 1 inplemented now)
101 */
102vm_offset_t
103vm_bounce_page_find(count)
104	int count;
105{
106	int bit;
107	int s,i;
108
109	if (count != 1)
110		panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
111
112	s = splbio();
113retry:
114	for (i = 0; i < bounceallocarraysize; i++) {
115		if (bounceallocarray[i] != 0xffffffff) {
116			bit = ffs(~bounceallocarray[i]);
117			if (bit) {
118				bounceallocarray[i] |= 1 << (bit - 1) ;
119				bouncefree -= count;
120				splx(s);
121				return bouncepa[(i * BITS_IN_UNSIGNED + (bit - 1))];
122			}
123		}
124	}
125	bpwait = 1;
126	tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
127	goto retry;
128}
129
130void
131vm_bounce_kva_free(addr, size, now)
132	vm_offset_t addr;
133	vm_offset_t size;
134	int now;
135{
136	int s = splbio();
137	kvaf[kvasfreecnt].addr = addr;
138	kvaf[kvasfreecnt].size = size;
139	++kvasfreecnt;
140	if( now) {
141		/*
142		 * this will do wakeups
143		 */
144		vm_bounce_kva(0,0);
145	} else {
146		if (bmwait) {
147		/*
148		 * if anyone is waiting on the bounce-map, then wakeup
149		 */
150			wakeup((caddr_t) io_map);
151			bmwait = 0;
152		}
153	}
154	splx(s);
155}
156
157/*
158 * free count bounce buffer pages
159 */
160void
161vm_bounce_page_free(pa, count)
162	vm_offset_t pa;
163	int count;
164{
165	int allocindex;
166	int index;
167	int bit;
168
169	if (count != 1)
170		panic("vm_bounce_page_free -- no support for > 1 page yet!!!");
171
172	for(index=0;index<bouncepages;index++) {
173		if( pa == bouncepa[index])
174			break;
175	}
176
177	if( index == bouncepages)
178		panic("vm_bounce_page_free: invalid bounce buffer");
179
180	allocindex = index / BITS_IN_UNSIGNED;
181	bit = index % BITS_IN_UNSIGNED;
182
183	bounceallocarray[allocindex] &= ~(1 << bit);
184
185	bouncefree += count;
186	if (bpwait) {
187		bpwait = 0;
188		wakeup((caddr_t) &bounceallocarray);
189	}
190}
191
192/*
193 * allocate count bounce buffer kva pages
194 */
195vm_offset_t
196vm_bounce_kva(size, waitok)
197	int size;
198	int waitok;
199{
200	int i;
201	vm_offset_t kva = 0;
202	vm_offset_t off;
203	int s = splbio();
204more:
205	if (!bmfreeing && kvasfreecnt) {
206		bmfreeing = 1;
207		for (i = 0; i < kvasfreecnt; i++) {
208			for(off=0;off<kvaf[i].size;off+=NBPG) {
209				pmap_kremove( kvaf[i].addr + off);
210			}
211			kmem_free_wakeup(io_map, kvaf[i].addr,
212				kvaf[i].size);
213		}
214		kvasfreecnt = 0;
215		bmfreeing = 0;
216		if( bmwait) {
217			bmwait = 0;
218			wakeup( (caddr_t) io_map);
219		}
220	}
221
222	if( size == 0) {
223		splx(s);
224		return NULL;
225	}
226
227	if ((kva = kmem_alloc_pageable(io_map, size)) == 0) {
228		if( !waitok) {
229			splx(s);
230			return NULL;
231		}
232		bmwait = 1;
233		tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
234		goto more;
235	}
236	splx(s);
237	return kva;
238}
239
240/*
241 * same as vm_bounce_kva -- but really allocate (but takes pages as arg)
242 */
243vm_offset_t
244vm_bounce_kva_alloc(count)
245int count;
246{
247	int i;
248	vm_offset_t kva;
249	vm_offset_t pa;
250	if( bouncepages == 0) {
251		kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
252		return kva;
253	}
254	kva = vm_bounce_kva(count*NBPG, 1);
255	for(i=0;i<count;i++) {
256		pa = vm_bounce_page_find(1);
257		pmap_kenter(kva + i * NBPG, pa);
258	}
259	return kva;
260}
261
262/*
263 * same as vm_bounce_kva_free -- but really free
264 */
265void
266vm_bounce_kva_alloc_free(kva, count)
267	vm_offset_t kva;
268	int count;
269{
270	int i;
271	vm_offset_t pa;
272	if( bouncepages == 0) {
273		free((caddr_t) kva, M_TEMP);
274		return;
275	}
276	for(i = 0; i < count; i++) {
277		pa = pmap_kextract(kva + i * NBPG);
278		vm_bounce_page_free(pa, 1);
279	}
280	vm_bounce_kva_free(kva, count*NBPG, 0);
281}
282
283/*
284 * do the things necessary to the struct buf to implement
285 * bounce buffers...  inserted before the disk sort
286 */
287void
288vm_bounce_alloc(bp)
289	struct buf *bp;
290{
291	int countvmpg;
292	vm_offset_t vastart, vaend;
293	vm_offset_t vapstart, vapend;
294	vm_offset_t va, kva;
295	vm_offset_t pa;
296	int dobounceflag = 0;
297	int i;
298
299	if (bouncepages == 0)
300		return;
301
302	if (bp->b_flags & B_BOUNCE) {
303		printf("vm_bounce_alloc: called recursively???\n");
304		return;
305	}
306
307	if (bp->b_bufsize < bp->b_bcount) {
308		printf(
309		    "vm_bounce_alloc: b_bufsize(0x%lx) < b_bcount(0x%lx) !!\n",
310			bp->b_bufsize, bp->b_bcount);
311		panic("vm_bounce_alloc");
312	}
313
314/*
315 *  This is not really necessary
316 *	if( bp->b_bufsize != bp->b_bcount) {
317 *		printf("size: %d, count: %d\n", bp->b_bufsize, bp->b_bcount);
318 *	}
319 */
320
321
322	vastart = (vm_offset_t) bp->b_data;
323	vaend = (vm_offset_t) bp->b_data + bp->b_bufsize;
324
325	vapstart = i386_trunc_page(vastart);
326	vapend = i386_round_page(vaend);
327	countvmpg = (vapend - vapstart) / NBPG;
328
329/*
330 * if any page is above 16MB, then go into bounce-buffer mode
331 */
332	va = vapstart;
333	for (i = 0; i < countvmpg; i++) {
334		pa = pmap_kextract(va);
335		if (pa >= SIXTEENMEG)
336			++dobounceflag;
337		if( pa == 0)
338			panic("vm_bounce_alloc: Unmapped page");
339		va += NBPG;
340	}
341	if (dobounceflag == 0)
342		return;
343
344	if (bouncepages < dobounceflag)
345		panic("Not enough bounce buffers!!!");
346
347/*
348 * allocate a replacement kva for b_addr
349 */
350	kva = vm_bounce_kva(countvmpg*NBPG, 1);
351#if 0
352	printf("%s: vapstart: %x, vapend: %x, countvmpg: %d, kva: %x ",
353		(bp->b_flags & B_READ) ? "read":"write",
354			vapstart, vapend, countvmpg, kva);
355#endif
356	va = vapstart;
357	for (i = 0; i < countvmpg; i++) {
358		pa = pmap_kextract(va);
359		if (pa >= SIXTEENMEG) {
360			/*
361			 * allocate a replacement page
362			 */
363			vm_offset_t bpa = vm_bounce_page_find(1);
364			pmap_kenter(kva + (NBPG * i), bpa);
365#if 0
366			printf("r(%d): (%x,%x,%x) ", i, va, pa, bpa);
367#endif
368			/*
369			 * if we are writing, the copy the data into the page
370			 */
371			if ((bp->b_flags & B_READ) == 0) {
372				bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
373			}
374		} else {
375			/*
376			 * use original page
377			 */
378			pmap_kenter(kva + (NBPG * i), pa);
379		}
380		va += NBPG;
381	}
382
383/*
384 * flag the buffer as being bounced
385 */
386	bp->b_flags |= B_BOUNCE;
387/*
388 * save the original buffer kva
389 */
390	bp->b_savekva = bp->b_data;
391/*
392 * put our new kva into the buffer (offset by original offset)
393 */
394	bp->b_data = (caddr_t) (((vm_offset_t) kva) |
395				((vm_offset_t) bp->b_savekva & (NBPG - 1)));
396#if 0
397	printf("b_savekva: %x, newva: %x\n", bp->b_savekva, bp->b_data);
398#endif
399	return;
400}
401
402/*
403 * hook into biodone to free bounce buffer
404 */
405void
406vm_bounce_free(bp)
407	struct buf *bp;
408{
409	int i;
410	vm_offset_t origkva, bouncekva, bouncekvaend;
411
412/*
413 * if this isn't a bounced buffer, then just return
414 */
415	if ((bp->b_flags & B_BOUNCE) == 0)
416		return;
417
418/*
419 *  This check is not necessary
420 *	if (bp->b_bufsize != bp->b_bcount) {
421 *		printf("vm_bounce_free: b_bufsize=%d, b_bcount=%d\n",
422 *			bp->b_bufsize, bp->b_bcount);
423 *	}
424 */
425
426	origkva = (vm_offset_t) bp->b_savekva;
427	bouncekva = (vm_offset_t) bp->b_data;
428/*
429	printf("free: %d ", bp->b_bufsize);
430*/
431
432/*
433 * check every page in the kva space for b_addr
434 */
435	for (i = 0; i < bp->b_bufsize; ) {
436		vm_offset_t mybouncepa;
437		vm_offset_t copycount;
438
439		copycount = i386_round_page(bouncekva + 1) - bouncekva;
440		mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
441
442/*
443 * if this is a bounced pa, then process as one
444 */
445		if ( mybouncepa != pmap_kextract( i386_trunc_page( origkva))) {
446			vm_offset_t tocopy = copycount;
447			if (i + tocopy > bp->b_bufsize)
448				tocopy = bp->b_bufsize - i;
449/*
450 * if this is a read, then copy from bounce buffer into original buffer
451 */
452			if (bp->b_flags & B_READ)
453				bcopy((caddr_t) bouncekva, (caddr_t) origkva, tocopy);
454/*
455 * free the bounce allocation
456 */
457
458/*
459			printf("(kva: %x, pa: %x)", bouncekva, mybouncepa);
460*/
461			vm_bounce_page_free(mybouncepa, 1);
462		}
463
464		origkva += copycount;
465		bouncekva += copycount;
466		i += copycount;
467	}
468
469/*
470	printf("\n");
471*/
472/*
473 * add the old kva into the "to free" list
474 */
475
476	bouncekva= i386_trunc_page((vm_offset_t) bp->b_data);
477	bouncekvaend= i386_round_page((vm_offset_t)bp->b_data + bp->b_bufsize);
478
479/*
480	printf("freeva: %d\n", (bouncekvaend - bouncekva) / NBPG);
481*/
482	vm_bounce_kva_free( bouncekva, (bouncekvaend - bouncekva), 0);
483	bp->b_data = bp->b_savekva;
484	bp->b_savekva = 0;
485	bp->b_flags &= ~B_BOUNCE;
486
487	return;
488}
489
490
491/*
492 * init the bounce buffer system
493 */
494void
495vm_bounce_init()
496{
497	int i;
498
499	kvasfreecnt = 0;
500
501	if (bouncepages == 0)
502		return;
503
504	bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
505	bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
506
507	if (!bounceallocarray)
508		panic("Cannot allocate bounce resource array");
509
510	bouncepa = malloc(bouncepages * sizeof(vm_offset_t), M_TEMP, M_NOWAIT);
511	if (!bouncepa)
512		panic("Cannot allocate physical memory array");
513
514	for(i=0;i<bounceallocarraysize;i++) {
515		bounceallocarray[i] = 0xffffffff;
516	}
517
518	for(i=0;i<bouncepages;i++) {
519		vm_offset_t pa;
520		if( (pa = pmap_kextract((vm_offset_t) bouncememory + i * NBPG)) >= SIXTEENMEG)
521			panic("bounce memory out of range");
522		if( pa == 0)
523			panic("bounce memory not resident");
524		bouncepa[i] = pa;
525		bounceallocarray[i/(8*sizeof(int))] &= ~(1<<(i%(8*sizeof(int))));
526	}
527	bouncefree = bouncepages;
528
529}
530#endif /* BOUNCE_BUFFERS */
531
532/*
533 * quick version of vm_fault
534 */
535void
536vm_fault_quick(v, prot)
537	caddr_t v;
538	int prot;
539{
540	if (prot & VM_PROT_WRITE)
541		subyte(v, fubyte(v));
542	else
543		fubyte(v);
544}
545
546/*
547 * Finish a fork operation, with process p2 nearly set up.
548 * Copy and update the kernel stack and pcb, making the child
549 * ready to run, and marking it so that it can return differently
550 * than the parent.  Returns 1 in the child process, 0 in the parent.
551 * We currently double-map the user area so that the stack is at the same
552 * address in each process; in the future we will probably relocate
553 * the frame pointers on the stack after copying.
554 */
555int
556cpu_fork(p1, p2)
557	register struct proc *p1, *p2;
558{
559	register struct user *up = p2->p_addr;
560	int offset;
561
562	/*
563	 * Copy pcb and stack from proc p1 to p2.
564	 * We do this as cheaply as possible, copying only the active
565	 * part of the stack.  The stack and pcb need to agree;
566	 * this is tricky, as the final pcb is constructed by savectx,
567	 * but its frame isn't yet on the stack when the stack is copied.
568	 * swtch compensates for this when the child eventually runs.
569	 * This should be done differently, with a single call
570	 * that copies and updates the pcb+stack,
571	 * replacing the bcopy and savectx.
572	 */
573	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
574	offset = mvesp() - (int)kstack;
575	bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
576	    (unsigned) ctob(UPAGES) - offset);
577	p2->p_md.md_regs = p1->p_md.md_regs;
578
579	pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
580
581	/*
582	 *
583	 * Arrange for a non-local goto when the new process
584	 * is started, to resume here, returning nonzero from setjmp.
585	 */
586	if (savectx(&up->u_pcb, 1)) {
587		/*
588		 * Return 1 in child.
589		 */
590		return (1);
591	}
592	return (0);
593}
594
595void
596cpu_exit(p)
597	register struct proc *p;
598{
599
600#if NNPX > 0
601	npxexit(p);
602#endif	/* NNPX */
603	cnt.v_swtch++;
604	cpu_switch(p);
605	panic("cpu_exit");
606}
607
608void
609cpu_wait(p) struct proc *p; {
610/*	extern vm_map_t upages_map; */
611
612	/* drop per-process resources */
613 	pmap_remove(vm_map_pmap(u_map), (vm_offset_t) p->p_addr,
614		((vm_offset_t) p->p_addr) + ctob(UPAGES));
615	kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
616	vmspace_free(p->p_vmspace);
617}
618
619/*
620 * Dump the machine specific header information at the start of a core dump.
621 */
622int
623cpu_coredump(p, vp, cred)
624	struct proc *p;
625	struct vnode *vp;
626	struct ucred *cred;
627{
628
629	return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES),
630	    (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL,
631	    p));
632}
633
634/*
635 * Set a red zone in the kernel stack after the u. area.
636 */
637void
638setredzone(pte, vaddr)
639	u_short *pte;
640	caddr_t vaddr;
641{
642/* eventually do this by setting up an expand-down stack segment
643   for ss0: selector, allowing stack access down to top of u.
644   this means though that protection violations need to be handled
645   thru a double fault exception that must do an integral task
646   switch to a known good context, within which a dump can be
647   taken. a sensible scheme might be to save the initial context
648   used by sched (that has physical memory mapped 1:1 at bottom)
649   and take the dump while still in mapped mode */
650}
651
652/*
653 * Move pages from one kernel virtual address to another.
654 * Both addresses are assumed to reside in the Sysmap,
655 * and size must be a multiple of CLSIZE.
656 */
657
658void
659pagemove(from, to, size)
660	register caddr_t from, to;
661	int size;
662{
663	register vm_offset_t pa;
664
665	if (size & CLOFSET)
666		panic("pagemove");
667	while (size > 0) {
668		pa = pmap_kextract((vm_offset_t)from);
669		if (pa == 0)
670			panic("pagemove 2");
671		if (pmap_kextract((vm_offset_t)to) != 0)
672			panic("pagemove 3");
673		pmap_kremove((vm_offset_t)from);
674		pmap_kenter((vm_offset_t)to, pa);
675		from += PAGE_SIZE;
676		to += PAGE_SIZE;
677		size -= PAGE_SIZE;
678	}
679}
680
681/*
682 * Convert kernel VA to physical address
683 */
684u_long
685kvtop(void *addr)
686{
687	vm_offset_t va;
688
689	va = pmap_kextract((vm_offset_t)addr);
690	if (va == 0)
691		panic("kvtop: zero page frame");
692	return((int)va);
693}
694
695/*
696 * Map an IO request into kernel virtual address space.
697 *
698 * All requests are (re)mapped into kernel VA space.
699 * Notice that we use b_bufsize for the size of the buffer
700 * to be mapped.  b_bcount might be modified by the driver.
701 */
702void
703vmapbuf(bp)
704	register struct buf *bp;
705{
706	register int npf;
707	register caddr_t addr;
708	int off;
709	vm_offset_t kva;
710	vm_offset_t pa;
711
712	if ((bp->b_flags & B_PHYS) == 0)
713		panic("vmapbuf");
714
715	/*
716	 * this is the kva that is to be used for
717	 * the temporary kernel mapping
718	 */
719	kva = (vm_offset_t) bp->b_saveaddr;
720
721	for (addr = (caddr_t)trunc_page(bp->b_data);
722		addr < bp->b_data + bp->b_bufsize;
723		addr += PAGE_SIZE) {
724
725/*
726 * do the vm_fault if needed, do the copy-on-write thing when
727 * reading stuff off device into memory.
728 */
729		vm_fault_quick(addr,
730			(bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ);
731		pa = pmap_kextract((vm_offset_t) addr);
732		if (pa == 0)
733			panic("vmapbuf: page not present");
734/*
735 * hold the data page
736 */
737#ifdef DIAGNOSTIC
738		if( VM_PAGE_TO_PHYS(PHYS_TO_VM_PAGE(pa)) != pa)
739			panic("vmapbuf: confused PHYS_TO_VM_PAGE mapping");
740#endif
741		vm_page_hold(PHYS_TO_VM_PAGE(pa));
742	}
743
744	addr = bp->b_saveaddr = bp->b_data;
745	off = (int)addr & PGOFSET;
746	npf = btoc(round_page(bp->b_bufsize + off));
747	bp->b_data = (caddr_t) (kva + off);
748	while (npf--) {
749		pa = pmap_kextract((vm_offset_t)addr);
750		if (pa == 0)
751			panic("vmapbuf: null page frame");
752		pmap_kenter(kva, trunc_page(pa));
753		addr += PAGE_SIZE;
754		kva += PAGE_SIZE;
755	}
756}
757
758/*
759 * Free the io map PTEs associated with this IO operation.
760 * We also invalidate the TLB entries and restore the original b_addr.
761 */
762void
763vunmapbuf(bp)
764	register struct buf *bp;
765{
766	register caddr_t addr;
767	vm_offset_t pa;
768
769	if ((bp->b_flags & B_PHYS) == 0)
770		panic("vunmapbuf");
771
772	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
773		addr < bp->b_data + bp->b_bufsize;
774		addr += NBPG)
775		pmap_kremove((vm_offset_t) addr);
776
777	bp->b_data = bp->b_saveaddr;
778	bp->b_saveaddr = NULL;
779
780/*
781 * unhold the pde, and data pages
782 */
783	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
784		addr < bp->b_data + bp->b_bufsize;
785		addr += NBPG) {
786	/*
787	 * release the data page
788	 */
789		pa = pmap_kextract((vm_offset_t) addr);
790		vm_page_unhold(PHYS_TO_VM_PAGE(pa));
791	}
792}
793
794/*
795 * Force reset the processor by invalidating the entire address space!
796 */
797void
798cpu_reset() {
799
800	/*
801	 * Attempt to do a CPU reset via the keyboard controller,
802	 * do not turn of the GateA20, as any machine that fails
803	 * to do the reset here would then end up in no man's land.
804	 */
805
806#ifndef BROKEN_KEYBOARD_RESET
807	outb(IO_KBD + 4, 0xFE);
808	DELAY(500000);	/* wait 0.5 sec to see if that did it */
809	printf("Keyboard reset did not work, attempting CPU shutdown\n");
810	DELAY(1000000);	/* wait 1 sec for printf to complete */
811#endif
812
813	/* force a shutdown by unmapping entire address space ! */
814	bzero((caddr_t) PTD, NBPG);
815
816	/* "good night, sweet prince .... <THUNK!>" */
817	pmap_update();
818	/* NOTREACHED */
819	while(1);
820}
821
822/*
823 * Grow the user stack to allow for 'sp'. This version grows the stack in
824 *	chunks of SGROWSIZ.
825 */
826int
827grow(p, sp)
828	struct proc *p;
829	u_int sp;
830{
831	unsigned int nss;
832	caddr_t v;
833	struct vmspace *vm = p->p_vmspace;
834
835	if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
836	    return (1);
837
838	nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
839
840	if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
841		return (0);
842
843	if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
844	    SGROWSIZ) < nss) {
845		int grow_amount;
846		/*
847		 * If necessary, grow the VM that the stack occupies
848		 * to allow for the rlimit. This allows us to not have
849		 * to allocate all of the VM up-front in execve (which
850		 * is expensive).
851		 * Grow the VM by the amount requested rounded up to
852		 * the nearest SGROWSIZ to provide for some hysteresis.
853		 */
854		grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
855		v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
856		    SGROWSIZ) - grow_amount;
857		/*
858		 * If there isn't enough room to extend by SGROWSIZ, then
859		 * just extend to the maximum size
860		 */
861		if (v < vm->vm_maxsaddr) {
862			v = vm->vm_maxsaddr;
863			grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
864		}
865		if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v,
866		    grow_amount, FALSE) != KERN_SUCCESS)) {
867			return (0);
868		}
869		vm->vm_ssize += grow_amount >> PAGE_SHIFT;
870	}
871
872	return (1);
873}
874
875/*
876 * prototype routine to implement the pre-zeroed page mechanism
877 * this routine is called from the idle loop.
878 */
879int
880vm_page_zero_idle() {
881	vm_page_t m;
882	if ((cnt.v_free_count > cnt.v_interrupt_free_min) &&
883		(m = vm_page_queue_free.tqh_first)) {
884		TAILQ_REMOVE(&vm_page_queue_free, m, pageq);
885		enable_intr();
886		pmap_zero_page(VM_PAGE_TO_PHYS(m));
887		disable_intr();
888		TAILQ_INSERT_HEAD(&vm_page_queue_zero, m, pageq);
889		return 1;
890	}
891	return 0;
892}
893