vm_machdep.c revision 8074
137535Sdes/*-
263012Sdes * Copyright (c) 1982, 1986 The Regents of the University of California.
337535Sdes * Copyright (c) 1989, 1990 William Jolitz
437535Sdes * Copyright (c) 1994 John Dyson
537535Sdes * All rights reserved.
637535Sdes *
737535Sdes * This code is derived from software contributed to Berkeley by
837535Sdes * the Systems Programming Group of the University of Utah Computer
937535Sdes * Science Department, and William Jolitz.
1037535Sdes *
1137535Sdes * Redistribution and use in source and binary forms, with or without
1237535Sdes * modification, are permitted provided that the following conditions
1337535Sdes * are met:
1437535Sdes * 1. Redistributions of source code must retain the above copyright
1563012Sdes *    notice, this list of conditions and the following disclaimer.
1637535Sdes * 2. Redistributions in binary form must reproduce the above copyright
1737535Sdes *    notice, this list of conditions and the following disclaimer in the
1837535Sdes *    documentation and/or other materials provided with the distribution.
1937535Sdes * 3. All advertising materials mentioning features or use of this software
2037535Sdes *    must display the following acknowledgement:
2137535Sdes *	This product includes software developed by the University of
2237535Sdes *	California, Berkeley and its contributors.
2337535Sdes * 4. Neither the name of the University nor the names of its contributors
2437535Sdes *    may be used to endorse or promote products derived from this software
2537535Sdes *    without specific prior written permission.
2637535Sdes *
2737535Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2863012Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2937535Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3037535Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3137535Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3260737Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3337535Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3463012Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3537535Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3663012Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3760376Sdes * SUCH DAMAGE.
3860189Sdes *
3937608Sdes *	from: @(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
4037535Sdes *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
4137535Sdes *	$Id: vm_machdep.c,v 1.35 1995/03/19 14:28:41 davidg Exp $
4237535Sdes */
4360376Sdes
4437535Sdes#include "npx.h"
4537535Sdes#include <sys/param.h>
4637535Sdes#include <sys/systm.h>
4740939Sdes#include <sys/proc.h>
4841862Sdes#include <sys/malloc.h>
4937535Sdes#include <sys/buf.h>
5063012Sdes#include <sys/vnode.h>
5137535Sdes#include <sys/user.h>
5263012Sdes
5363012Sdes#include <machine/clock.h>
5437535Sdes#include <machine/cpu.h>
5563012Sdes#include <machine/md_var.h>
5663012Sdes
5763012Sdes#include <vm/vm.h>
5863012Sdes#include <vm/vm_kern.h>
5963012Sdes
6063012Sdes#include <i386/isa/isa.h>
6163012Sdes
6263012Sdes#ifdef BOUNCE_BUFFERS
6363012Sdesvm_map_t	io_map;
6460196Sdesvolatile int	kvasfreecnt;
6563012Sdes
6663012Sdes
6763012Sdescaddr_t		bouncememory;
6863012Sdesint		bouncepages, bpwait;
6963012Sdesvm_offset_t	*bouncepa;
7063012Sdesint		bmwait, bmfreeing;
7163012Sdes
7263012Sdes#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
7363012Sdesint		bounceallocarraysize;
7463012Sdesunsigned	*bounceallocarray;
7537535Sdesint		bouncefree;
7637535Sdes
7763012Sdes#define SIXTEENMEG (4096*4096)
7863012Sdes#define MAXBKVA 1024
7963012Sdesint		maxbkva = MAXBKVA*NBPG;
8063012Sdes
8163012Sdes/* special list that can be used at interrupt time for eventual kva free */
8263012Sdesstruct kvasfree {
8363012Sdes	vm_offset_t addr;
8463012Sdes	vm_offset_t size;
8563012Sdes} kvaf[MAXBKVA];
8663012Sdes
8763012Sdes
8837535Sdesvm_offset_t vm_bounce_kva();
8937535Sdes/*
9037608Sdes * get bounce buffer pages (count physically contiguous)
9163012Sdes * (only 1 inplemented now)
9237608Sdes */
9337608Sdesvm_offset_t
9463012Sdesvm_bounce_page_find(count)
9537608Sdes	int count;
9663012Sdes{
9737608Sdes	int bit;
9863012Sdes	int s,i;
9963012Sdes
10063012Sdes	if (count != 1)
10163012Sdes		panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
10263012Sdes
10363012Sdes	s = splbio();
10463012Sdesretry:
10563012Sdes	for (i = 0; i < bounceallocarraysize; i++) {
10663012Sdes		if (bounceallocarray[i] != 0xffffffff) {
10763012Sdes			bit = ffs(~bounceallocarray[i]);
10863012Sdes			if (bit) {
10963012Sdes				bounceallocarray[i] |= 1 << (bit - 1) ;
11063012Sdes				bouncefree -= count;
11163012Sdes				splx(s);
11263012Sdes				return bouncepa[(i * BITS_IN_UNSIGNED + (bit - 1))];
11363012Sdes			}
11463012Sdes		}
11563012Sdes	}
11663012Sdes	bpwait = 1;
11763012Sdes	tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
11863012Sdes	goto retry;
11963012Sdes}
12063012Sdes
12163012Sdesvoid
12263012Sdesvm_bounce_kva_free(addr, size, now)
12337608Sdes	vm_offset_t addr;
12437608Sdes	vm_offset_t size;
12537608Sdes	int now;
12637608Sdes{
12737608Sdes	int s = splbio();
12863012Sdes	kvaf[kvasfreecnt].addr = addr;
12937535Sdes	kvaf[kvasfreecnt].size = size;
13037535Sdes	++kvasfreecnt;
13163012Sdes	if( now) {
13263012Sdes		/*
13337535Sdes		 * this will do wakeups
13463012Sdes		 */
13563012Sdes		vm_bounce_kva(0,0);
13663012Sdes	} else {
13763012Sdes		if (bmwait) {
13863012Sdes		/*
13963012Sdes		 * if anyone is waiting on the bounce-map, then wakeup
14063012Sdes		 */
14163012Sdes			wakeup((caddr_t) io_map);
14263012Sdes			bmwait = 0;
14363012Sdes		}
14437535Sdes	}
14537535Sdes	splx(s);
14663012Sdes}
14763012Sdes
14863012Sdes/*
14963012Sdes * free count bounce buffer pages
15063012Sdes */
15163012Sdesvoid
15263012Sdesvm_bounce_page_free(pa, count)
15363012Sdes	vm_offset_t pa;
15463012Sdes	int count;
15563012Sdes{
15663012Sdes	int allocindex;
15763012Sdes	int index;
15863012Sdes	int bit;
15963012Sdes
16063012Sdes	if (count != 1)
16163012Sdes		panic("vm_bounce_page_free -- no support for > 1 page yet!!!");
16263012Sdes
16363012Sdes	for(index=0;index<bouncepages;index++) {
16463012Sdes		if( pa == bouncepa[index])
16563012Sdes			break;
16663012Sdes	}
16763012Sdes
16837535Sdes	if( index == bouncepages)
16937535Sdes		panic("vm_bounce_page_free: invalid bounce buffer");
17037608Sdes
17137608Sdes	allocindex = index / BITS_IN_UNSIGNED;
17237608Sdes	bit = index % BITS_IN_UNSIGNED;
17337535Sdes
17463012Sdes	bounceallocarray[allocindex] &= ~(1 << bit);
17537535Sdes
17663012Sdes	bouncefree += count;
17763012Sdes	if (bpwait) {
17863012Sdes		bpwait = 0;
17963012Sdes		wakeup((caddr_t) &bounceallocarray);
18063012Sdes	}
18163012Sdes}
18263012Sdes
18363012Sdes/*
18463012Sdes * allocate count bounce buffer kva pages
18537535Sdes */
18663012Sdesvm_offset_t
18763012Sdesvm_bounce_kva(size, waitok)
18837535Sdes	int size;
18963012Sdes	int waitok;
19063012Sdes{
19163012Sdes	int i;
19263012Sdes	vm_offset_t kva = 0;
19363012Sdes	vm_offset_t off;
19463012Sdes	int s = splbio();
19537535Sdesmore:
19663012Sdes	if (!bmfreeing && kvasfreecnt) {
19737535Sdes		bmfreeing = 1;
19863012Sdes		for (i = 0; i < kvasfreecnt; i++) {
19937535Sdes			for(off=0;off<kvaf[i].size;off+=NBPG) {
20037535Sdes				pmap_kremove( kvaf[i].addr + off);
20137608Sdes			}
20237608Sdes			kmem_free_wakeup(io_map, kvaf[i].addr,
20337608Sdes				kvaf[i].size);
20437535Sdes		}
20563012Sdes		kvasfreecnt = 0;
20637535Sdes		bmfreeing = 0;
20763012Sdes		if( bmwait) {
20863012Sdes			bmwait = 0;
20963012Sdes			wakeup( (caddr_t) io_map);
21037535Sdes		}
21137535Sdes	}
21237608Sdes
21337608Sdes	if( size == 0) {
21437608Sdes		splx(s);
21537535Sdes		return NULL;
21663012Sdes	}
21737535Sdes
21863012Sdes	if ((kva = kmem_alloc_pageable(io_map, size)) == 0) {
21963012Sdes		if( !waitok) {
22063012Sdes			splx(s);
22163012Sdes			return NULL;
22263012Sdes		}
22363012Sdes		bmwait = 1;
22437535Sdes		tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
22563012Sdes		goto more;
22637535Sdes	}
22737535Sdes	splx(s);
22837608Sdes	return kva;
22963012Sdes}
23037608Sdes
23163012Sdes/*
23263012Sdes * same as vm_bounce_kva -- but really allocate (but takes pages as arg)
23337535Sdes */
23463012Sdesvm_offset_t
23563012Sdesvm_bounce_kva_alloc(count)
23663012Sdesint count;
23763012Sdes{
23863012Sdes	int i;
23963012Sdes	vm_offset_t kva;
24063012Sdes	vm_offset_t pa;
24163012Sdes	if( bouncepages == 0) {
24263012Sdes		kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
24363012Sdes		return kva;
24463012Sdes	}
24563012Sdes	kva = vm_bounce_kva(count*NBPG, 1);
24663012Sdes	for(i=0;i<count;i++) {
24763012Sdes		pa = vm_bounce_page_find(1);
24863012Sdes		pmap_kenter(kva + i * NBPG, pa);
24963012Sdes	}
25063012Sdes	return kva;
25163012Sdes}
25263012Sdes
25363012Sdes/*
25463012Sdes * same as vm_bounce_kva_free -- but really free
25563012Sdes */
25663012Sdesvoid
25763012Sdesvm_bounce_kva_alloc_free(kva, count)
25863012Sdes	vm_offset_t kva;
25963012Sdes	int count;
26063012Sdes{
26163012Sdes	int i;
26263012Sdes	vm_offset_t pa;
26363012Sdes	if( bouncepages == 0) {
26463012Sdes		free((caddr_t) kva, M_TEMP);
26563012Sdes		return;
26663012Sdes	}
26763012Sdes	for(i = 0; i < count; i++) {
26863012Sdes		pa = pmap_kextract(kva + i * NBPG);
26963012Sdes		vm_bounce_page_free(pa, 1);
27063012Sdes	}
27163012Sdes	vm_bounce_kva_free(kva, count*NBPG, 0);
27263012Sdes}
27363012Sdes
27463012Sdes/*
27563012Sdes * do the things necessary to the struct buf to implement
27663012Sdes * bounce buffers...  inserted before the disk sort
27763012Sdes */
27863012Sdesvoid
27963012Sdesvm_bounce_alloc(bp)
28063012Sdes	struct buf *bp;
28163012Sdes{
28263012Sdes	int countvmpg;
28363012Sdes	vm_offset_t vastart, vaend;
28463012Sdes	vm_offset_t vapstart, vapend;
28563012Sdes	vm_offset_t va, kva;
28663012Sdes	vm_offset_t pa;
28763012Sdes	int dobounceflag = 0;
28863012Sdes	int i;
28963012Sdes
29063012Sdes	if (bouncepages == 0)
29163012Sdes		return;
29263012Sdes
29363012Sdes	if (bp->b_flags & B_BOUNCE) {
29463012Sdes		printf("vm_bounce_alloc: called recursively???\n");
29563012Sdes		return;
29663012Sdes	}
29763012Sdes
29863012Sdes	if (bp->b_bufsize < bp->b_bcount) {
29963012Sdes		printf(
30063012Sdes		    "vm_bounce_alloc: b_bufsize(0x%lx) < b_bcount(0x%lx) !!\n",
30163012Sdes			bp->b_bufsize, bp->b_bcount);
30263012Sdes		panic("vm_bounce_alloc");
30363012Sdes	}
30463012Sdes
30563012Sdes/*
30663012Sdes *  This is not really necessary
30763012Sdes *	if( bp->b_bufsize != bp->b_bcount) {
30863012Sdes *		printf("size: %d, count: %d\n", bp->b_bufsize, bp->b_bcount);
30963012Sdes *	}
31063012Sdes */
31163012Sdes
31263012Sdes
31363012Sdes	vastart = (vm_offset_t) bp->b_data;
31463012Sdes	vaend = (vm_offset_t) bp->b_data + bp->b_bufsize;
31563012Sdes
31663012Sdes	vapstart = i386_trunc_page(vastart);
31763012Sdes	vapend = i386_round_page(vaend);
31863012Sdes	countvmpg = (vapend - vapstart) / NBPG;
31963012Sdes
32063012Sdes/*
32163012Sdes * if any page is above 16MB, then go into bounce-buffer mode
32263012Sdes */
32363012Sdes	va = vapstart;
32463012Sdes	for (i = 0; i < countvmpg; i++) {
32537535Sdes		pa = pmap_kextract(va);
32663012Sdes		if (pa >= SIXTEENMEG)
32763012Sdes			++dobounceflag;
32863012Sdes		if( pa == 0)
32963012Sdes			panic("vm_bounce_alloc: Unmapped page");
33063012Sdes		va += NBPG;
33137535Sdes	}
33263012Sdes	if (dobounceflag == 0)
33363012Sdes		return;
33463012Sdes
33563012Sdes	if (bouncepages < dobounceflag)
33663012Sdes		panic("Not enough bounce buffers!!!");
33763012Sdes
33863012Sdes/*
33963012Sdes * allocate a replacement kva for b_addr
34063012Sdes */
34163012Sdes	kva = vm_bounce_kva(countvmpg*NBPG, 1);
34237535Sdes#if 0
34337535Sdes	printf("%s: vapstart: %x, vapend: %x, countvmpg: %d, kva: %x ",
34437608Sdes		(bp->b_flags & B_READ) ? "read":"write",
34563012Sdes			vapstart, vapend, countvmpg, kva);
34663012Sdes#endif
34763012Sdes	va = vapstart;
34863012Sdes	for (i = 0; i < countvmpg; i++) {
34963012Sdes		pa = pmap_kextract(va);
35063012Sdes		if (pa >= SIXTEENMEG) {
35163012Sdes			/*
35263012Sdes			 * allocate a replacement page
35363012Sdes			 */
35463012Sdes			vm_offset_t bpa = vm_bounce_page_find(1);
35563012Sdes			pmap_kenter(kva + (NBPG * i), bpa);
35663012Sdes#if 0
35763012Sdes			printf("r(%d): (%x,%x,%x) ", i, va, pa, bpa);
35863012Sdes#endif
35963012Sdes			/*
36063012Sdes			 * if we are writing, the copy the data into the page
36163012Sdes			 */
36263012Sdes			if ((bp->b_flags & B_READ) == 0) {
36363012Sdes				bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
36463012Sdes			}
36563012Sdes		} else {
36663012Sdes			/*
36763012Sdes			 * use original page
36863012Sdes			 */
36963012Sdes			pmap_kenter(kva + (NBPG * i), pa);
37063012Sdes		}
37163012Sdes		va += NBPG;
37263012Sdes	}
37363012Sdes
37463012Sdes/*
37563012Sdes * flag the buffer as being bounced
37663012Sdes */
37763012Sdes	bp->b_flags |= B_BOUNCE;
37863012Sdes/*
37963012Sdes * save the original buffer kva
38063012Sdes */
38163012Sdes	bp->b_savekva = bp->b_data;
38263012Sdes/*
38363012Sdes * put our new kva into the buffer (offset by original offset)
38463012Sdes */
38563012Sdes	bp->b_data = (caddr_t) (((vm_offset_t) kva) |
38663012Sdes				((vm_offset_t) bp->b_savekva & (NBPG - 1)));
38763012Sdes#if 0
38863012Sdes	printf("b_savekva: %x, newva: %x\n", bp->b_savekva, bp->b_data);
38963012Sdes#endif
39063012Sdes	return;
39163012Sdes}
39263012Sdes
39363012Sdes/*
39463012Sdes * hook into biodone to free bounce buffer
39563012Sdes */
39663012Sdesvoid
39763012Sdesvm_bounce_free(bp)
39863012Sdes	struct buf *bp;
39963012Sdes{
40063012Sdes	int i;
40163012Sdes	vm_offset_t origkva, bouncekva, bouncekvaend;
40263012Sdes
40363012Sdes/*
40463012Sdes * if this isn't a bounced buffer, then just return
40563012Sdes */
40663012Sdes	if ((bp->b_flags & B_BOUNCE) == 0)
40763012Sdes		return;
40863012Sdes
40963012Sdes/*
41063012Sdes *  This check is not necessary
41163012Sdes *	if (bp->b_bufsize != bp->b_bcount) {
41263012Sdes *		printf("vm_bounce_free: b_bufsize=%d, b_bcount=%d\n",
41363012Sdes *			bp->b_bufsize, bp->b_bcount);
41463012Sdes *	}
41563012Sdes */
41663012Sdes
41763012Sdes	origkva = (vm_offset_t) bp->b_savekva;
41863012Sdes	bouncekva = (vm_offset_t) bp->b_data;
41963012Sdes/*
42063012Sdes	printf("free: %d ", bp->b_bufsize);
42163012Sdes*/
42263012Sdes
42363012Sdes/*
42463012Sdes * check every page in the kva space for b_addr
42563012Sdes */
42663012Sdes	for (i = 0; i < bp->b_bufsize; ) {
42763012Sdes		vm_offset_t mybouncepa;
42863012Sdes		vm_offset_t copycount;
42963012Sdes
43063012Sdes		copycount = i386_round_page(bouncekva + 1) - bouncekva;
43163012Sdes		mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
43263012Sdes
43363012Sdes/*
43463012Sdes * if this is a bounced pa, then process as one
43563012Sdes */
43663012Sdes		if ( mybouncepa != pmap_kextract( i386_trunc_page( origkva))) {
43763012Sdes			vm_offset_t tocopy = copycount;
43863012Sdes			if (i + tocopy > bp->b_bufsize)
43963012Sdes				tocopy = bp->b_bufsize - i;
44063012Sdes/*
44163012Sdes * if this is a read, then copy from bounce buffer into original buffer
44263012Sdes */
44363012Sdes			if (bp->b_flags & B_READ)
44463012Sdes				bcopy((caddr_t) bouncekva, (caddr_t) origkva, tocopy);
44563012Sdes/*
44637608Sdes * free the bounce allocation
44737608Sdes */
44862965Sdes
44962965Sdes/*
45037608Sdes			printf("(kva: %x, pa: %x)", bouncekva, mybouncepa);
45137608Sdes*/
45237608Sdes			vm_bounce_page_free(mybouncepa, 1);
45337608Sdes		}
45437608Sdes
45562965Sdes		origkva += copycount;
45662965Sdes		bouncekva += copycount;
45762965Sdes		i += copycount;
45862965Sdes	}
45962965Sdes
46062965Sdes/*
46162965Sdes	printf("\n");
46262965Sdes*/
46362965Sdes/*
46437608Sdes * add the old kva into the "to free" list
46537608Sdes */
46637608Sdes
46737608Sdes	bouncekva= i386_trunc_page((vm_offset_t) bp->b_data);
46837608Sdes	bouncekvaend= i386_round_page((vm_offset_t)bp->b_data + bp->b_bufsize);
46937608Sdes
47037608Sdes/*
47137608Sdes	printf("freeva: %d\n", (bouncekvaend - bouncekva) / NBPG);
47237608Sdes*/
47337608Sdes	vm_bounce_kva_free( bouncekva, (bouncekvaend - bouncekva), 0);
47437608Sdes	bp->b_data = bp->b_savekva;
47537608Sdes	bp->b_savekva = 0;
47637608Sdes	bp->b_flags &= ~B_BOUNCE;
47737608Sdes
47837608Sdes	return;
47937608Sdes}
48037608Sdes
48137608Sdes
48237608Sdes/*
48337608Sdes * init the bounce buffer system
48437608Sdes */
48537608Sdesvoid
48637608Sdesvm_bounce_init()
48737608Sdes{
48837608Sdes	int i;
48937608Sdes
49037608Sdes	kvasfreecnt = 0;
49137608Sdes
49237608Sdes	if (bouncepages == 0)
49337608Sdes		return;
49437608Sdes
49537608Sdes	bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
49637608Sdes	bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
49737608Sdes
49862965Sdes	if (!bounceallocarray)
49937608Sdes		panic("Cannot allocate bounce resource array");
50037608Sdes
50137608Sdes	bouncepa = malloc(bouncepages * sizeof(vm_offset_t), M_TEMP, M_NOWAIT);
50237608Sdes	if (!bouncepa)
50337608Sdes		panic("Cannot allocate physical memory array");
50462965Sdes
50563012Sdes	for(i=0;i<bounceallocarraysize;i++) {
50637608Sdes		bounceallocarray[i] = 0xffffffff;
50762965Sdes	}
50862965Sdes
50937608Sdes	for(i=0;i<bouncepages;i++) {
51062965Sdes		vm_offset_t pa;
51162965Sdes		if( (pa = pmap_kextract((vm_offset_t) bouncememory + i * NBPG)) >= SIXTEENMEG)
51262965Sdes			panic("bounce memory out of range");
51362965Sdes		if( pa == 0)
51462965Sdes			panic("bounce memory not resident");
51562965Sdes		bouncepa[i] = pa;
51663012Sdes		bounceallocarray[i/(8*sizeof(int))] &= ~(1<<(i%(8*sizeof(int))));
51762965Sdes	}
51862965Sdes	bouncefree = bouncepages;
51962965Sdes
52062965Sdes}
52162965Sdes#endif /* BOUNCE_BUFFERS */
52262965Sdes/*
52362965Sdes * quick version of vm_fault
52462965Sdes */
52563012Sdes
52662965Sdesvoid
52762965Sdesvm_fault_quick( v, prot)
52862965Sdes	vm_offset_t v;
52962965Sdes	int prot;
53062965Sdes{
53162965Sdes	if (prot & VM_PROT_WRITE)
53262965Sdes		subyte((char *)v, fubyte((char *)v));
53362965Sdes	else
53462965Sdes		(void) fubyte((char *)v);
53562965Sdes}
53662965Sdes
53762965Sdes
53862965Sdes/*
53962965Sdes * Finish a fork operation, with process p2 nearly set up.
54062965Sdes * Copy and update the kernel stack and pcb, making the child
54162965Sdes * ready to run, and marking it so that it can return differently
54263012Sdes * than the parent.  Returns 1 in the child process, 0 in the parent.
54362965Sdes * We currently double-map the user area so that the stack is at the same
54462965Sdes * address in each process; in the future we will probably relocate
54562811Sdes * the frame pointers on the stack after copying.
54662965Sdes */
54737608Sdesint
54837608Sdescpu_fork(p1, p2)
54963012Sdes	register struct proc *p1, *p2;
55063012Sdes{
55163012Sdes	register struct user *up = p2->p_addr;
55263012Sdes	int offset;
55363012Sdes
55437608Sdes	/*
55563012Sdes	 * Copy pcb and stack from proc p1 to p2.
55637608Sdes	 * We do this as cheaply as possible, copying only the active
55763012Sdes	 * part of the stack.  The stack and pcb need to agree;
55863012Sdes	 * this is tricky, as the final pcb is constructed by savectx,
55937535Sdes	 * but its frame isn't yet on the stack when the stack is copied.
56063012Sdes	 * swtch compensates for this when the child eventually runs.
56163012Sdes	 * This should be done differently, with a single call
56263012Sdes	 * that copies and updates the pcb+stack,
56363012Sdes	 * replacing the bcopy and savectx.
56463012Sdes	 */
56560737Sume	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
56663012Sdes	offset = mvesp() - (int)kstack;
56763012Sdes	bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
56863012Sdes	    (unsigned) ctob(UPAGES) - offset);
56963012Sdes	p2->p_md.md_regs = p1->p_md.md_regs;
57063012Sdes
57163012Sdes	pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
57263012Sdes
57363012Sdes	/*
57463012Sdes	 *
57563012Sdes	 * Arrange for a non-local goto when the new process
57663012Sdes	 * is started, to resume here, returning nonzero from setjmp.
57763012Sdes	 */
57863012Sdes	if (savectx(&up->u_pcb, 1)) {
57963012Sdes		/*
58063012Sdes		 * Return 1 in child.
58163012Sdes		 */
58263012Sdes		return (1);
58363012Sdes	}
58463012Sdes	return (0);
58563012Sdes}
58663012Sdes
58763012Sdesvoid
58863012Sdescpu_exit(p)
58963012Sdes	register struct proc *p;
59063012Sdes{
59163012Sdes
59263012Sdes#if NNPX > 0
59363012Sdes	npxexit(p);
59463012Sdes#endif	/* NNPX */
59563012Sdes	cnt.v_swtch++;
59663012Sdes	cpu_switch(p);
59763012Sdes	panic("cpu_exit");
59863012Sdes}
59963012Sdes
60063012Sdesvoid
60163012Sdescpu_wait(p) struct proc *p; {
60263012Sdes/*	extern vm_map_t upages_map; */
60363012Sdes
60463012Sdes	/* drop per-process resources */
60563012Sdes 	pmap_remove(vm_map_pmap(u_map), (vm_offset_t) p->p_addr,
60663012Sdes		((vm_offset_t) p->p_addr) + ctob(UPAGES));
60763012Sdes	kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
60863012Sdes	vmspace_free(p->p_vmspace);
60963012Sdes}
61063012Sdes
61163012Sdes/*
61263012Sdes * Dump the machine specific header information at the start of a core dump.
61363012Sdes */
61463012Sdesint
61563012Sdescpu_coredump(p, vp, cred)
61663012Sdes	struct proc *p;
61763012Sdes	struct vnode *vp;
61863012Sdes	struct ucred *cred;
61963012Sdes{
62063012Sdes
62163012Sdes	return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES),
62263012Sdes	    (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL,
62363012Sdes	    p));
62463012Sdes}
62563012Sdes
62663012Sdes/*
62763012Sdes * Set a red zone in the kernel stack after the u. area.
62863012Sdes */
62963012Sdesvoid
63063012Sdessetredzone(pte, vaddr)
63163012Sdes	u_short *pte;
63263012Sdes	caddr_t vaddr;
63363012Sdes{
63463012Sdes/* eventually do this by setting up an expand-down stack segment
63563012Sdes   for ss0: selector, allowing stack access down to top of u.
63663012Sdes   this means though that protection violations need to be handled
63763012Sdes   thru a double fault exception that must do an integral task
63863012Sdes   switch to a known good context, within which a dump can be
63963012Sdes   taken. a sensible scheme might be to save the initial context
64063012Sdes   used by sched (that has physical memory mapped 1:1 at bottom)
64163012Sdes   and take the dump while still in mapped mode */
64263012Sdes}
64363012Sdes
64463012Sdes/*
64563012Sdes * Move pages from one kernel virtual address to another.
64663012Sdes * Both addresses are assumed to reside in the Sysmap,
64763012Sdes * and size must be a multiple of CLSIZE.
64863012Sdes */
64963012Sdes
65063012Sdesvoid
65163012Sdespagemove(from, to, size)
65263012Sdes	register caddr_t from, to;
65363012Sdes	int size;
65463012Sdes{
65563012Sdes	register vm_offset_t pa;
65663012Sdes
65763012Sdes	if (size & CLOFSET)
65860737Sume		panic("pagemove");
65963012Sdes	while (size > 0) {
66060737Sume		pa = pmap_kextract((vm_offset_t)from);
66163012Sdes		if (pa == 0)
66255544Sdes			panic("pagemove 2");
66355544Sdes		if (pmap_kextract((vm_offset_t)to) != 0)
66463012Sdes			panic("pagemove 3");
66560737Sume		pmap_kremove((vm_offset_t)from);
66663012Sdes		pmap_kenter((vm_offset_t)to, pa);
66760737Sume		from += PAGE_SIZE;
66841862Sdes		to += PAGE_SIZE;
66937535Sdes		size -= PAGE_SIZE;
67060189Sdes	}
67160189Sdes}
67260189Sdes
67363012Sdes/*
67460587Sume * Convert kernel VA to physical address
67560587Sume */
67660587Sumeu_long
67760587Sumekvtop(void *addr)
67860587Sume{
67960189Sdes	vm_offset_t va;
68060587Sume
68160587Sume	va = pmap_kextract((vm_offset_t)addr);
68260587Sume	if (va == 0)
68360587Sume		panic("kvtop: zero page frame");
68460189Sdes	return((int)va);
68537535Sdes}
68663012Sdes
68763012Sdes/*
68863012Sdes * Map an IO request into kernel virtual address space.
68963012Sdes *
69063012Sdes * All requests are (re)mapped into kernel VA space.
69163012Sdes * Notice that we use b_bufsize for the size of the buffer
69263012Sdes * to be mapped.  b_bcount might be modified by the driver.
69363012Sdes */
69463012Sdesvoid
69563012Sdesvmapbuf(bp)
69663012Sdes	register struct buf *bp;
69760189Sdes{
69863012Sdes	register int npf;
69963012Sdes	register caddr_t addr;
70063012Sdes	int off;
70163012Sdes	vm_offset_t kva;
70237535Sdes	vm_offset_t pa, lastv, v;
70337535Sdes
70463012Sdes	if ((bp->b_flags & B_PHYS) == 0)
70560376Sdes		panic("vmapbuf");
70660376Sdes
70763012Sdes	/*
70863012Sdes	 * this is the kva that is to be used for
70963012Sdes	 * the temporary kernel mapping
71060954Sdes	 */
71160954Sdes	kva = (vm_offset_t) bp->b_saveaddr;
71260954Sdes
71363012Sdes	lastv = 0;
71460376Sdes	for (addr = (caddr_t)trunc_page(bp->b_data);
71563012Sdes		addr < bp->b_data + bp->b_bufsize;
71663012Sdes		addr += PAGE_SIZE) {
71760376Sdes
71863012Sdes/*
71963012Sdes * make sure that the pde is valid and held
72063012Sdes */
72163012Sdes		v = trunc_page(((vm_offset_t)vtopte(addr)));
72263012Sdes		if (v != lastv) {
72363012Sdes			vm_fault_quick(v, VM_PROT_READ);
72463012Sdes			pa = pmap_kextract( v);
72560737Sume			vm_page_hold(PHYS_TO_VM_PAGE(pa));
72660737Sume			lastv = v;
72760737Sume		}
72860737Sume
72963012Sdes/*
73063012Sdes * do the vm_fault if needed, do the copy-on-write thing when
73160376Sdes * reading stuff off device into memory.
73260737Sume */
73363012Sdes		vm_fault_quick(addr,
73463012Sdes			(bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ);
73563069Sdes		pa = pmap_kextract((vm_offset_t) addr);
73663069Sdes/*
73763012Sdes * hold the data page
73863012Sdes */
73963012Sdes		vm_page_hold(PHYS_TO_VM_PAGE(pa));
74063012Sdes	}
74163012Sdes
74263069Sdes	addr = bp->b_saveaddr = bp->b_data;
74363069Sdes	off = (int)addr & PGOFSET;
74463069Sdes	npf = btoc(round_page(bp->b_bufsize + off));
74563069Sdes	bp->b_data = (caddr_t) (kva + off);
74663012Sdes	while (npf--) {
74763069Sdes		pa = pmap_kextract((vm_offset_t)addr);
74863069Sdes		if (pa == 0)
74963012Sdes			panic("vmapbuf: null page frame");
75063012Sdes		pmap_kenter(kva, trunc_page(pa));
75163012Sdes		addr += PAGE_SIZE;
75263012Sdes		kva += PAGE_SIZE;
75363012Sdes	}
75463012Sdes}
75560737Sume
75663012Sdes/*
75763012Sdes * Free the io map PTEs associated with this IO operation.
75863012Sdes * We also invalidate the TLB entries and restore the original b_addr.
75963012Sdes */
76060737Sumevoid
76137535Sdesvunmapbuf(bp)
76263012Sdes	register struct buf *bp;
76363012Sdes{
76463012Sdes	register caddr_t addr;
76563012Sdes	vm_offset_t v,lastv,pa;
76663012Sdes
76763012Sdes	if ((bp->b_flags & B_PHYS) == 0)
76863012Sdes		panic("vunmapbuf");
76963012Sdes
77063012Sdes	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
77163012Sdes		addr < bp->b_data + bp->b_bufsize;
77263012Sdes		addr += NBPG)
77337535Sdes		pmap_kremove((vm_offset_t) addr);
77463012Sdes
77563012Sdes	bp->b_data = bp->b_saveaddr;
77663012Sdes	bp->b_saveaddr = NULL;
77763012Sdes
77863012Sdes/*
77963012Sdes * unhold the pde, and data pages
78063012Sdes */
78163012Sdes	lastv = 0;
78263012Sdes	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
78363012Sdes		addr < bp->b_data + bp->b_bufsize;
78463012Sdes		addr += NBPG) {
78563012Sdes
78663012Sdes	/*
78763012Sdes	 * release the data page
78863012Sdes	 */
78963012Sdes		pa = pmap_kextract((vm_offset_t) addr);
79063012Sdes		vm_page_unhold(PHYS_TO_VM_PAGE(pa));
79160376Sdes
79263012Sdes	/*
79363012Sdes	 * and unhold the page table
79463012Sdes	 */
79563012Sdes		v = trunc_page(((vm_offset_t)vtopte(addr)));
79663012Sdes		if (v != lastv) {
79763012Sdes			pa = pmap_kextract(v);
79863012Sdes			vm_page_unhold(PHYS_TO_VM_PAGE(pa));
79960376Sdes			lastv = v;
80063012Sdes		}
80163012Sdes	}
80263012Sdes}
80363012Sdes
80463012Sdes/*
80563012Sdes * Force reset the processor by invalidating the entire address space!
80663012Sdes */
80763012Sdesvoid
80863012Sdescpu_reset() {
80963012Sdes
81063012Sdes	/*
81163012Sdes	 * Attempt to do a CPU reset via the keyboard controller,
81263012Sdes	 * do not turn of the GateA20, as any machine that fails
81363012Sdes	 * to do the reset here would then end up in no man's land.
81463012Sdes	 */
81563012Sdes	outb(IO_KBD + 4, 0xFE);
81663012Sdes	DELAY(500000);	/* wait 0.5 sec to see if that did it */
81763012Sdes	printf("Keyboard reset did not work, attempting CPU shutdown\n");
81863012Sdes	DELAY(1000000);	/* wait 1 sec for printf to complete */
81963012Sdes
82063012Sdes	/* force a shutdown by unmapping entire address space ! */
82163012Sdes	bzero((caddr_t) PTD, NBPG);
82263012Sdes
82363012Sdes	/* "good night, sweet prince .... <THUNK!>" */
82463012Sdes	pmap_update();
82563012Sdes	/* NOTREACHED */
82663012Sdes	while(1);
82763012Sdes}
82863012Sdes
82963012Sdes/*
83063012Sdes * Grow the user stack to allow for 'sp'. This version grows the stack in
83163012Sdes *	chunks of SGROWSIZ.
83263012Sdes */
83363012Sdesint
83463012Sdesgrow(p, sp)
83563012Sdes	struct proc *p;
83663012Sdes	u_int sp;
83763012Sdes{
83863012Sdes	unsigned int nss;
83963012Sdes	caddr_t v;
84063012Sdes	struct vmspace *vm = p->p_vmspace;
84163012Sdes
84263012Sdes	if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
84363012Sdes	    return (1);
84463012Sdes
84563012Sdes	nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
84663012Sdes
84763012Sdes	if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
84863012Sdes		return (0);
84963012Sdes
85063012Sdes	if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
85163012Sdes	    SGROWSIZ) < nss) {
85263012Sdes		int grow_amount;
85363012Sdes		/*
85463012Sdes		 * If necessary, grow the VM that the stack occupies
85563012Sdes		 * to allow for the rlimit. This allows us to not have
85663012Sdes		 * to allocate all of the VM up-front in execve (which
85763012Sdes		 * is expensive).
85863012Sdes		 * Grow the VM by the amount requested rounded up to
85963012Sdes		 * the nearest SGROWSIZ to provide for some hysteresis.
86063012Sdes		 */
86163012Sdes		grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
86263012Sdes		v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
86363012Sdes		    SGROWSIZ) - grow_amount;
86463012Sdes		/*
86563012Sdes		 * If there isn't enough room to extend by SGROWSIZ, then
86663069Sdes		 * just extend to the maximum size
86763069Sdes		 */
86863012Sdes		if (v < vm->vm_maxsaddr) {
86963012Sdes			v = vm->vm_maxsaddr;
87063069Sdes			grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
87163069Sdes		}
87263069Sdes		if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v,
87363069Sdes		    grow_amount, FALSE) != KERN_SUCCESS)) {
87463069Sdes			return (0);
87563069Sdes		}
87663069Sdes		vm->vm_ssize += grow_amount >> PAGE_SHIFT;
87763069Sdes	}
87863069Sdes
87963012Sdes	return (1);
88063069Sdes}
88163012Sdes