xref: /freebsd/sys/i386/i386/vm_machdep.c (revision d5e26ef0ef23717b01cf6e3a8eb88eb88b68cbe2)
15b81b6b3SRodney W. Grimes /*-
25b81b6b3SRodney W. Grimes  * Copyright (c) 1982, 1986 The Regents of the University of California.
35b81b6b3SRodney W. Grimes  * Copyright (c) 1989, 1990 William Jolitz
45b81b6b3SRodney W. Grimes  * All rights reserved.
55b81b6b3SRodney W. Grimes  *
65b81b6b3SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
75b81b6b3SRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
85b81b6b3SRodney W. Grimes  * Science Department, and William Jolitz.
95b81b6b3SRodney W. Grimes  *
105b81b6b3SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
115b81b6b3SRodney W. Grimes  * modification, are permitted provided that the following conditions
125b81b6b3SRodney W. Grimes  * are met:
135b81b6b3SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
145b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
155b81b6b3SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
165b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
175b81b6b3SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
185b81b6b3SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
195b81b6b3SRodney W. Grimes  *    must display the following acknowledgement:
205b81b6b3SRodney W. Grimes  *	This product includes software developed by the University of
215b81b6b3SRodney W. Grimes  *	California, Berkeley and its contributors.
225b81b6b3SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
235b81b6b3SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
245b81b6b3SRodney W. Grimes  *    without specific prior written permission.
255b81b6b3SRodney W. Grimes  *
265b81b6b3SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
275b81b6b3SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
285b81b6b3SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
295b81b6b3SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
305b81b6b3SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
315b81b6b3SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
325b81b6b3SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
335b81b6b3SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
345b81b6b3SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
355b81b6b3SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
365b81b6b3SRodney W. Grimes  * SUCH DAMAGE.
375b81b6b3SRodney W. Grimes  *
38960173b9SRodney W. Grimes  *	from: @(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
395b81b6b3SRodney W. Grimes  *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
40d5e26ef0SDavid Greenman  *	$Id: vm_machdep.c,v 1.13 1994/03/21 09:35:10 davidg Exp $
415b81b6b3SRodney W. Grimes  */
425b81b6b3SRodney W. Grimes 
43960173b9SRodney W. Grimes #include "npx.h"
445b81b6b3SRodney W. Grimes #include "param.h"
455b81b6b3SRodney W. Grimes #include "systm.h"
465b81b6b3SRodney W. Grimes #include "proc.h"
475b81b6b3SRodney W. Grimes #include "malloc.h"
485b81b6b3SRodney W. Grimes #include "buf.h"
495b81b6b3SRodney W. Grimes #include "user.h"
505b81b6b3SRodney W. Grimes 
515b81b6b3SRodney W. Grimes #include "../include/cpu.h"
525b81b6b3SRodney W. Grimes 
535b81b6b3SRodney W. Grimes #include "vm/vm.h"
545b81b6b3SRodney W. Grimes #include "vm/vm_kern.h"
555b81b6b3SRodney W. Grimes 
56d5e26ef0SDavid Greenman #ifndef NOBOUNCE
57d5e26ef0SDavid Greenman 
58d5e26ef0SDavid Greenman caddr_t		bouncememory;
59d5e26ef0SDavid Greenman vm_offset_t	bouncepa, bouncepaend;
60d5e26ef0SDavid Greenman int		bouncepages;
61d5e26ef0SDavid Greenman vm_map_t	bounce_map;
62d5e26ef0SDavid Greenman int		bmwait, bmfreeing;
63d5e26ef0SDavid Greenman 
64d5e26ef0SDavid Greenman int		bounceallocarraysize;
65d5e26ef0SDavid Greenman unsigned	*bounceallocarray;
66d5e26ef0SDavid Greenman int		bouncefree;
67d5e26ef0SDavid Greenman 
68d5e26ef0SDavid Greenman #define SIXTEENMEG (4096*4096)
69d5e26ef0SDavid Greenman #define MAXBKVA 512
70d5e26ef0SDavid Greenman 
71d5e26ef0SDavid Greenman /* special list that can be used at interrupt time for eventual kva free */
72d5e26ef0SDavid Greenman struct kvasfree {
73d5e26ef0SDavid Greenman 	vm_offset_t addr;
74d5e26ef0SDavid Greenman 	vm_offset_t size;
75d5e26ef0SDavid Greenman } kvaf[MAXBKVA];
76d5e26ef0SDavid Greenman 
77d5e26ef0SDavid Greenman int		kvasfreecnt;
78d5e26ef0SDavid Greenman 
79d5e26ef0SDavid Greenman /*
80d5e26ef0SDavid Greenman  * get bounce buffer pages (count physically contiguous)
81d5e26ef0SDavid Greenman  * (only 1 inplemented now)
82d5e26ef0SDavid Greenman  */
83d5e26ef0SDavid Greenman vm_offset_t
84d5e26ef0SDavid Greenman vm_bounce_page_find(count)
85d5e26ef0SDavid Greenman 	int count;
86d5e26ef0SDavid Greenman {
87d5e26ef0SDavid Greenman 	int bit;
88d5e26ef0SDavid Greenman 	int s,i;
89d5e26ef0SDavid Greenman 
90d5e26ef0SDavid Greenman 	if (count != 1)
91d5e26ef0SDavid Greenman 		panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
92d5e26ef0SDavid Greenman 
93d5e26ef0SDavid Greenman 	s = splbio();
94d5e26ef0SDavid Greenman retry:
95d5e26ef0SDavid Greenman 	for (i = 0; i < bounceallocarraysize; i++) {
96d5e26ef0SDavid Greenman 		if (bounceallocarray[i] != 0xffffffff) {
97d5e26ef0SDavid Greenman 			if (bit = ffs(~bounceallocarray[i])) {
98d5e26ef0SDavid Greenman 				bounceallocarray[i] |= 1 << (bit - 1) ;
99d5e26ef0SDavid Greenman 				bouncefree -= count;
100d5e26ef0SDavid Greenman 				splx(s);
101d5e26ef0SDavid Greenman 				return bouncepa + (i * 8 * sizeof(unsigned) + (bit - 1)) * NBPG;
102d5e26ef0SDavid Greenman 			}
103d5e26ef0SDavid Greenman 		}
104d5e26ef0SDavid Greenman 	}
105d5e26ef0SDavid Greenman 	tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
106d5e26ef0SDavid Greenman 	goto retry;
107d5e26ef0SDavid Greenman }
108d5e26ef0SDavid Greenman 
109d5e26ef0SDavid Greenman /*
110d5e26ef0SDavid Greenman  * free count bounce buffer pages
111d5e26ef0SDavid Greenman  */
112d5e26ef0SDavid Greenman void
113d5e26ef0SDavid Greenman vm_bounce_page_free(pa, count)
114d5e26ef0SDavid Greenman 	vm_offset_t pa;
115d5e26ef0SDavid Greenman 	int count;
116d5e26ef0SDavid Greenman {
117d5e26ef0SDavid Greenman 	int allocindex;
118d5e26ef0SDavid Greenman 	int index;
119d5e26ef0SDavid Greenman 	int bit;
120d5e26ef0SDavid Greenman 
121d5e26ef0SDavid Greenman 	if (count != 1)
122d5e26ef0SDavid Greenman 		panic("vm_bounce_page_free -- no support for > 1 page yet!!!\n");
123d5e26ef0SDavid Greenman 
124d5e26ef0SDavid Greenman 	index = (pa - bouncepa) / NBPG;
125d5e26ef0SDavid Greenman 
126d5e26ef0SDavid Greenman 	if ((index < 0) || (index >= bouncepages))
127d5e26ef0SDavid Greenman 		panic("vm_bounce_page_free -- bad index\n");
128d5e26ef0SDavid Greenman 
129d5e26ef0SDavid Greenman 	allocindex = index / (8 * sizeof(unsigned));
130d5e26ef0SDavid Greenman 	bit = index % (8 * sizeof(unsigned));
131d5e26ef0SDavid Greenman 
132d5e26ef0SDavid Greenman 	bounceallocarray[allocindex] &= ~(1 << bit);
133d5e26ef0SDavid Greenman 
134d5e26ef0SDavid Greenman 	bouncefree += count;
135d5e26ef0SDavid Greenman 	wakeup((caddr_t) &bounceallocarray);
136d5e26ef0SDavid Greenman }
137d5e26ef0SDavid Greenman 
138d5e26ef0SDavid Greenman /*
139d5e26ef0SDavid Greenman  * allocate count bounce buffer kva pages
140d5e26ef0SDavid Greenman  */
141d5e26ef0SDavid Greenman vm_offset_t
142d5e26ef0SDavid Greenman vm_bounce_kva(count)
143d5e26ef0SDavid Greenman 	int count;
144d5e26ef0SDavid Greenman {
145d5e26ef0SDavid Greenman 	int tofree;
146d5e26ef0SDavid Greenman 	int i;
147d5e26ef0SDavid Greenman 	int startfree;
148d5e26ef0SDavid Greenman 	vm_offset_t kva;
149d5e26ef0SDavid Greenman 	int s = splbio();
150d5e26ef0SDavid Greenman 	startfree = 0;
151d5e26ef0SDavid Greenman more:
152d5e26ef0SDavid Greenman 	if (!bmfreeing && (tofree = kvasfreecnt)) {
153d5e26ef0SDavid Greenman 		bmfreeing = 1;
154d5e26ef0SDavid Greenman more1:
155d5e26ef0SDavid Greenman 		for (i = startfree; i < kvasfreecnt; i++) {
156d5e26ef0SDavid Greenman 			pmap_remove(kernel_pmap,
157d5e26ef0SDavid Greenman 				kvaf[i].addr, kvaf[i].addr + kvaf[i].size);
158d5e26ef0SDavid Greenman 			kmem_free_wakeup(bounce_map, kvaf[i].addr,
159d5e26ef0SDavid Greenman 				kvaf[i].size);
160d5e26ef0SDavid Greenman 		}
161d5e26ef0SDavid Greenman 		if (kvasfreecnt != tofree) {
162d5e26ef0SDavid Greenman 			startfree = i;
163d5e26ef0SDavid Greenman 			bmfreeing = 0;
164d5e26ef0SDavid Greenman 			goto more;
165d5e26ef0SDavid Greenman 		}
166d5e26ef0SDavid Greenman 		kvasfreecnt = 0;
167d5e26ef0SDavid Greenman 		bmfreeing = 0;
168d5e26ef0SDavid Greenman 	}
169d5e26ef0SDavid Greenman 
170d5e26ef0SDavid Greenman 	if (!(kva = kmem_alloc_pageable(bounce_map, count * NBPG))) {
171d5e26ef0SDavid Greenman 		bmwait = 1;
172d5e26ef0SDavid Greenman 		tsleep((caddr_t) bounce_map, PRIBIO, "bmwait", 0);
173d5e26ef0SDavid Greenman 		goto more;
174d5e26ef0SDavid Greenman 	}
175d5e26ef0SDavid Greenman 
176d5e26ef0SDavid Greenman 	splx(s);
177d5e26ef0SDavid Greenman 
178d5e26ef0SDavid Greenman 	return kva;
179d5e26ef0SDavid Greenman }
180d5e26ef0SDavid Greenman 
181d5e26ef0SDavid Greenman /*
182d5e26ef0SDavid Greenman  * init the bounce buffer system
183d5e26ef0SDavid Greenman  */
184d5e26ef0SDavid Greenman void
185d5e26ef0SDavid Greenman vm_bounce_init()
186d5e26ef0SDavid Greenman {
187d5e26ef0SDavid Greenman 	vm_offset_t minaddr, maxaddr;
188d5e26ef0SDavid Greenman 
189d5e26ef0SDavid Greenman 	if (bouncepages == 0)
190d5e26ef0SDavid Greenman 		return;
191d5e26ef0SDavid Greenman 
192d5e26ef0SDavid Greenman 	bounceallocarraysize = (bouncepages + (8*sizeof(unsigned))-1) / (8 * sizeof(unsigned));
193d5e26ef0SDavid Greenman 	bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
194d5e26ef0SDavid Greenman 
195d5e26ef0SDavid Greenman 	if (!bounceallocarray)
196d5e26ef0SDavid Greenman 		panic("Cannot allocate bounce resource array\n");
197d5e26ef0SDavid Greenman 
198d5e26ef0SDavid Greenman 	bzero(bounceallocarray, bounceallocarraysize * sizeof(long));
199d5e26ef0SDavid Greenman 
200d5e26ef0SDavid Greenman 	bounce_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, MAXBKVA * NBPG, FALSE);
201d5e26ef0SDavid Greenman 
202d5e26ef0SDavid Greenman 	bouncepa = pmap_extract(kernel_pmap, (vm_offset_t) bouncememory);
203d5e26ef0SDavid Greenman 	bouncepaend = bouncepa + bouncepages * NBPG;
204d5e26ef0SDavid Greenman 	bouncefree = bouncepages;
205d5e26ef0SDavid Greenman 	kvasfreecnt = 0;
206d5e26ef0SDavid Greenman }
207d5e26ef0SDavid Greenman 
208d5e26ef0SDavid Greenman /*
209d5e26ef0SDavid Greenman  * do the things necessary to the struct buf to implement
210d5e26ef0SDavid Greenman  * bounce buffers...  inserted before the disk sort
211d5e26ef0SDavid Greenman  */
212d5e26ef0SDavid Greenman void
213d5e26ef0SDavid Greenman vm_bounce_alloc(bp)
214d5e26ef0SDavid Greenman 	struct buf *bp;
215d5e26ef0SDavid Greenman {
216d5e26ef0SDavid Greenman 	int countvmpg;
217d5e26ef0SDavid Greenman 	vm_offset_t vastart, vaend;
218d5e26ef0SDavid Greenman 	vm_offset_t vapstart, vapend;
219d5e26ef0SDavid Greenman 	vm_offset_t va, kva;
220d5e26ef0SDavid Greenman 	vm_offset_t pa;
221d5e26ef0SDavid Greenman 	int dobounceflag = 0;
222d5e26ef0SDavid Greenman 	int bounceindex;
223d5e26ef0SDavid Greenman 	int i;
224d5e26ef0SDavid Greenman 	int s;
225d5e26ef0SDavid Greenman 
226d5e26ef0SDavid Greenman 	if (bouncepages == 0)
227d5e26ef0SDavid Greenman 		return;
228d5e26ef0SDavid Greenman 
229d5e26ef0SDavid Greenman 	vastart = (vm_offset_t) bp->b_un.b_addr;
230d5e26ef0SDavid Greenman 	vaend = (vm_offset_t) bp->b_un.b_addr + bp->b_bcount;
231d5e26ef0SDavid Greenman 
232d5e26ef0SDavid Greenman 	vapstart = i386_trunc_page(vastart);
233d5e26ef0SDavid Greenman 	vapend = i386_round_page(vaend);
234d5e26ef0SDavid Greenman 	countvmpg = (vapend - vapstart) / NBPG;
235d5e26ef0SDavid Greenman 
236d5e26ef0SDavid Greenman /*
237d5e26ef0SDavid Greenman  * if any page is above 16MB, then go into bounce-buffer mode
238d5e26ef0SDavid Greenman  */
239d5e26ef0SDavid Greenman 	va = vapstart;
240d5e26ef0SDavid Greenman 	for (i = 0; i < countvmpg; i++) {
241d5e26ef0SDavid Greenman 		pa = pmap_extract(kernel_pmap, va);
242d5e26ef0SDavid Greenman 		if (pa >= SIXTEENMEG)
243d5e26ef0SDavid Greenman 			++dobounceflag;
244d5e26ef0SDavid Greenman 		va += NBPG;
245d5e26ef0SDavid Greenman 	}
246d5e26ef0SDavid Greenman 	if (dobounceflag == 0)
247d5e26ef0SDavid Greenman 		return;
248d5e26ef0SDavid Greenman 
249d5e26ef0SDavid Greenman 	if (bouncepages < dobounceflag)
250d5e26ef0SDavid Greenman 		panic("Not enough bounce buffers!!!");
251d5e26ef0SDavid Greenman 
252d5e26ef0SDavid Greenman /*
253d5e26ef0SDavid Greenman  * allocate a replacement kva for b_addr
254d5e26ef0SDavid Greenman  */
255d5e26ef0SDavid Greenman 	kva = vm_bounce_kva(countvmpg);
256d5e26ef0SDavid Greenman 	va = vapstart;
257d5e26ef0SDavid Greenman 	for (i = 0; i < countvmpg; i++) {
258d5e26ef0SDavid Greenman 		pa = pmap_extract(kernel_pmap, va);
259d5e26ef0SDavid Greenman 		if (pa >= SIXTEENMEG) {
260d5e26ef0SDavid Greenman 			/*
261d5e26ef0SDavid Greenman 			 * allocate a replacement page
262d5e26ef0SDavid Greenman 			 */
263d5e26ef0SDavid Greenman 			vm_offset_t bpa = vm_bounce_page_find(1);
264d5e26ef0SDavid Greenman 			pmap_enter(kernel_pmap, kva + (NBPG * i), bpa, VM_PROT_DEFAULT,
265d5e26ef0SDavid Greenman 				TRUE);
266d5e26ef0SDavid Greenman 			/*
267d5e26ef0SDavid Greenman 			 * if we are writing, the copy the data into the page
268d5e26ef0SDavid Greenman 			 */
269d5e26ef0SDavid Greenman 			if ((bp->b_flags & B_READ) == 0)
270d5e26ef0SDavid Greenman 				bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
271d5e26ef0SDavid Greenman 		} else {
272d5e26ef0SDavid Greenman 			/*
273d5e26ef0SDavid Greenman 			 * use original page
274d5e26ef0SDavid Greenman 			 */
275d5e26ef0SDavid Greenman 			pmap_enter(kernel_pmap, kva + (NBPG * i), pa, VM_PROT_DEFAULT,
276d5e26ef0SDavid Greenman 				TRUE);
277d5e26ef0SDavid Greenman 		}
278d5e26ef0SDavid Greenman 		va += NBPG;
279d5e26ef0SDavid Greenman 	}
280d5e26ef0SDavid Greenman 
281d5e26ef0SDavid Greenman /*
282d5e26ef0SDavid Greenman  * flag the buffer as being bounced
283d5e26ef0SDavid Greenman  */
284d5e26ef0SDavid Greenman 	bp->b_flags |= B_BOUNCE;
285d5e26ef0SDavid Greenman /*
286d5e26ef0SDavid Greenman  * save the original buffer kva
287d5e26ef0SDavid Greenman  */
288d5e26ef0SDavid Greenman 	bp->b_savekva = bp->b_un.b_addr;
289d5e26ef0SDavid Greenman /*
290d5e26ef0SDavid Greenman  * put our new kva into the buffer (offset by original offset)
291d5e26ef0SDavid Greenman  */
292d5e26ef0SDavid Greenman 	bp->b_un.b_addr = (caddr_t) (((vm_offset_t) kva) |
293d5e26ef0SDavid Greenman 				((vm_offset_t) bp->b_savekva & (NBPG - 1)));
294d5e26ef0SDavid Greenman 	return;
295d5e26ef0SDavid Greenman }
296d5e26ef0SDavid Greenman 
297d5e26ef0SDavid Greenman /*
298d5e26ef0SDavid Greenman  * hook into biodone to free bounce buffer
299d5e26ef0SDavid Greenman  */
300d5e26ef0SDavid Greenman void
301d5e26ef0SDavid Greenman vm_bounce_free(bp)
302d5e26ef0SDavid Greenman 	struct buf *bp;
303d5e26ef0SDavid Greenman {
304d5e26ef0SDavid Greenman 	int i;
305d5e26ef0SDavid Greenman 	vm_offset_t origkva, bouncekva;
306d5e26ef0SDavid Greenman 	vm_offset_t vastart, vaend;
307d5e26ef0SDavid Greenman 	vm_offset_t vapstart, vapend;
308d5e26ef0SDavid Greenman 	int countbounce = 0;
309d5e26ef0SDavid Greenman 	vm_offset_t firstbouncepa = 0;
310d5e26ef0SDavid Greenman 	int firstbounceindex;
311d5e26ef0SDavid Greenman 	int countvmpg;
312d5e26ef0SDavid Greenman 	vm_offset_t bcount;
313d5e26ef0SDavid Greenman 	int s;
314d5e26ef0SDavid Greenman 
315d5e26ef0SDavid Greenman /*
316d5e26ef0SDavid Greenman  * if this isn't a bounced buffer, then just return
317d5e26ef0SDavid Greenman  */
318d5e26ef0SDavid Greenman 	if ((bp->b_flags & B_BOUNCE) == 0)
319d5e26ef0SDavid Greenman 		return;
320d5e26ef0SDavid Greenman 
321d5e26ef0SDavid Greenman 	origkva = (vm_offset_t) bp->b_savekva;
322d5e26ef0SDavid Greenman 	bouncekva = (vm_offset_t) bp->b_un.b_addr;
323d5e26ef0SDavid Greenman 
324d5e26ef0SDavid Greenman 	vastart = bouncekva;
325d5e26ef0SDavid Greenman 	vaend = bouncekva + bp->b_bcount;
326d5e26ef0SDavid Greenman 	bcount = bp->b_bcount;
327d5e26ef0SDavid Greenman 
328d5e26ef0SDavid Greenman 	vapstart = i386_trunc_page(vastart);
329d5e26ef0SDavid Greenman 	vapend = i386_round_page(vaend);
330d5e26ef0SDavid Greenman 
331d5e26ef0SDavid Greenman 	countvmpg = (vapend - vapstart) / NBPG;
332d5e26ef0SDavid Greenman 
333d5e26ef0SDavid Greenman /*
334d5e26ef0SDavid Greenman  * check every page in the kva space for b_addr
335d5e26ef0SDavid Greenman  */
336d5e26ef0SDavid Greenman 	for (i = 0; i < countvmpg; i++) {
337d5e26ef0SDavid Greenman 		vm_offset_t mybouncepa;
338d5e26ef0SDavid Greenman 		vm_offset_t copycount;
339d5e26ef0SDavid Greenman 
340d5e26ef0SDavid Greenman 		copycount = i386_round_page(bouncekva + 1) - bouncekva;
341d5e26ef0SDavid Greenman 		mybouncepa = pmap_extract(kernel_pmap, i386_trunc_page(bouncekva));
342d5e26ef0SDavid Greenman 
343d5e26ef0SDavid Greenman /*
344d5e26ef0SDavid Greenman  * if this is a bounced pa, then process as one
345d5e26ef0SDavid Greenman  */
346d5e26ef0SDavid Greenman 		if ((mybouncepa >= bouncepa) && (mybouncepa < bouncepaend)) {
347d5e26ef0SDavid Greenman 			if (copycount > bcount)
348d5e26ef0SDavid Greenman 				copycount = bcount;
349d5e26ef0SDavid Greenman /*
350d5e26ef0SDavid Greenman  * if this is a read, then copy from bounce buffer into original buffer
351d5e26ef0SDavid Greenman  */
352d5e26ef0SDavid Greenman 			if (bp->b_flags & B_READ)
353d5e26ef0SDavid Greenman 				bcopy((caddr_t) bouncekva, (caddr_t) origkva, copycount);
354d5e26ef0SDavid Greenman /*
355d5e26ef0SDavid Greenman  * free the bounce allocation
356d5e26ef0SDavid Greenman  */
357d5e26ef0SDavid Greenman 			vm_bounce_page_free(i386_trunc_page(mybouncepa), 1);
358d5e26ef0SDavid Greenman 		}
359d5e26ef0SDavid Greenman 
360d5e26ef0SDavid Greenman 		origkva += copycount;
361d5e26ef0SDavid Greenman 		bouncekva += copycount;
362d5e26ef0SDavid Greenman 		bcount -= copycount;
363d5e26ef0SDavid Greenman 	}
364d5e26ef0SDavid Greenman 
365d5e26ef0SDavid Greenman /*
366d5e26ef0SDavid Greenman  * add the old kva into the "to free" list
367d5e26ef0SDavid Greenman  */
368d5e26ef0SDavid Greenman 	bouncekva = i386_trunc_page((vm_offset_t) bp->b_un.b_addr);
369d5e26ef0SDavid Greenman 	kvaf[kvasfreecnt].addr = bouncekva;
370d5e26ef0SDavid Greenman 	kvaf[kvasfreecnt++].size = countvmpg * NBPG;
371d5e26ef0SDavid Greenman 	if (bmwait) {
372d5e26ef0SDavid Greenman 		/*
373d5e26ef0SDavid Greenman 		 * if anyone is waiting on the bounce-map, then wakeup
374d5e26ef0SDavid Greenman 		 */
375d5e26ef0SDavid Greenman 		wakeup((caddr_t) bounce_map);
376d5e26ef0SDavid Greenman 		bmwait = 0;
377d5e26ef0SDavid Greenman 	}
378d5e26ef0SDavid Greenman 
379d5e26ef0SDavid Greenman 	bp->b_un.b_addr = bp->b_savekva;
380d5e26ef0SDavid Greenman 	bp->b_savekva = 0;
381d5e26ef0SDavid Greenman 	bp->b_flags &= ~B_BOUNCE;
382d5e26ef0SDavid Greenman 
383d5e26ef0SDavid Greenman 	return;
384d5e26ef0SDavid Greenman }
385d5e26ef0SDavid Greenman 
386d5e26ef0SDavid Greenman #endif /* NOBOUNCE */
387d5e26ef0SDavid Greenman 
3885b81b6b3SRodney W. Grimes /*
3895b81b6b3SRodney W. Grimes  * Finish a fork operation, with process p2 nearly set up.
3905b81b6b3SRodney W. Grimes  * Copy and update the kernel stack and pcb, making the child
3915b81b6b3SRodney W. Grimes  * ready to run, and marking it so that it can return differently
3925b81b6b3SRodney W. Grimes  * than the parent.  Returns 1 in the child process, 0 in the parent.
3935b81b6b3SRodney W. Grimes  * We currently double-map the user area so that the stack is at the same
3945b81b6b3SRodney W. Grimes  * address in each process; in the future we will probably relocate
3955b81b6b3SRodney W. Grimes  * the frame pointers on the stack after copying.
3965b81b6b3SRodney W. Grimes  */
397381fe1aaSGarrett Wollman int
3985b81b6b3SRodney W. Grimes cpu_fork(p1, p2)
3995b81b6b3SRodney W. Grimes 	register struct proc *p1, *p2;
4005b81b6b3SRodney W. Grimes {
4015b81b6b3SRodney W. Grimes 	register struct user *up = p2->p_addr;
4025b81b6b3SRodney W. Grimes 	int foo, offset, addr, i;
4035b81b6b3SRodney W. Grimes 	extern char kstack[];
4045b81b6b3SRodney W. Grimes 	extern int mvesp();
4055b81b6b3SRodney W. Grimes 
4065b81b6b3SRodney W. Grimes 	/*
4075b81b6b3SRodney W. Grimes 	 * Copy pcb and stack from proc p1 to p2.
4085b81b6b3SRodney W. Grimes 	 * We do this as cheaply as possible, copying only the active
4095b81b6b3SRodney W. Grimes 	 * part of the stack.  The stack and pcb need to agree;
4105b81b6b3SRodney W. Grimes 	 * this is tricky, as the final pcb is constructed by savectx,
4115b81b6b3SRodney W. Grimes 	 * but its frame isn't yet on the stack when the stack is copied.
4125b81b6b3SRodney W. Grimes 	 * swtch compensates for this when the child eventually runs.
4135b81b6b3SRodney W. Grimes 	 * This should be done differently, with a single call
4145b81b6b3SRodney W. Grimes 	 * that copies and updates the pcb+stack,
4155b81b6b3SRodney W. Grimes 	 * replacing the bcopy and savectx.
4165b81b6b3SRodney W. Grimes 	 */
4175b81b6b3SRodney W. Grimes 	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
4185b81b6b3SRodney W. Grimes 	offset = mvesp() - (int)kstack;
4195b81b6b3SRodney W. Grimes 	bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
4205b81b6b3SRodney W. Grimes 	    (unsigned) ctob(UPAGES) - offset);
4215b81b6b3SRodney W. Grimes 	p2->p_regs = p1->p_regs;
4225b81b6b3SRodney W. Grimes 
4235b81b6b3SRodney W. Grimes 	/*
4245b81b6b3SRodney W. Grimes 	 * Wire top of address space of child to it's kstack.
4255b81b6b3SRodney W. Grimes 	 * First, fault in a page of pte's to map it.
4265b81b6b3SRodney W. Grimes 	 */
4277f8cb368SDavid Greenman #if 0
4285b81b6b3SRodney W. Grimes         addr = trunc_page((u_int)vtopte(kstack));
4295b81b6b3SRodney W. Grimes 	vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
4305b81b6b3SRodney W. Grimes 	for (i=0; i < UPAGES; i++)
4317f8cb368SDavid Greenman 		pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
43226931201SDavid Greenman 			   pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG),
43326931201SDavid Greenman 			   /*
43426931201SDavid Greenman 			    * The user area has to be mapped writable because
43526931201SDavid Greenman 			    * it contains the kernel stack (when CR0_WP is on
43626931201SDavid Greenman 			    * on a 486 there is no user-read/kernel-write
43726931201SDavid Greenman 			    * mode).  It is protected from user mode access
43826931201SDavid Greenman 			    * by the segment limits.
43926931201SDavid Greenman 			    */
44026931201SDavid Greenman 			   VM_PROT_READ|VM_PROT_WRITE, TRUE);
4417f8cb368SDavid Greenman #endif
4425b81b6b3SRodney W. Grimes 	pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
4435b81b6b3SRodney W. Grimes 
4445b81b6b3SRodney W. Grimes 	/*
4455b81b6b3SRodney W. Grimes 	 *
4465b81b6b3SRodney W. Grimes 	 * Arrange for a non-local goto when the new process
4475b81b6b3SRodney W. Grimes 	 * is started, to resume here, returning nonzero from setjmp.
4485b81b6b3SRodney W. Grimes 	 */
4495b81b6b3SRodney W. Grimes 	if (savectx(up, 1)) {
4505b81b6b3SRodney W. Grimes 		/*
4515b81b6b3SRodney W. Grimes 		 * Return 1 in child.
4525b81b6b3SRodney W. Grimes 		 */
4535b81b6b3SRodney W. Grimes 		return (1);
4545b81b6b3SRodney W. Grimes 	}
4555b81b6b3SRodney W. Grimes 	return (0);
4565b81b6b3SRodney W. Grimes }
4575b81b6b3SRodney W. Grimes 
4585b81b6b3SRodney W. Grimes #ifdef notyet
4595b81b6b3SRodney W. Grimes /*
4605b81b6b3SRodney W. Grimes  * cpu_exit is called as the last action during exit.
4615b81b6b3SRodney W. Grimes  *
4625b81b6b3SRodney W. Grimes  * We change to an inactive address space and a "safe" stack,
4635b81b6b3SRodney W. Grimes  * passing thru an argument to the new stack. Now, safely isolated
4645b81b6b3SRodney W. Grimes  * from the resources we're shedding, we release the address space
4655b81b6b3SRodney W. Grimes  * and any remaining machine-dependent resources, including the
4665b81b6b3SRodney W. Grimes  * memory for the user structure and kernel stack.
4675b81b6b3SRodney W. Grimes  *
4685b81b6b3SRodney W. Grimes  * Next, we assign a dummy context to be written over by swtch,
4695b81b6b3SRodney W. Grimes  * calling it to send this process off to oblivion.
4705b81b6b3SRodney W. Grimes  * [The nullpcb allows us to minimize cost in swtch() by not having
4715b81b6b3SRodney W. Grimes  * a special case].
4725b81b6b3SRodney W. Grimes  */
4735b81b6b3SRodney W. Grimes struct proc *swtch_to_inactive();
47475124a8bSPaul Richards volatile void
4755b81b6b3SRodney W. Grimes cpu_exit(p)
4765b81b6b3SRodney W. Grimes 	register struct proc *p;
4775b81b6b3SRodney W. Grimes {
4785b81b6b3SRodney W. Grimes 	static struct pcb nullpcb;	/* pcb to overwrite on last swtch */
4795b81b6b3SRodney W. Grimes 
480960173b9SRodney W. Grimes #if NNPX > 0
4815b81b6b3SRodney W. Grimes 	npxexit(p);
482960173b9SRodney W. Grimes #endif	/* NNPX */
4835b81b6b3SRodney W. Grimes 
4845b81b6b3SRodney W. Grimes 	/* move to inactive space and stack, passing arg accross */
4855b81b6b3SRodney W. Grimes 	p = swtch_to_inactive(p);
4865b81b6b3SRodney W. Grimes 
4875b81b6b3SRodney W. Grimes 	/* drop per-process resources */
4885b81b6b3SRodney W. Grimes 	vmspace_free(p->p_vmspace);
4895b81b6b3SRodney W. Grimes 	kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
4905b81b6b3SRodney W. Grimes 
4915b81b6b3SRodney W. Grimes 	p->p_addr = (struct user *) &nullpcb;
4925b81b6b3SRodney W. Grimes 	splclock();
4935b81b6b3SRodney W. Grimes 	swtch();
4945b81b6b3SRodney W. Grimes 	/* NOTREACHED */
4955b81b6b3SRodney W. Grimes }
4965b81b6b3SRodney W. Grimes #else
4977c2b54e8SNate Williams void
4985b81b6b3SRodney W. Grimes cpu_exit(p)
4995b81b6b3SRodney W. Grimes 	register struct proc *p;
5005b81b6b3SRodney W. Grimes {
5015b81b6b3SRodney W. Grimes 
502960173b9SRodney W. Grimes #if NNPX > 0
5035b81b6b3SRodney W. Grimes 	npxexit(p);
504960173b9SRodney W. Grimes #endif	/* NNPX */
5055b81b6b3SRodney W. Grimes 	splclock();
5067f8cb368SDavid Greenman 	curproc = 0;
5075b81b6b3SRodney W. Grimes 	swtch();
5087c2b54e8SNate Williams 	/*
5097c2b54e8SNate Williams 	 * This is to shutup the compiler, and if swtch() failed I suppose
5107c2b54e8SNate Williams 	 * this would be a good thing.  This keeps gcc happy because panic
5117c2b54e8SNate Williams 	 * is a volatile void function as well.
5127c2b54e8SNate Williams 	 */
5137c2b54e8SNate Williams 	panic("cpu_exit");
5145b81b6b3SRodney W. Grimes }
5155b81b6b3SRodney W. Grimes 
516381fe1aaSGarrett Wollman void
5177f8cb368SDavid Greenman cpu_wait(p) struct proc *p; {
5187f8cb368SDavid Greenman /*	extern vm_map_t upages_map; */
5197f8cb368SDavid Greenman 	extern char kstack[];
5205b81b6b3SRodney W. Grimes 
5215b81b6b3SRodney W. Grimes 	/* drop per-process resources */
5227f8cb368SDavid Greenman  	pmap_remove(vm_map_pmap(kernel_map), (vm_offset_t) p->p_addr,
5237f8cb368SDavid Greenman 		((vm_offset_t) p->p_addr) + ctob(UPAGES));
5245b81b6b3SRodney W. Grimes 	kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
5257f8cb368SDavid Greenman 	vmspace_free(p->p_vmspace);
5265b81b6b3SRodney W. Grimes }
5275b81b6b3SRodney W. Grimes #endif
5285b81b6b3SRodney W. Grimes 
5295b81b6b3SRodney W. Grimes /*
5305b81b6b3SRodney W. Grimes  * Set a red zone in the kernel stack after the u. area.
5315b81b6b3SRodney W. Grimes  */
532381fe1aaSGarrett Wollman void
5335b81b6b3SRodney W. Grimes setredzone(pte, vaddr)
5345b81b6b3SRodney W. Grimes 	u_short *pte;
5355b81b6b3SRodney W. Grimes 	caddr_t vaddr;
5365b81b6b3SRodney W. Grimes {
5375b81b6b3SRodney W. Grimes /* eventually do this by setting up an expand-down stack segment
5385b81b6b3SRodney W. Grimes    for ss0: selector, allowing stack access down to top of u.
5395b81b6b3SRodney W. Grimes    this means though that protection violations need to be handled
5405b81b6b3SRodney W. Grimes    thru a double fault exception that must do an integral task
5415b81b6b3SRodney W. Grimes    switch to a known good context, within which a dump can be
5425b81b6b3SRodney W. Grimes    taken. a sensible scheme might be to save the initial context
5435b81b6b3SRodney W. Grimes    used by sched (that has physical memory mapped 1:1 at bottom)
5445b81b6b3SRodney W. Grimes    and take the dump while still in mapped mode */
5455b81b6b3SRodney W. Grimes }
5465b81b6b3SRodney W. Grimes 
5475b81b6b3SRodney W. Grimes /*
5485b81b6b3SRodney W. Grimes  * Convert kernel VA to physical address
5495b81b6b3SRodney W. Grimes  */
550aaf08d94SGarrett Wollman u_long
5517f8cb368SDavid Greenman kvtop(void *addr)
5525b81b6b3SRodney W. Grimes {
5535b81b6b3SRodney W. Grimes 	vm_offset_t va;
5545b81b6b3SRodney W. Grimes 
5555b81b6b3SRodney W. Grimes 	va = pmap_extract(kernel_pmap, (vm_offset_t)addr);
5565b81b6b3SRodney W. Grimes 	if (va == 0)
5575b81b6b3SRodney W. Grimes 		panic("kvtop: zero page frame");
5587f8cb368SDavid Greenman 	return((int)va);
5595b81b6b3SRodney W. Grimes }
5605b81b6b3SRodney W. Grimes 
5615b81b6b3SRodney W. Grimes extern vm_map_t phys_map;
5625b81b6b3SRodney W. Grimes 
5635b81b6b3SRodney W. Grimes /*
5645b81b6b3SRodney W. Grimes  * Map an IO request into kernel virtual address space.  Requests fall into
5655b81b6b3SRodney W. Grimes  * one of five catagories:
5665b81b6b3SRodney W. Grimes  *
5675b81b6b3SRodney W. Grimes  *	B_PHYS|B_UAREA:	User u-area swap.
5685b81b6b3SRodney W. Grimes  *			Address is relative to start of u-area (p_addr).
5695b81b6b3SRodney W. Grimes  *	B_PHYS|B_PAGET:	User page table swap.
5705b81b6b3SRodney W. Grimes  *			Address is a kernel VA in usrpt (Usrptmap).
5715b81b6b3SRodney W. Grimes  *	B_PHYS|B_DIRTY:	Dirty page push.
5725b81b6b3SRodney W. Grimes  *			Address is a VA in proc2's address space.
5735b81b6b3SRodney W. Grimes  *	B_PHYS|B_PGIN:	Kernel pagein of user pages.
5745b81b6b3SRodney W. Grimes  *			Address is VA in user's address space.
5755b81b6b3SRodney W. Grimes  *	B_PHYS:		User "raw" IO request.
5765b81b6b3SRodney W. Grimes  *			Address is VA in user's address space.
5775b81b6b3SRodney W. Grimes  *
5785b81b6b3SRodney W. Grimes  * All requests are (re)mapped into kernel VA space via the useriomap
5795b81b6b3SRodney W. Grimes  * (a name with only slightly more meaning than "kernelmap")
5805b81b6b3SRodney W. Grimes  */
581381fe1aaSGarrett Wollman void
5825b81b6b3SRodney W. Grimes vmapbuf(bp)
5835b81b6b3SRodney W. Grimes 	register struct buf *bp;
5845b81b6b3SRodney W. Grimes {
5855b81b6b3SRodney W. Grimes 	register int npf;
5865b81b6b3SRodney W. Grimes 	register caddr_t addr;
5875b81b6b3SRodney W. Grimes 	register long flags = bp->b_flags;
5885b81b6b3SRodney W. Grimes 	struct proc *p;
5895b81b6b3SRodney W. Grimes 	int off;
5905b81b6b3SRodney W. Grimes 	vm_offset_t kva;
5915b81b6b3SRodney W. Grimes 	register vm_offset_t pa;
5925b81b6b3SRodney W. Grimes 
5935b81b6b3SRodney W. Grimes 	if ((flags & B_PHYS) == 0)
5945b81b6b3SRodney W. Grimes 		panic("vmapbuf");
5955b81b6b3SRodney W. Grimes 	addr = bp->b_saveaddr = bp->b_un.b_addr;
5965b81b6b3SRodney W. Grimes 	off = (int)addr & PGOFSET;
5975b81b6b3SRodney W. Grimes 	p = bp->b_proc;
5985b81b6b3SRodney W. Grimes 	npf = btoc(round_page(bp->b_bcount + off));
5995b81b6b3SRodney W. Grimes 	kva = kmem_alloc_wait(phys_map, ctob(npf));
6005b81b6b3SRodney W. Grimes 	bp->b_un.b_addr = (caddr_t) (kva + off);
6015b81b6b3SRodney W. Grimes 	while (npf--) {
6025b81b6b3SRodney W. Grimes 		pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
6035b81b6b3SRodney W. Grimes 		if (pa == 0)
6045b81b6b3SRodney W. Grimes 			panic("vmapbuf: null page frame");
6055b81b6b3SRodney W. Grimes 		pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
6065b81b6b3SRodney W. Grimes 			   VM_PROT_READ|VM_PROT_WRITE, TRUE);
6075b81b6b3SRodney W. Grimes 		addr += PAGE_SIZE;
6085b81b6b3SRodney W. Grimes 		kva += PAGE_SIZE;
6095b81b6b3SRodney W. Grimes 	}
6105b81b6b3SRodney W. Grimes }
6115b81b6b3SRodney W. Grimes 
6125b81b6b3SRodney W. Grimes /*
6135b81b6b3SRodney W. Grimes  * Free the io map PTEs associated with this IO operation.
6145b81b6b3SRodney W. Grimes  * We also invalidate the TLB entries and restore the original b_addr.
6155b81b6b3SRodney W. Grimes  */
616381fe1aaSGarrett Wollman void
6175b81b6b3SRodney W. Grimes vunmapbuf(bp)
6185b81b6b3SRodney W. Grimes 	register struct buf *bp;
6195b81b6b3SRodney W. Grimes {
6205b81b6b3SRodney W. Grimes 	register int npf;
6215b81b6b3SRodney W. Grimes 	register caddr_t addr = bp->b_un.b_addr;
6225b81b6b3SRodney W. Grimes 	vm_offset_t kva;
6235b81b6b3SRodney W. Grimes 
6245b81b6b3SRodney W. Grimes 	if ((bp->b_flags & B_PHYS) == 0)
6255b81b6b3SRodney W. Grimes 		panic("vunmapbuf");
6265b81b6b3SRodney W. Grimes 	npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
6275b81b6b3SRodney W. Grimes 	kva = (vm_offset_t)((int)addr & ~PGOFSET);
6285b81b6b3SRodney W. Grimes 	kmem_free_wakeup(phys_map, kva, ctob(npf));
6295b81b6b3SRodney W. Grimes 	bp->b_un.b_addr = bp->b_saveaddr;
6305b81b6b3SRodney W. Grimes 	bp->b_saveaddr = NULL;
6315b81b6b3SRodney W. Grimes }
6325b81b6b3SRodney W. Grimes 
6335b81b6b3SRodney W. Grimes /*
6345b81b6b3SRodney W. Grimes  * Force reset the processor by invalidating the entire address space!
6355b81b6b3SRodney W. Grimes  */
6367f8cb368SDavid Greenman void
6375b81b6b3SRodney W. Grimes cpu_reset() {
6385b81b6b3SRodney W. Grimes 
6395b81b6b3SRodney W. Grimes 	/* force a shutdown by unmapping entire address space ! */
6405b81b6b3SRodney W. Grimes 	bzero((caddr_t) PTD, NBPG);
6415b81b6b3SRodney W. Grimes 
6425b81b6b3SRodney W. Grimes 	/* "good night, sweet prince .... <THUNK!>" */
6435b81b6b3SRodney W. Grimes 	tlbflush();
6445b81b6b3SRodney W. Grimes 	/* NOTREACHED */
6457f8cb368SDavid Greenman 	while(1);
6465b81b6b3SRodney W. Grimes }
647b9d60b3fSDavid Greenman 
648b9d60b3fSDavid Greenman /*
649b9d60b3fSDavid Greenman  * Grow the user stack to allow for 'sp'. This version grows the stack in
65029360eb0SDavid Greenman  *	chunks of SGROWSIZ.
651b9d60b3fSDavid Greenman  */
652b9d60b3fSDavid Greenman int
653b9d60b3fSDavid Greenman grow(p, sp)
654b9d60b3fSDavid Greenman 	struct proc *p;
655b9d60b3fSDavid Greenman 	int sp;
656b9d60b3fSDavid Greenman {
657b9d60b3fSDavid Greenman 	unsigned int nss;
658b9d60b3fSDavid Greenman 	caddr_t v;
659b9d60b3fSDavid Greenman 	struct vmspace *vm = p->p_vmspace;
660b9d60b3fSDavid Greenman 
661b9d60b3fSDavid Greenman 	if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
662b9d60b3fSDavid Greenman 	    return (1);
663b9d60b3fSDavid Greenman 
664b9d60b3fSDavid Greenman 	nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
665b9d60b3fSDavid Greenman 
666b9d60b3fSDavid Greenman 	if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
667b9d60b3fSDavid Greenman 		return (0);
668b9d60b3fSDavid Greenman 
669b9d60b3fSDavid Greenman 	if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
67029360eb0SDavid Greenman 	    SGROWSIZ) < nss) {
671b9d60b3fSDavid Greenman 		int grow_amount;
672b9d60b3fSDavid Greenman 		/*
673b9d60b3fSDavid Greenman 		 * If necessary, grow the VM that the stack occupies
674b9d60b3fSDavid Greenman 		 * to allow for the rlimit. This allows us to not have
675b9d60b3fSDavid Greenman 		 * to allocate all of the VM up-front in execve (which
676b9d60b3fSDavid Greenman 		 * is expensive).
677b9d60b3fSDavid Greenman 		 * Grow the VM by the amount requested rounded up to
67829360eb0SDavid Greenman 		 * the nearest SGROWSIZ to provide for some hysteresis.
679b9d60b3fSDavid Greenman 		 */
68029360eb0SDavid Greenman 		grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
681b9d60b3fSDavid Greenman 		v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
68229360eb0SDavid Greenman 		    SGROWSIZ) - grow_amount;
683b9d60b3fSDavid Greenman 		/*
68429360eb0SDavid Greenman 		 * If there isn't enough room to extend by SGROWSIZ, then
685b9d60b3fSDavid Greenman 		 * just extend to the maximum size
686b9d60b3fSDavid Greenman 		 */
687b9d60b3fSDavid Greenman 		if (v < vm->vm_maxsaddr) {
688b9d60b3fSDavid Greenman 			v = vm->vm_maxsaddr;
689b9d60b3fSDavid Greenman 			grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
690b9d60b3fSDavid Greenman 		}
691b9d60b3fSDavid Greenman 		if (vm_allocate(&vm->vm_map, (vm_offset_t *)&v,
692b9d60b3fSDavid Greenman 		    grow_amount, FALSE) != KERN_SUCCESS) {
693b9d60b3fSDavid Greenman 			return (0);
694b9d60b3fSDavid Greenman 		}
695b9d60b3fSDavid Greenman 		vm->vm_ssize += grow_amount >> PAGE_SHIFT;
696b9d60b3fSDavid Greenman 	}
697b9d60b3fSDavid Greenman 
698b9d60b3fSDavid Greenman 	return (1);
699b9d60b3fSDavid Greenman }
700