vm_machdep.c revision 9507
1208747Sraj/*-
2208747Sraj * Copyright (c) 1982, 1986 The Regents of the University of California.
3208747Sraj * Copyright (c) 1989, 1990 William Jolitz
4208747Sraj * Copyright (c) 1994 John Dyson
5208747Sraj * All rights reserved.
6208747Sraj *
7208747Sraj * This code is derived from software contributed to Berkeley by
8208747Sraj * the Systems Programming Group of the University of Utah Computer
9208747Sraj * Science Department, and William Jolitz.
10208747Sraj *
11208747Sraj * Redistribution and use in source and binary forms, with or without
12208747Sraj * modification, are permitted provided that the following conditions
13208747Sraj * are met:
14208747Sraj * 1. Redistributions of source code must retain the above copyright
15208747Sraj *    notice, this list of conditions and the following disclaimer.
16208747Sraj * 2. Redistributions in binary form must reproduce the above copyright
17208747Sraj *    notice, this list of conditions and the following disclaimer in the
18208747Sraj *    documentation and/or other materials provided with the distribution.
19208747Sraj * 3. All advertising materials mentioning features or use of this software
20208747Sraj *    must display the following acknowledgement:
21208747Sraj *	This product includes software developed by the University of
22208747Sraj *	California, Berkeley and its contributors.
23208747Sraj * 4. Neither the name of the University nor the names of its contributors
24208747Sraj *    may be used to endorse or promote products derived from this software
25208747Sraj *    without specific prior written permission.
26208747Sraj *
27208747Sraj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30208747Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37208747Sraj * SUCH DAMAGE.
38208747Sraj *
39208747Sraj *	from: @(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
40208747Sraj *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
41208747Sraj *	$Id: vm_machdep.c,v 1.39 1995/05/30 07:59:46 rgrimes Exp $
42218077Smarcel */
43208747Sraj
44208747Sraj#include "npx.h"
45208747Sraj#include <sys/param.h>
46208747Sraj#include <sys/systm.h>
47218077Smarcel#include <sys/proc.h>
48208747Sraj#include <sys/malloc.h>
49208747Sraj#include <sys/buf.h>
50208747Sraj#include <sys/vnode.h>
51208747Sraj#include <sys/user.h>
52208747Sraj
53208747Sraj#include <machine/clock.h>
54208747Sraj#include <machine/cpu.h>
55208747Sraj#include <machine/md_var.h>
56208747Sraj
57208747Sraj#include <vm/vm.h>
58208747Sraj#include <vm/vm_kern.h>
59208747Sraj#include <vm/vm_page.h>
60208747Sraj
61208747Sraj#include <i386/isa/isa.h>
62208747Sraj
63208747Sraj#ifdef BOUNCE_BUFFERS
64208747Srajvm_map_t	io_map;
65208747Srajvolatile int	kvasfreecnt;
66208747Sraj
67208747Sraj
68208747Srajcaddr_t		bouncememory;
69208747Srajint		bouncepages, bpwait;
70208747Srajvm_offset_t	*bouncepa;
71208747Srajint		bmwait, bmfreeing;
72208747Sraj
73208747Sraj#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
74208747Srajint		bounceallocarraysize;
75208747Srajunsigned	*bounceallocarray;
76208747Srajint		bouncefree;
77208747Sraj
78208747Sraj#define SIXTEENMEG (4096*4096)
79208747Sraj#define MAXBKVA 1024
80208747Srajint		maxbkva = MAXBKVA*NBPG;
81208747Sraj
82208747Sraj/* special list that can be used at interrupt time for eventual kva free */
83208747Srajstruct kvasfree {
84208747Sraj	vm_offset_t addr;
85208747Sraj	vm_offset_t size;
86208747Sraj} kvaf[MAXBKVA];
87208747Sraj
88208747Sraj
89208747Srajvm_offset_t vm_bounce_kva();
90208747Sraj/*
91208747Sraj * get bounce buffer pages (count physically contiguous)
92208747Sraj * (only 1 inplemented now)
93208747Sraj */
94208747Srajvm_offset_t
95208747Srajvm_bounce_page_find(count)
96208747Sraj	int count;
97208747Sraj{
98208747Sraj	int bit;
99208747Sraj	int s,i;
100208747Sraj
101208747Sraj	if (count != 1)
102208747Sraj		panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
103208747Sraj
104208747Sraj	s = splbio();
105208747Srajretry:
106208747Sraj	for (i = 0; i < bounceallocarraysize; i++) {
107208747Sraj		if (bounceallocarray[i] != 0xffffffff) {
108208747Sraj			bit = ffs(~bounceallocarray[i]);
109208747Sraj			if (bit) {
110208747Sraj				bounceallocarray[i] |= 1 << (bit - 1) ;
111208747Sraj				bouncefree -= count;
112208747Sraj				splx(s);
113208747Sraj				return bouncepa[(i * BITS_IN_UNSIGNED + (bit - 1))];
114208747Sraj			}
115208747Sraj		}
116208747Sraj	}
117208747Sraj	bpwait = 1;
118208747Sraj	tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
119208747Sraj	goto retry;
120208747Sraj}
121208747Sraj
122208747Srajvoid
123208747Srajvm_bounce_kva_free(addr, size, now)
124208747Sraj	vm_offset_t addr;
125208747Sraj	vm_offset_t size;
126208747Sraj	int now;
127208747Sraj{
128208747Sraj	int s = splbio();
129208747Sraj	kvaf[kvasfreecnt].addr = addr;
130208747Sraj	kvaf[kvasfreecnt].size = size;
131208747Sraj	++kvasfreecnt;
132208747Sraj	if( now) {
133208747Sraj		/*
134208747Sraj		 * this will do wakeups
135208747Sraj		 */
136208747Sraj		vm_bounce_kva(0,0);
137208747Sraj	} else {
138208747Sraj		if (bmwait) {
139208747Sraj		/*
140208747Sraj		 * if anyone is waiting on the bounce-map, then wakeup
141208747Sraj		 */
142208747Sraj			wakeup((caddr_t) io_map);
143208747Sraj			bmwait = 0;
144208747Sraj		}
145208747Sraj	}
146208747Sraj	splx(s);
147208747Sraj}
148208747Sraj
149208747Sraj/*
150208747Sraj * free count bounce buffer pages
151208747Sraj */
152208747Srajvoid
153208747Srajvm_bounce_page_free(pa, count)
154208747Sraj	vm_offset_t pa;
155208747Sraj	int count;
156208747Sraj{
157208747Sraj	int allocindex;
158208747Sraj	int index;
159208747Sraj	int bit;
160208747Sraj
161208747Sraj	if (count != 1)
162208747Sraj		panic("vm_bounce_page_free -- no support for > 1 page yet!!!");
163218077Smarcel
164218077Smarcel	for(index=0;index<bouncepages;index++) {
165208747Sraj		if( pa == bouncepa[index])
166208747Sraj			break;
167208747Sraj	}
168208747Sraj
169208747Sraj	if( index == bouncepages)
170208747Sraj		panic("vm_bounce_page_free: invalid bounce buffer");
171208747Sraj
172208747Sraj	allocindex = index / BITS_IN_UNSIGNED;
173208747Sraj	bit = index % BITS_IN_UNSIGNED;
174208747Sraj
175208747Sraj	bounceallocarray[allocindex] &= ~(1 << bit);
176208747Sraj
177208747Sraj	bouncefree += count;
178208747Sraj	if (bpwait) {
179208747Sraj		bpwait = 0;
180208747Sraj		wakeup((caddr_t) &bounceallocarray);
181208747Sraj	}
182208747Sraj}
183208747Sraj
184208747Sraj/*
185208747Sraj * allocate count bounce buffer kva pages
186208747Sraj */
187208747Srajvm_offset_t
188208747Srajvm_bounce_kva(size, waitok)
189208747Sraj	int size;
190208747Sraj	int waitok;
191208747Sraj{
192208747Sraj	int i;
193208747Sraj	vm_offset_t kva = 0;
194208747Sraj	vm_offset_t off;
195208747Sraj	int s = splbio();
196208747Srajmore:
197208747Sraj	if (!bmfreeing && kvasfreecnt) {
198208747Sraj		bmfreeing = 1;
199208747Sraj		for (i = 0; i < kvasfreecnt; i++) {
200208747Sraj			for(off=0;off<kvaf[i].size;off+=NBPG) {
201208747Sraj				pmap_kremove( kvaf[i].addr + off);
202208747Sraj			}
203208747Sraj			kmem_free_wakeup(io_map, kvaf[i].addr,
204208747Sraj				kvaf[i].size);
205208747Sraj		}
206208747Sraj		kvasfreecnt = 0;
207208747Sraj		bmfreeing = 0;
208208747Sraj		if( bmwait) {
209208747Sraj			bmwait = 0;
210218077Smarcel			wakeup( (caddr_t) io_map);
211218077Smarcel		}
212208747Sraj	}
213218077Smarcel
214218077Smarcel	if( size == 0) {
215218077Smarcel		splx(s);
216208747Sraj		return NULL;
217218077Smarcel	}
218208747Sraj
219208747Sraj	if ((kva = kmem_alloc_pageable(io_map, size)) == 0) {
220208747Sraj		if( !waitok) {
221208747Sraj			splx(s);
222218077Smarcel			return NULL;
223218077Smarcel		}
224208747Sraj		bmwait = 1;
225208747Sraj		tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
226208747Sraj		goto more;
227208747Sraj	}
228218077Smarcel	splx(s);
229208747Sraj	return kva;
230208747Sraj}
231208747Sraj
232208747Sraj/*
233208747Sraj * same as vm_bounce_kva -- but really allocate (but takes pages as arg)
234208747Sraj */
235208747Srajvm_offset_t
236208747Srajvm_bounce_kva_alloc(count)
237218077Smarcelint count;
238218077Smarcel{
239218077Smarcel	int i;
240218077Smarcel	vm_offset_t kva;
241208747Sraj	vm_offset_t pa;
242208747Sraj	if( bouncepages == 0) {
243208747Sraj		kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
244208747Sraj		return kva;
245208747Sraj	}
246208747Sraj	kva = vm_bounce_kva(count*NBPG, 1);
247208747Sraj	for(i=0;i<count;i++) {
248208747Sraj		pa = vm_bounce_page_find(1);
249208747Sraj		pmap_kenter(kva + i * NBPG, pa);
250208747Sraj	}
251208747Sraj	return kva;
252208747Sraj}
253208747Sraj
254208747Sraj/*
255208747Sraj * same as vm_bounce_kva_free -- but really free
256208747Sraj */
257208747Srajvoid
258208747Srajvm_bounce_kva_alloc_free(kva, count)
259208747Sraj	vm_offset_t kva;
260208747Sraj	int count;
261208747Sraj{
262208747Sraj	int i;
263208747Sraj	vm_offset_t pa;
264208747Sraj	if( bouncepages == 0) {
265208747Sraj		free((caddr_t) kva, M_TEMP);
266208747Sraj		return;
267208747Sraj	}
268208747Sraj	for(i = 0; i < count; i++) {
269208747Sraj		pa = pmap_kextract(kva + i * NBPG);
270208747Sraj		vm_bounce_page_free(pa, 1);
271208747Sraj	}
272208747Sraj	vm_bounce_kva_free(kva, count*NBPG, 0);
273208747Sraj}
274208747Sraj
275208747Sraj/*
276208747Sraj * do the things necessary to the struct buf to implement
277208747Sraj * bounce buffers...  inserted before the disk sort
278208747Sraj */
279208747Srajvoid
280208747Srajvm_bounce_alloc(bp)
281208747Sraj	struct buf *bp;
282208747Sraj{
283208747Sraj	int countvmpg;
284208747Sraj	vm_offset_t vastart, vaend;
285208747Sraj	vm_offset_t vapstart, vapend;
286208747Sraj	vm_offset_t va, kva;
287208747Sraj	vm_offset_t pa;
288208747Sraj	int dobounceflag = 0;
289208747Sraj	int i;
290208747Sraj
291208747Sraj	if (bouncepages == 0)
292208747Sraj		return;
293208747Sraj
294208747Sraj	if (bp->b_flags & B_BOUNCE) {
295208747Sraj		printf("vm_bounce_alloc: called recursively???\n");
296208747Sraj		return;
297208747Sraj	}
298208747Sraj
299208747Sraj	if (bp->b_bufsize < bp->b_bcount) {
300208747Sraj		printf(
301208747Sraj		    "vm_bounce_alloc: b_bufsize(0x%lx) < b_bcount(0x%lx) !!\n",
302208747Sraj			bp->b_bufsize, bp->b_bcount);
303208747Sraj		panic("vm_bounce_alloc");
304208747Sraj	}
305208747Sraj
306208747Sraj/*
307208747Sraj *  This is not really necessary
308208747Sraj *	if( bp->b_bufsize != bp->b_bcount) {
309208747Sraj *		printf("size: %d, count: %d\n", bp->b_bufsize, bp->b_bcount);
310208747Sraj *	}
311208747Sraj */
312208747Sraj
313208747Sraj
314209908Sraj	vastart = (vm_offset_t) bp->b_data;
315218077Smarcel	vaend = (vm_offset_t) bp->b_data + bp->b_bufsize;
316218077Smarcel
317209908Sraj	vapstart = i386_trunc_page(vastart);
318208747Sraj	vapend = i386_round_page(vaend);
319208747Sraj	countvmpg = (vapend - vapstart) / NBPG;
320208747Sraj
321208747Sraj/*
322208747Sraj * if any page is above 16MB, then go into bounce-buffer mode
323208747Sraj */
324208747Sraj	va = vapstart;
325208747Sraj	for (i = 0; i < countvmpg; i++) {
326208747Sraj		pa = pmap_kextract(va);
327208747Sraj		if (pa >= SIXTEENMEG)
328208747Sraj			++dobounceflag;
329208747Sraj		if( pa == 0)
330208747Sraj			panic("vm_bounce_alloc: Unmapped page");
331208747Sraj		va += NBPG;
332208747Sraj	}
333208747Sraj	if (dobounceflag == 0)
334208747Sraj		return;
335208747Sraj
336208747Sraj	if (bouncepages < dobounceflag)
337208747Sraj		panic("Not enough bounce buffers!!!");
338208747Sraj
339208747Sraj/*
340208747Sraj * allocate a replacement kva for b_addr
341208747Sraj */
342208747Sraj	kva = vm_bounce_kva(countvmpg*NBPG, 1);
343208747Sraj#if 0
344208747Sraj	printf("%s: vapstart: %x, vapend: %x, countvmpg: %d, kva: %x ",
345208747Sraj		(bp->b_flags & B_READ) ? "read":"write",
346208747Sraj			vapstart, vapend, countvmpg, kva);
347208747Sraj#endif
348208747Sraj	va = vapstart;
349208747Sraj	for (i = 0; i < countvmpg; i++) {
350208747Sraj		pa = pmap_kextract(va);
351208747Sraj		if (pa >= SIXTEENMEG) {
352208747Sraj			/*
353208747Sraj			 * allocate a replacement page
354218077Smarcel			 */
355218077Smarcel			vm_offset_t bpa = vm_bounce_page_find(1);
356218077Smarcel			pmap_kenter(kva + (NBPG * i), bpa);
357218077Smarcel#if 0
358218077Smarcel			printf("r(%d): (%x,%x,%x) ", i, va, pa, bpa);
359218077Smarcel#endif
360218077Smarcel			/*
361218077Smarcel			 * if we are writing, the copy the data into the page
362218077Smarcel			 */
363218077Smarcel			if ((bp->b_flags & B_READ) == 0) {
364218077Smarcel				bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
365218077Smarcel			}
366218077Smarcel		} else {
367218077Smarcel			/*
368218077Smarcel			 * use original page
369218077Smarcel			 */
370218077Smarcel			pmap_kenter(kva + (NBPG * i), pa);
371218077Smarcel		}
372218077Smarcel		va += NBPG;
373218077Smarcel	}
374218077Smarcel
375218077Smarcel/*
376218077Smarcel * flag the buffer as being bounced
377218077Smarcel */
378218077Smarcel	bp->b_flags |= B_BOUNCE;
379218077Smarcel/*
380218077Smarcel * save the original buffer kva
381218077Smarcel */
382218077Smarcel	bp->b_savekva = bp->b_data;
383218077Smarcel/*
384218077Smarcel * put our new kva into the buffer (offset by original offset)
385218077Smarcel */
386218077Smarcel	bp->b_data = (caddr_t) (((vm_offset_t) kva) |
387218077Smarcel				((vm_offset_t) bp->b_savekva & (NBPG - 1)));
388218077Smarcel#if 0
389218077Smarcel	printf("b_savekva: %x, newva: %x\n", bp->b_savekva, bp->b_data);
390218077Smarcel#endif
391218077Smarcel	return;
392218077Smarcel}
393218077Smarcel
394218077Smarcel/*
395218077Smarcel * hook into biodone to free bounce buffer
396218077Smarcel */
397218077Smarcelvoid
398218077Smarcelvm_bounce_free(bp)
399218077Smarcel	struct buf *bp;
400218077Smarcel{
401218077Smarcel	int i;
402218077Smarcel	vm_offset_t origkva, bouncekva, bouncekvaend;
403218077Smarcel
404218077Smarcel/*
405218077Smarcel * if this isn't a bounced buffer, then just return
406218077Smarcel */
407218077Smarcel	if ((bp->b_flags & B_BOUNCE) == 0)
408218077Smarcel		return;
409218077Smarcel
410218077Smarcel/*
411218077Smarcel *  This check is not necessary
412218077Smarcel *	if (bp->b_bufsize != bp->b_bcount) {
413218077Smarcel *		printf("vm_bounce_free: b_bufsize=%d, b_bcount=%d\n",
414218077Smarcel *			bp->b_bufsize, bp->b_bcount);
415218077Smarcel *	}
416218077Smarcel */
417218077Smarcel
418218077Smarcel	origkva = (vm_offset_t) bp->b_savekva;
419218077Smarcel	bouncekva = (vm_offset_t) bp->b_data;
420218077Smarcel/*
421218077Smarcel	printf("free: %d ", bp->b_bufsize);
422218077Smarcel*/
423218077Smarcel
424218077Smarcel/*
425218077Smarcel * check every page in the kva space for b_addr
426218077Smarcel */
427218077Smarcel	for (i = 0; i < bp->b_bufsize; ) {
428218077Smarcel		vm_offset_t mybouncepa;
429218077Smarcel		vm_offset_t copycount;
430218077Smarcel
431218077Smarcel		copycount = i386_round_page(bouncekva + 1) - bouncekva;
432218077Smarcel		mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
433218077Smarcel
434218077Smarcel/*
435218077Smarcel * if this is a bounced pa, then process as one
436218077Smarcel */
437218077Smarcel		if ( mybouncepa != pmap_kextract( i386_trunc_page( origkva))) {
438218077Smarcel			vm_offset_t tocopy = copycount;
439218077Smarcel			if (i + tocopy > bp->b_bufsize)
440218077Smarcel				tocopy = bp->b_bufsize - i;
441218077Smarcel/*
442218077Smarcel * if this is a read, then copy from bounce buffer into original buffer
443218077Smarcel */
444218077Smarcel			if (bp->b_flags & B_READ)
445218077Smarcel				bcopy((caddr_t) bouncekva, (caddr_t) origkva, tocopy);
446218077Smarcel/*
447218077Smarcel * free the bounce allocation
448218077Smarcel */
449218077Smarcel
450218077Smarcel/*
451218077Smarcel			printf("(kva: %x, pa: %x)", bouncekva, mybouncepa);
452218077Smarcel*/
453218077Smarcel			vm_bounce_page_free(mybouncepa, 1);
454218077Smarcel		}
455218077Smarcel
456218077Smarcel		origkva += copycount;
457218077Smarcel		bouncekva += copycount;
458218077Smarcel		i += copycount;
459218077Smarcel	}
460218077Smarcel
461218077Smarcel/*
462218077Smarcel	printf("\n");
463218077Smarcel*/
464218077Smarcel/*
465218077Smarcel * add the old kva into the "to free" list
466218077Smarcel */
467218077Smarcel
468218077Smarcel	bouncekva= i386_trunc_page((vm_offset_t) bp->b_data);
469218077Smarcel	bouncekvaend= i386_round_page((vm_offset_t)bp->b_data + bp->b_bufsize);
470218077Smarcel
471218077Smarcel/*
472218077Smarcel	printf("freeva: %d\n", (bouncekvaend - bouncekva) / NBPG);
473218077Smarcel*/
474218077Smarcel	vm_bounce_kva_free( bouncekva, (bouncekvaend - bouncekva), 0);
475218077Smarcel	bp->b_data = bp->b_savekva;
476218077Smarcel	bp->b_savekva = 0;
477218077Smarcel	bp->b_flags &= ~B_BOUNCE;
478218077Smarcel
479218077Smarcel	return;
480218077Smarcel}
481218077Smarcel
482218077Smarcel
483218077Smarcel/*
484218077Smarcel * init the bounce buffer system
485218077Smarcel */
486218077Smarcelvoid
487218077Smarcelvm_bounce_init()
488218077Smarcel{
489218077Smarcel	int i;
490218077Smarcel
491218077Smarcel	kvasfreecnt = 0;
492218077Smarcel
493218077Smarcel	if (bouncepages == 0)
494218077Smarcel		return;
495218077Smarcel
496218077Smarcel	bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
497218077Smarcel	bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
498218077Smarcel
499218077Smarcel	if (!bounceallocarray)
500218077Smarcel		panic("Cannot allocate bounce resource array");
501218077Smarcel
502218077Smarcel	bouncepa = malloc(bouncepages * sizeof(vm_offset_t), M_TEMP, M_NOWAIT);
503218077Smarcel	if (!bouncepa)
504218077Smarcel		panic("Cannot allocate physical memory array");
505218077Smarcel
506218077Smarcel	for(i=0;i<bounceallocarraysize;i++) {
507218077Smarcel		bounceallocarray[i] = 0xffffffff;
508218077Smarcel	}
509218077Smarcel
510218077Smarcel	for(i=0;i<bouncepages;i++) {
511218077Smarcel		vm_offset_t pa;
512218077Smarcel		if( (pa = pmap_kextract((vm_offset_t) bouncememory + i * NBPG)) >= SIXTEENMEG)
513218077Smarcel			panic("bounce memory out of range");
514218077Smarcel		if( pa == 0)
515218077Smarcel			panic("bounce memory not resident");
516218077Smarcel		bouncepa[i] = pa;
517218077Smarcel		bounceallocarray[i/(8*sizeof(int))] &= ~(1<<(i%(8*sizeof(int))));
518218077Smarcel	}
519218077Smarcel	bouncefree = bouncepages;
520218077Smarcel
521218077Smarcel}
522218077Smarcel#endif /* BOUNCE_BUFFERS */
523218077Smarcel/*
524218077Smarcel * quick version of vm_fault
525218077Smarcel */
526218077Smarcel
527218077Smarcelvoid
528218077Smarcelvm_fault_quick( v, prot)
529218077Smarcel	vm_offset_t v;
530218077Smarcel	int prot;
531218077Smarcel{
532218077Smarcel	if (prot & VM_PROT_WRITE)
533218077Smarcel		subyte((char *)v, fubyte((char *)v));
534218077Smarcel	else
535218077Smarcel		(void) fubyte((char *)v);
536218077Smarcel}
537218077Smarcel
538218077Smarcel
539218077Smarcel/*
540218077Smarcel * Finish a fork operation, with process p2 nearly set up.
541218077Smarcel * Copy and update the kernel stack and pcb, making the child
542218077Smarcel * ready to run, and marking it so that it can return differently
543218077Smarcel * than the parent.  Returns 1 in the child process, 0 in the parent.
544218077Smarcel * We currently double-map the user area so that the stack is at the same
545218077Smarcel * address in each process; in the future we will probably relocate
546218077Smarcel * the frame pointers on the stack after copying.
547218077Smarcel */
548218077Smarcelint
549218077Smarcelcpu_fork(p1, p2)
550218077Smarcel	register struct proc *p1, *p2;
551218077Smarcel{
552218077Smarcel	register struct user *up = p2->p_addr;
553218077Smarcel	int offset;
554218077Smarcel
555218077Smarcel	/*
556218077Smarcel	 * Copy pcb and stack from proc p1 to p2.
557218077Smarcel	 * We do this as cheaply as possible, copying only the active
558218077Smarcel	 * part of the stack.  The stack and pcb need to agree;
559218077Smarcel	 * this is tricky, as the final pcb is constructed by savectx,
560218077Smarcel	 * but its frame isn't yet on the stack when the stack is copied.
561218077Smarcel	 * swtch compensates for this when the child eventually runs.
562218077Smarcel	 * This should be done differently, with a single call
563218077Smarcel	 * that copies and updates the pcb+stack,
564218077Smarcel	 * replacing the bcopy and savectx.
565218077Smarcel	 */
566218077Smarcel	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
567218077Smarcel	offset = mvesp() - (int)kstack;
568218077Smarcel	bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
569	    (unsigned) ctob(UPAGES) - offset);
570	p2->p_md.md_regs = p1->p_md.md_regs;
571
572	pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
573
574	/*
575	 *
576	 * Arrange for a non-local goto when the new process
577	 * is started, to resume here, returning nonzero from setjmp.
578	 */
579	if (savectx(&up->u_pcb, 1)) {
580		/*
581		 * Return 1 in child.
582		 */
583		return (1);
584	}
585	return (0);
586}
587
588void
589cpu_exit(p)
590	register struct proc *p;
591{
592
593#if NNPX > 0
594	npxexit(p);
595#endif	/* NNPX */
596	cnt.v_swtch++;
597	cpu_switch(p);
598	panic("cpu_exit");
599}
600
601void
602cpu_wait(p) struct proc *p; {
603/*	extern vm_map_t upages_map; */
604
605	/* drop per-process resources */
606 	pmap_remove(vm_map_pmap(u_map), (vm_offset_t) p->p_addr,
607		((vm_offset_t) p->p_addr) + ctob(UPAGES));
608	kmem_free(u_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
609	vmspace_free(p->p_vmspace);
610}
611
612/*
613 * Dump the machine specific header information at the start of a core dump.
614 */
615int
616cpu_coredump(p, vp, cred)
617	struct proc *p;
618	struct vnode *vp;
619	struct ucred *cred;
620{
621
622	return (vn_rdwr(UIO_WRITE, vp, (caddr_t) p->p_addr, ctob(UPAGES),
623	    (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL,
624	    p));
625}
626
627/*
628 * Set a red zone in the kernel stack after the u. area.
629 */
630void
631setredzone(pte, vaddr)
632	u_short *pte;
633	caddr_t vaddr;
634{
635/* eventually do this by setting up an expand-down stack segment
636   for ss0: selector, allowing stack access down to top of u.
637   this means though that protection violations need to be handled
638   thru a double fault exception that must do an integral task
639   switch to a known good context, within which a dump can be
640   taken. a sensible scheme might be to save the initial context
641   used by sched (that has physical memory mapped 1:1 at bottom)
642   and take the dump while still in mapped mode */
643}
644
645/*
646 * Move pages from one kernel virtual address to another.
647 * Both addresses are assumed to reside in the Sysmap,
648 * and size must be a multiple of CLSIZE.
649 */
650
651void
652pagemove(from, to, size)
653	register caddr_t from, to;
654	int size;
655{
656	register vm_offset_t pa;
657
658	if (size & CLOFSET)
659		panic("pagemove");
660	while (size > 0) {
661		pa = pmap_kextract((vm_offset_t)from);
662		if (pa == 0)
663			panic("pagemove 2");
664		if (pmap_kextract((vm_offset_t)to) != 0)
665			panic("pagemove 3");
666		pmap_kremove((vm_offset_t)from);
667		pmap_kenter((vm_offset_t)to, pa);
668		from += PAGE_SIZE;
669		to += PAGE_SIZE;
670		size -= PAGE_SIZE;
671	}
672}
673
674/*
675 * Convert kernel VA to physical address
676 */
677u_long
678kvtop(void *addr)
679{
680	vm_offset_t va;
681
682	va = pmap_kextract((vm_offset_t)addr);
683	if (va == 0)
684		panic("kvtop: zero page frame");
685	return((int)va);
686}
687
688/*
689 * Map an IO request into kernel virtual address space.
690 *
691 * All requests are (re)mapped into kernel VA space.
692 * Notice that we use b_bufsize for the size of the buffer
693 * to be mapped.  b_bcount might be modified by the driver.
694 */
695void
696vmapbuf(bp)
697	register struct buf *bp;
698{
699	register int npf;
700	register caddr_t addr;
701	int off;
702	vm_offset_t kva;
703	vm_offset_t pa, v;
704
705	if ((bp->b_flags & B_PHYS) == 0)
706		panic("vmapbuf");
707
708	/*
709	 * this is the kva that is to be used for
710	 * the temporary kernel mapping
711	 */
712	kva = (vm_offset_t) bp->b_saveaddr;
713
714	for (addr = (caddr_t)trunc_page(bp->b_data);
715		addr < bp->b_data + bp->b_bufsize;
716		addr += PAGE_SIZE) {
717
718/*
719 * do the vm_fault if needed, do the copy-on-write thing when
720 * reading stuff off device into memory.
721 */
722		vm_fault_quick(addr,
723			(bp->b_flags&B_READ)?(VM_PROT_READ|VM_PROT_WRITE):VM_PROT_READ);
724		pa = pmap_kextract((vm_offset_t) addr);
725		if (pa == 0)
726			panic("vmapbuf: page not present");
727/*
728 * hold the data page
729 */
730#ifdef DIAGNOSTIC
731		if( VM_PAGE_TO_PHYS(PHYS_TO_VM_PAGE(pa)) != pa)
732			panic("vmapbuf: confused PHYS_TO_VM_PAGE mapping");
733#endif
734		vm_page_hold(PHYS_TO_VM_PAGE(pa));
735	}
736
737	addr = bp->b_saveaddr = bp->b_data;
738	off = (int)addr & PGOFSET;
739	npf = btoc(round_page(bp->b_bufsize + off));
740	bp->b_data = (caddr_t) (kva + off);
741	while (npf--) {
742		pa = pmap_kextract((vm_offset_t)addr);
743		if (pa == 0)
744			panic("vmapbuf: null page frame");
745		pmap_kenter(kva, trunc_page(pa));
746		addr += PAGE_SIZE;
747		kva += PAGE_SIZE;
748	}
749}
750
751/*
752 * Free the io map PTEs associated with this IO operation.
753 * We also invalidate the TLB entries and restore the original b_addr.
754 */
755void
756vunmapbuf(bp)
757	register struct buf *bp;
758{
759	register caddr_t addr;
760	vm_offset_t v,pa;
761
762	if ((bp->b_flags & B_PHYS) == 0)
763		panic("vunmapbuf");
764
765	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
766		addr < bp->b_data + bp->b_bufsize;
767		addr += NBPG)
768		pmap_kremove((vm_offset_t) addr);
769
770	bp->b_data = bp->b_saveaddr;
771	bp->b_saveaddr = NULL;
772
773/*
774 * unhold the pde, and data pages
775 */
776	for (addr = (caddr_t)trunc_page((vm_offset_t) bp->b_data);
777		addr < bp->b_data + bp->b_bufsize;
778		addr += NBPG) {
779	/*
780	 * release the data page
781	 */
782		pa = pmap_kextract((vm_offset_t) addr);
783		vm_page_unhold(PHYS_TO_VM_PAGE(pa));
784	}
785}
786
787/*
788 * Force reset the processor by invalidating the entire address space!
789 */
790void
791cpu_reset() {
792
793	/*
794	 * Attempt to do a CPU reset via the keyboard controller,
795	 * do not turn of the GateA20, as any machine that fails
796	 * to do the reset here would then end up in no man's land.
797	 */
798
799#ifndef BROKEN_KEYBOARD_RESET
800	outb(IO_KBD + 4, 0xFE);
801	DELAY(500000);	/* wait 0.5 sec to see if that did it */
802	printf("Keyboard reset did not work, attempting CPU shutdown\n");
803	DELAY(1000000);	/* wait 1 sec for printf to complete */
804#endif
805
806	/* force a shutdown by unmapping entire address space ! */
807	bzero((caddr_t) PTD, NBPG);
808
809	/* "good night, sweet prince .... <THUNK!>" */
810	pmap_update();
811	/* NOTREACHED */
812	while(1);
813}
814
815/*
816 * Grow the user stack to allow for 'sp'. This version grows the stack in
817 *	chunks of SGROWSIZ.
818 */
819int
820grow(p, sp)
821	struct proc *p;
822	u_int sp;
823{
824	unsigned int nss;
825	caddr_t v;
826	struct vmspace *vm = p->p_vmspace;
827
828	if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
829	    return (1);
830
831	nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
832
833	if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
834		return (0);
835
836	if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
837	    SGROWSIZ) < nss) {
838		int grow_amount;
839		/*
840		 * If necessary, grow the VM that the stack occupies
841		 * to allow for the rlimit. This allows us to not have
842		 * to allocate all of the VM up-front in execve (which
843		 * is expensive).
844		 * Grow the VM by the amount requested rounded up to
845		 * the nearest SGROWSIZ to provide for some hysteresis.
846		 */
847		grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
848		v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
849		    SGROWSIZ) - grow_amount;
850		/*
851		 * If there isn't enough room to extend by SGROWSIZ, then
852		 * just extend to the maximum size
853		 */
854		if (v < vm->vm_maxsaddr) {
855			v = vm->vm_maxsaddr;
856			grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
857		}
858		if ((grow_amount == 0) || (vm_map_find(&vm->vm_map, NULL, 0, (vm_offset_t *)&v,
859		    grow_amount, FALSE) != KERN_SUCCESS)) {
860			return (0);
861		}
862		vm->vm_ssize += grow_amount >> PAGE_SHIFT;
863	}
864
865	return (1);
866}
867