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