xref: /original-bsd/sys/i386/i386/vm_machdep.c (revision e59fb703)
1 /*-
2  * Copyright (c) 1982, 1986 The Regents of the University of California.
3  * Copyright (c) 1989, 1990 William Jolitz
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department, and William Jolitz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
39  */
40 
41 /*
42  *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
43  */
44 
45 #include "param.h"
46 #include "systm.h"
47 #include "proc.h"
48 #include "malloc.h"
49 #include "buf.h"
50 #include "user.h"
51 
52 #include "../include/cpu.h"
53 
54 #include "vm/vm.h"
55 #include "vm/vm_kern.h"
56 
57 /*
58  * Finish a fork operation, with process p2 nearly set up.
59  * Copy and update the kernel stack and pcb, making the child
60  * ready to run, and marking it so that it can return differently
61  * than the parent.  Returns 1 in the child process, 0 in the parent.
62  * We currently double-map the user area so that the stack is at the same
63  * address in each process; in the future we will probably relocate
64  * the frame pointers on the stack after copying.
65  */
66 cpu_fork(p1, p2)
67 	register struct proc *p1, *p2;
68 {
69 	register struct user *up = p2->p_addr;
70 	int foo, offset, addr, i;
71 	extern char kstack[];
72 	extern int mvesp();
73 
74 	/*
75 	 * Copy pcb and stack from proc p1 to p2.
76 	 * We do this as cheaply as possible, copying only the active
77 	 * part of the stack.  The stack and pcb need to agree;
78 	 * this is tricky, as the final pcb is constructed by savectx,
79 	 * but its frame isn't yet on the stack when the stack is copied.
80 	 * swtch compensates for this when the child eventually runs.
81 	 * This should be done differently, with a single call
82 	 * that copies and updates the pcb+stack,
83 	 * replacing the bcopy and savectx.
84 	 */
85 	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
86 	offset = mvesp() - (int)kstack;
87 	bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
88 	    (unsigned) ctob(UPAGES) - offset);
89 	p2->p_regs = p1->p_regs;
90 
91 	/*
92 	 * Wire top of address space of child to it's u.
93 	 * First, fault in a page of pte's to map it.
94 	 */
95         addr = trunc_page((u_int)vtopte(kstack));
96 	(void)vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
97 	for (i=0; i < UPAGES; i++)
98 		pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
99 			pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG),
100 			VM_PROT_READ, 1);
101 	pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
102 
103 	/*
104 	 *
105 	 * Arrange for a non-local goto when the new process
106 	 * is started, to resume here, returning nonzero from setjmp.
107 	 */
108 	if (savectx(up, 1)) {
109 		/*
110 		 * Return 1 in child.
111 		 */
112 		return (1);
113 	}
114 	return (0);
115 }
116 
117 extern struct proc *npxproc;
118 
119 #ifdef notyet
120 /*
121  * cpu_exit is called as the last action during exit.
122  *
123  * We change to an inactive address space and a "safe" stack,
124  * passing thru an argument to the new stack. Now, safely isolated
125  * from the resources we're shedding, we release the address space
126  * and any remaining machine-dependent resources, including the
127  * memory for the user structure and kernel stack.
128  *
129  * Next, we assign a dummy context to be written over by swtch,
130  * calling it to send this process off to oblivion.
131  * [The nullpcb allows us to minimize cost in swtch() by not having
132  * a special case].
133  */
134 struct proc *swtch_to_inactive();
135 cpu_exit(p)
136 	register struct proc *p;
137 {
138 	static struct pcb nullpcb;	/* pcb to overwrite on last swtch */
139 
140 	/* free cporcessor (if we have it) */
141 	if( p == npxproc) npxproc =0;
142 
143 	/* move to inactive space and stack, passing arg accross */
144 	p = swtch_to_inactive(p);
145 
146 	/* drop per-process resources */
147 	vmspace_free(p->p_vmspace);
148 	kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
149 
150 	p->p_addr = (struct user *) &nullpcb;
151 	swtch();
152 	/* NOTREACHED */
153 }
154 #else
155 cpu_exit(p)
156 	register struct proc *p;
157 {
158 
159 	/* free coprocessor (if we have it) */
160 	if( p == npxproc) npxproc =0;
161 
162 	curproc = p;
163 	swtch();
164 }
165 
166 cpu_wait(p) struct proc *p; {
167 
168 	/* drop per-process resources */
169 	vmspace_free(p->p_vmspace);
170 	kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
171 }
172 #endif
173 
174 /*
175  * Set a red zone in the kernel stack after the u. area.
176  */
177 setredzone(pte, vaddr)
178 	u_short *pte;
179 	caddr_t vaddr;
180 {
181 /* eventually do this by setting up an expand-down stack segment
182    for ss0: selector, allowing stack access down to top of u.
183    this means though that protection violations need to be handled
184    thru a double fault exception that must do an integral task
185    switch to a known good context, within which a dump can be
186    taken. a sensible scheme might be to save the initial context
187    used by sched (that has physical memory mapped 1:1 at bottom)
188    and take the dump while still in mapped mode */
189 }
190 
191 /*
192  * Move pages from one kernel virtual address to another.
193  * Both addresses are assumed to reside in the Sysmap,
194  * and size must be a multiple of CLSIZE.
195  */
196 pagemove(from, to, size)
197 	register caddr_t from, to;
198 	int size;
199 {
200 	register struct pte *fpte, *tpte;
201 
202 	if (size % CLBYTES)
203 		panic("pagemove");
204 	fpte = kvtopte(from);
205 	tpte = kvtopte(to);
206 	while (size > 0) {
207 		*tpte++ = *fpte;
208 		*(int *)fpte++ = 0;
209 		from += NBPG;
210 		to += NBPG;
211 		size -= NBPG;
212 	}
213 	tlbflush();
214 }
215 
216 /*
217  * Convert kernel VA to physical address
218  */
219 kvtop(addr)
220 	register caddr_t addr;
221 {
222 	vm_offset_t va;
223 
224 	va = pmap_extract(kernel_pmap, (vm_offset_t)addr);
225 	if (va == 0)
226 		panic("kvtop: zero page frame");
227 	return((int)va);
228 }
229 
230 #ifdef notdef
231 /*
232  * The probe[rw] routines should probably be redone in assembler
233  * for efficiency.
234  */
235 prober(addr)
236 	register u_int addr;
237 {
238 	register int page;
239 	register struct proc *p;
240 
241 	if (addr >= USRSTACK)
242 		return(0);
243 	p = u.u_procp;
244 	page = btop(addr);
245 	if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
246 		return(1);
247 	return(0);
248 }
249 
250 probew(addr)
251 	register u_int addr;
252 {
253 	register int page;
254 	register struct proc *p;
255 
256 	if (addr >= USRSTACK)
257 		return(0);
258 	p = u.u_procp;
259 	page = btop(addr);
260 	if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
261 		return((*(int *)vtopte(p, page) & PG_PROT) == PG_UW);
262 	return(0);
263 }
264 
265 /*
266  * NB: assumes a physically contiguous kernel page table
267  *     (makes life a LOT simpler).
268  */
269 kernacc(addr, count, rw)
270 	register u_int addr;
271 	int count, rw;
272 {
273 	register struct pde *pde;
274 	register struct pte *pte;
275 	register int ix, cnt;
276 	extern long Syssize;
277 
278 	if (count <= 0)
279 		return(0);
280 	pde = (struct pde *)((u_int)u.u_procp->p_p0br + u.u_procp->p_szpt * NBPG);
281 	ix = (addr & PD_MASK) >> PD_SHIFT;
282 	cnt = ((addr + count + (1 << PD_SHIFT) - 1) & PD_MASK) >> PD_SHIFT;
283 	cnt -= ix;
284 	for (pde += ix; cnt; cnt--, pde++)
285 		if (pde->pd_v == 0)
286 			return(0);
287 	ix = btop(addr-0xfe000000);
288 	cnt = btop(addr-0xfe000000+count+NBPG-1);
289 	if (cnt > (int)&Syssize)
290 		return(0);
291 	cnt -= ix;
292 	for (pte = &Sysmap[ix]; cnt; cnt--, pte++)
293 		if (pte->pg_v == 0 /*|| (rw == B_WRITE && pte->pg_prot == 1)*/)
294 			return(0);
295 	return(1);
296 }
297 
298 useracc(addr, count, rw)
299 	register u_int addr;
300 	int count, rw;
301 {
302 	register int (*func)();
303 	register u_int addr2;
304 	extern int prober(), probew();
305 
306 	if (count <= 0)
307 		return(0);
308 	addr2 = addr;
309 	addr += count;
310 	func = (rw == B_READ) ? prober : probew;
311 	do {
312 		if ((*func)(addr2) == 0)
313 			return(0);
314 		addr2 = (addr2 + NBPG) & ~PGOFSET;
315 	} while (addr2 < addr);
316 	return(1);
317 }
318 #endif
319 
320 extern vm_map_t phys_map;
321 
322 /*
323  * Map an IO request into kernel virtual address space.  Requests fall into
324  * one of five catagories:
325  *
326  *	B_PHYS|B_UAREA:	User u-area swap.
327  *			Address is relative to start of u-area (p_addr).
328  *	B_PHYS|B_PAGET:	User page table swap.
329  *			Address is a kernel VA in usrpt (Usrptmap).
330  *	B_PHYS|B_DIRTY:	Dirty page push.
331  *			Address is a VA in proc2's address space.
332  *	B_PHYS|B_PGIN:	Kernel pagein of user pages.
333  *			Address is VA in user's address space.
334  *	B_PHYS:		User "raw" IO request.
335  *			Address is VA in user's address space.
336  *
337  * All requests are (re)mapped into kernel VA space via the useriomap
338  * (a name with only slightly more meaning than "kernelmap")
339  */
340 vmapbuf(bp)
341 	register struct buf *bp;
342 {
343 	register int npf;
344 	register caddr_t addr;
345 	register long flags = bp->b_flags;
346 	struct proc *p;
347 	int off;
348 	vm_offset_t kva;
349 	register vm_offset_t pa;
350 
351 	if ((flags & B_PHYS) == 0)
352 		panic("vmapbuf");
353 	addr = bp->b_saveaddr = bp->b_un.b_addr;
354 	off = (int)addr & PGOFSET;
355 	p = bp->b_proc;
356 	npf = btoc(round_page(bp->b_bcount + off));
357 	kva = kmem_alloc_wait(phys_map, ctob(npf));
358 	bp->b_un.b_addr = (caddr_t) (kva + off);
359 	while (npf--) {
360 		pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
361 		if (pa == 0)
362 			panic("vmapbuf: null page frame");
363 		pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
364 			   VM_PROT_READ|VM_PROT_WRITE, TRUE);
365 		addr += PAGE_SIZE;
366 		kva += PAGE_SIZE;
367 	}
368 }
369 
370 /*
371  * Free the io map PTEs associated with this IO operation.
372  * We also invalidate the TLB entries and restore the original b_addr.
373  */
374 vunmapbuf(bp)
375 	register struct buf *bp;
376 {
377 	register int npf;
378 	register caddr_t addr = bp->b_un.b_addr;
379 	vm_offset_t kva;
380 
381 	if ((bp->b_flags & B_PHYS) == 0)
382 		panic("vunmapbuf");
383 	npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
384 	kva = (vm_offset_t)((int)addr & ~PGOFSET);
385 	kmem_free_wakeup(phys_map, kva, ctob(npf));
386 	bp->b_un.b_addr = bp->b_saveaddr;
387 	bp->b_saveaddr = NULL;
388 }
389