|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)vm_proc.c 7.11 (Berkeley) 6/30/90
21: */
22:
23: #include "param.h"
24: #include "systm.h"
25: #include "user.h"
26: #include "proc.h"
27: #include "map.h"
28: #include "cmap.h"
29: #include "text.h"
30: #include "vm.h"
31:
32: #include "machine/pte.h"
33: #include "machine/mtpr.h"
34: #include "machine/cpu.h"
35:
36: /*
37: * Get virtual memory resources for a new process.
38: * Called after page tables are allocated, but before they
39: * are initialized, we initialize the memory management registers,
40: * and then expand the page tables for the data and stack segments
41: * creating zero fill pte's there. Text pte's are set up elsewhere.
42: *
43: * SHOULD FREE EXTRA PAGE TABLE PAGES HERE OR SOMEWHERE.
44: */
45: vgetvm(ts, ds, ss)
46: segsz_t ts, ds, ss;
47: {
48:
49: #if defined(vax)
50: u.u_pcb.pcb_p0lr = AST_NONE;
51: setp0lr(ts);
52: setp1lr(P1PAGES - HIGHPAGES);
53: #endif
54: #if defined(tahoe)
55: setp0lr(ts);
56: setp1lr(0);
57: setp2lr(P2PAGES - HIGHPAGES);
58: #endif
59: #if defined(hp300) || defined(i386)
60: setp0lr(LOWPAGES + ts);
61: setp1lr(P1PAGES - HIGHPAGES);
62: #endif
63: u.u_procp->p_tsize = ts;
64: u.u_tsize = ts;
65: expand((int)ss, 1);
66: expand((int)ds, 0);
67: }
68:
69: /*
70: * Release the virtual memory resources (memory
71: * pages, and swap area) associated with the current process.
72: * Caller must not be swappable. Used at exit or execl.
73: */
74: vrelvm()
75: {
76: register struct proc *p = u.u_procp;
77:
78: /*
79: * Release memory; text first, then data and stack pages.
80: */
81: xfree();
82: p->p_rssize -= vmemfree(dptopte(p, 0), (int)p->p_dsize);
83: p->p_rssize -= vmemfree(sptopte(p, p->p_ssize - 1), (int)p->p_ssize);
84: if (p->p_rssize != 0)
85: panic("vrelvm rss");
86: /*
87: * Wait for all page outs to complete, then
88: * release swap space.
89: */
90: p->p_swrss = 0;
91: while (p->p_poip)
92: sleep((caddr_t)&p->p_poip, PSWP+1);
93: (void) vsexpand((segsz_t)0, &u.u_dmap, 1);
94: (void) vsexpand((segsz_t)0, &u.u_smap, 1);
95: p->p_tsize = 0;
96: p->p_dsize = 0;
97: p->p_ssize = 0;
98: u.u_tsize = 0;
99: u.u_dsize = 0;
100: u.u_ssize = 0;
101: }
102:
103: /*
104: * Pass virtual memory resources from p to q.
105: * P's u. area is up, q's is uq. Used internally
106: * when starting/ending a vfork().
107: */
108: vpassvm(p, q, up, uq, umap)
109: register struct proc *p, *q;
110: register struct user *up, *uq;
111: struct pte *umap;
112: {
113:
114: /*
115: * Pass fields related to vm sizes.
116: */
117: uq->u_tsize = q->p_tsize = p->p_tsize; up->u_tsize = p->p_tsize = 0;
118: uq->u_dsize = q->p_dsize = p->p_dsize; up->u_dsize = p->p_dsize = 0;
119: uq->u_ssize = q->p_ssize = p->p_ssize; up->u_ssize = p->p_ssize = 0;
120: q->p_mmsize = p->p_mmsize; p->p_mmsize = 0;
121:
122: /*
123: * Pass proc table paging statistics.
124: */
125: q->p_swrss = p->p_swrss; p->p_swrss = 0;
126: q->p_rssize = p->p_rssize; p->p_rssize = 0;
127: q->p_poip = p->p_poip; p->p_poip = 0;
128:
129: /*
130: * Relink text segment.
131: */
132: q->p_textp = p->p_textp;
133: xrepl(p, q);
134: p->p_textp = 0;
135:
136: /*
137: * Pass swap space maps.
138: */
139: uq->u_dmap = up->u_dmap; up->u_dmap = zdmap;
140: uq->u_smap = up->u_smap; up->u_smap = zdmap;
141:
142: /*
143: * Pass u. paging statistics.
144: */
145: uq->u_outime = up->u_outime; up->u_outime = 0;
146: uq->u_ru = up->u_ru;
147: bzero((caddr_t)&up->u_ru, sizeof (struct rusage));
148: uq->u_cru = up->u_cru;
149: bzero((caddr_t)&up->u_cru, sizeof (struct rusage));
150:
151: /*
152: * And finally, pass the page tables themselves.
153: * On return we are running on the other set of
154: * page tables, but still with the same u. area.
155: */
156: vpasspt(p, q, up, uq, umap);
157: #ifdef MAPMEM
158: /*
159: * Exchange mapped memory resources.
160: */
161: if (up->u_mmap)
162: mmvfork(up, uq);
163: #endif
164: }
165:
166: /*
167: * Change the size of the data+stack regions of the process.
168: * If the size is shrinking, it's easy-- just release virtual memory.
169: * If it's growing, initalize new page table entries as
170: * 'zero fill on demand' pages.
171: */
172: expand(change, region)
173: int change, region;
174: {
175: register struct proc *p;
176: #if defined(vax)
177: register struct pte *base, *p0, *p1;
178: int p0lr, p1lr;
179: #endif
180: #if defined(tahoe)
181: register struct pte *base, *p0, *p2;
182: int p0lr, p2lr;
183: #endif
184: #if defined(hp300) || defined(i386)
185: register struct pte *base;
186: int p0lr, p1lr;
187: #endif
188: struct pte proto;
189: struct pte *base0;
190: segsz_t ods, oss;
191: int size;
192: u_int v;
193:
194: p = u.u_procp;
195: if (change == 0)
196: return;
197: if (change % CLSIZE)
198: panic("expand");
199:
200: #ifdef PGINPROF
201: vmsizmon();
202: #endif
203:
204: /*
205: * Update the sizes to reflect the change. Note that we may
206: * swap as a result of a ptexpand, but this will work, because
207: * the routines which swap out will get the current text and data
208: * sizes from the arguments they are passed, and when the process
209: * resumes the lengths in the proc structure are used to
210: * build the new page tables.
211: */
212: ods = u.u_dsize;
213: oss = u.u_ssize;
214: if (region == 0) {
215: v = dptov(p, change > 0 ? p->p_dsize : p->p_dsize+change);
216: p->p_dsize += change;
217: u.u_dsize += change;
218: } else {
219: v = sptov(p, change > 0 ? p->p_ssize-1+change : p->p_ssize-1);
220: p->p_ssize += change;
221: u.u_ssize += change;
222: }
223:
224: /*
225: * Compute the end of the text+data regions and the beginning
226: * of the stack region in the page tables,
227: * and expand the page tables if necessary.
228: */
229: #if defined(vax)
230: p0 = u.u_pcb.pcb_p0br + (u.u_pcb.pcb_p0lr&~AST_CLR);
231: p1 = u.u_pcb.pcb_p1br + (u.u_pcb.pcb_p1lr&~PME_CLR);
232: if (change > p1 - p0)
233: ptexpand(clrnd(ctopt(change - (p1 - p0))), ods, p->p_mmsize, oss);
234: #endif
235: #if defined(tahoe)
236: p0 = u.u_pcb.pcb_p0br + u.u_pcb.pcb_p0lr;
237: p2 = u.u_pcb.pcb_p2br + u.u_pcb.pcb_p2lr;
238: if (change > p2 - p0)
239: ptexpand(clrnd(ctopt(change - (p2 - p0))), ods, p->p_mmsize, oss);
240: #endif
241: #if defined(hp300) || defined(i386)
242: size = ptsize(p) - u.u_pcb.pcb_szpt;
243: if (size > 0)
244: ptexpand(size, ods, p->p_mmsize, oss);
245: #endif
246: /* PTEXPAND SHOULD GIVE BACK EXCESS PAGE TABLE PAGES */
247:
248: /*
249: * Compute the base of the allocated/freed region.
250: */
251: #if defined(vax)
252: p0lr = u.u_pcb.pcb_p0lr&~AST_CLR;
253: p1lr = u.u_pcb.pcb_p1lr&~PME_CLR;
254: #endif
255: #if defined(tahoe)
256: p0lr = u.u_pcb.pcb_p0lr;
257: p2lr = u.u_pcb.pcb_p2lr;
258: #endif
259: #if defined(hp300) || defined(i386)
260: p0lr = u.u_pcb.pcb_p0lr;
261: p1lr = u.u_pcb.pcb_p1lr;
262: #endif
263: if (region == 0) {
264: #ifdef MAPMEM
265: size = dptov(u.u_procp, ods);
266: #else
267: size = p0lr;
268: #endif
269: base = u.u_pcb.pcb_p0br + size + (change > 0 ? 0 : change);
270: } else {
271: #if defined(vax) || defined(hp300) || defined(i386)
272: size = p1lr;
273: base = u.u_pcb.pcb_p1br + size - (change > 0 ? change : 0);
274: #endif
275: #if defined(tahoe)
276: size = p2lr;
277: base = u.u_pcb.pcb_p2br + size - (change > 0 ? change : 0);
278: #endif
279: }
280:
281: /*
282: * If we shrank, give back the virtual memory.
283: */
284: if (change < 0)
285: p->p_rssize -= vmemfree(base, -change);
286:
287: /*
288: * Update the processor length registers and copies in the pcb.
289: */
290: if (region == 0) {
291: if (u.u_procp->p_mmsize == 0)
292: setp0lr(size + change);
293: } else
294: #if defined(vax) || defined(hp300) || defined(i386)
295: setp1lr(size - change);
296: #endif
297: #if defined(tahoe)
298: setp2lr(size - change);
299: #endif
300:
301: /*
302: * If shrinking, clear pte's, otherwise
303: * initialize zero fill on demand pte's.
304: */
305: *(int *)&proto = PG_UW;
306: if (change < 0)
307: change = -change;
308: else {
309: proto.pg_fod = 1;
310: ((struct fpte *)&proto)->pg_fileno = PG_FZERO;
311: cnt.v_nzfod += change;
312: }
313: base0 = base;
314: size = change;
315: while (--change >= 0)
316: *base++ = proto;
317:
318: /*
319: * We changed mapping for the current process,
320: * so must update the hardware translation
321: */
322: newptes(base0, v, size);
323: }
324:
325: /*
326: * Create a duplicate copy of the current process
327: * in process slot p, which has been partially initialized
328: * by newproc().
329: *
330: * Could deadlock here if two large proc's get page tables
331: * and then each gets part of his UPAGES if they then have
332: * consumed all the available memory. This can only happen when
333: * USRPTSIZE + UPAGES * NPROC > maxmem
334: * which is impossible except on systems with tiny real memories,
335: * when large procs stupidly fork() instead of vfork().
336: */
337: procdup(p, isvfork)
338: register struct proc *p;
339: {
340:
341: /*
342: * Allocate page tables for new process, waiting
343: * for memory to be free.
344: */
345: while (vgetpt(p, vmemall) == 0) {
346: kmapwnt++;
347: sleep((caddr_t)kernelmap, PSWP+4);
348: }
349: /*
350: * Snapshot the current u. area pcb and get a u.
351: * for the new process, a copy of our u.
352: */
353: resume(pcbb(u.u_procp));
354: (void) vgetu(p, vmemall, Forkmap, &forkutl, &u);
355: #if defined(tahoe)
356: /*
357: * Define new cache data key.
358: */
359: ckey_cnt[forkutl.u_procp->p_ckey]++;
360: forkutl.u_procp->p_dkey = getdatakey();
361: forkutl.u_pcb.pcb_savacc.faddr = (float *)NULL;
362: #endif
363:
364: /*
365: * Arrange for a non-local goto when the new process
366: * is started, to resume here, returning nonzero from setjmp.
367: */
368: forkutl.u_pcb.pcb_sswap = (int *)&u.u_ssave;
369: if (savectx(&forkutl.u_ssave)) {
370: #ifdef MAPMEM
371: if ((u.u_procp->p_flag & SVFORK) == 0 && u.u_mmap)
372: (void) mmfork((struct user *)0, &u);
373: #endif
374: /*
375: * Return 1 in child.
376: */
377: return (1);
378: }
379:
380: /*
381: * If the new process is being created in vfork(), then
382: * exchange vm resources with it. We want to end up with
383: * just a u. area and an empty p0 region, so initialize the
384: * prototypes in the other area before the exchange.
385: */
386: if (isvfork) {
387: #if defined(vax)
388: forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr & AST_CLR;
389: forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES;
390: #endif
391: #if defined(tahoe)
392: forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr;
393: forkutl.u_pcb.pcb_p1lr = 0;
394: forkutl.u_pcb.pcb_p2lr = P2PAGES - HIGHPAGES;
395: #endif
396: #if defined(hp300) || defined(i386)
397: forkutl.u_pcb.pcb_p0lr = 0;
398: forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES;
399: #endif
400: vpassvm(u.u_procp, p, &u, &forkutl, Forkmap);
401: /*
402: * Return 0 in parent.
403: */
404: return (0);
405: }
406: /*
407: * A real fork; clear vm statistics of new process
408: * and link into the new text segment.
409: * Equivalent things happen during vfork() in vpassvm().
410: */
411: bzero((caddr_t)&forkutl.u_ru, sizeof (struct rusage));
412: bzero((caddr_t)&forkutl.u_cru, sizeof (struct rusage));
413: forkutl.u_dmap = u.u_cdmap;
414: forkutl.u_smap = u.u_csmap;
415: forkutl.u_outime = 0;
416:
417: /*
418: * Attach to the text segment.
419: */
420: if (p->p_textp) {
421: p->p_textp->x_count++;
422: xlink(p);
423: }
424:
425: #ifdef MAPMEM
426: /*
427: * We do this before duplicating the address space since vmdup()
428: * might block causing Forkmap/forkutl to become invalid
429: */
430: if (u.u_mmap)
431: (void) mmfork(&u, &forkutl);
432: #endif
433: /*
434: * Duplicate data and stack space of current process
435: * in the new process.
436: */
437: vmdup(p, dptopte(p, 0), dptov(p, 0), p->p_dsize, CDATA);
438: vmdup(p, sptopte(p, p->p_ssize - 1), sptov(p, p->p_ssize - 1), p->p_ssize, CSTACK);
439:
440: /*
441: * Return 0 in parent.
442: */
443: return (0);
444: }
445:
446: vmdup(p, pte, v, count, type)
447: struct proc *p;
448: register struct pte *pte;
449: register unsigned v;
450: register segsz_t count;
451: int type;
452: {
453: register struct pte *opte = vtopte(u.u_procp, v);
454: register int i;
455: register struct cmap *c;
456:
457: while (count != 0) {
458: count -= CLSIZE;
459: if (opte->pg_fod) {
460: v += CLSIZE;
461: for (i = 0; i < CLSIZE; i++)
462: *(int *)pte++ = *(int *)opte++;
463: continue;
464: }
465: opte += CLSIZE;
466: (void) vmemall(pte, CLSIZE, p, type);
467: p->p_rssize += CLSIZE;
468: for (i = 0; i < CLSIZE; i++) {
469: copyseg((caddr_t)ctob(v+i), (pte+i)->pg_pfnum);
470: *(int *)(pte+i) |= (PG_V|PG_M) + PG_UW;
471: }
472: v += CLSIZE;
473: c = &cmap[pgtocm(pte->pg_pfnum)];
474: MUNLOCK(c);
475: pte += CLSIZE;
476: }
477: p->p_flag |= SPTECHG;
478: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.