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