|
|
1.1 root 1: /* vmproc.c 4.5 81/03/08 */
2:
3: #include "sys/param.h"
4: #include "sys/systm.h"
5: #include "sys/user.h"
6: #include "sys/proc.h"
7: #include "sys/mtpr.h"
8: #include "sys/pte.h"
9: #include "sys/map.h"
10: #include "sys/cmap.h"
11: #include "sys/text.h"
12: #include "sys/inode.h"
13: #include "sys/vm.h"
14:
15: struct pte *Forkmap;
16: struct user *forkutl;
17:
18: struct dmap zdmap; /* well, it has to be somewhere */
19:
20: /*
21: * Get virtual memory resources for a new process.
22: * Called after page tables are allocated, but before they
23: * are initialized, we initialize the memory management registers,
24: * and then expand the page tables for the data and stack segments
25: * creating zero fill pte's there. Text pte's are set up elsewhere.
26: *
27: * SHOULD FREE EXTRA PAGE TABLE PAGES HERE OR SOMEWHERE.
28: */
29: vgetvm(ts, ds, ss)
30: clicks_t ts, ds, ss;
31: {
32:
33: mtpr(P0LR, ts);
34: u.u_pcb.pcb_p0lr = ts | AST_NONE;
35: mtpr(P1LR, P1TOP - UPAGES);
36: u.u_pcb.pcb_p1lr = P1TOP - UPAGES;
37: u.u_procp->p_tsize = ts;
38: u.u_tsize = ts;
39: expand((int)ss, P1BR);
40: expand((int)ds, P0BR);
41: }
42:
43: /*
44: * Release the virtual memory resources (memory
45: * pages, and swap area) associated with the current process.
46: * Caller must not be swappable. Used at exit or execl.
47: */
48: vrelvm()
49: {
50: register struct proc *p = u.u_procp;
51:
52: /*
53: * Release memory; text first, then data and stack pages.
54: */
55: xfree();
56: p->p_rssize -= vmemfree(dptopte(p, 0), p->p_dsize);
57: p->p_rssize -= vmemfree(sptopte(p, p->p_ssize - 1), p->p_ssize);
58: if (p->p_rssize != 0)
59: panic("vrelvm rss");
60: /*
61: * Wait for all page outs to complete, then
62: * release swap space.
63: */
64: p->p_swrss = 0;
65: while (p->p_poip)
66: sleep((caddr_t)&p->p_poip, PSWP+1);
67: (void) vsexpand((clicks_t)0, &u.u_dmap, 1);
68: (void) vsexpand((clicks_t)0, &u.u_smap, 1);
69: p->p_tsize = 0;
70: p->p_dsize = 0;
71: p->p_ssize = 0;
72: u.u_tsize = 0;
73: u.u_dsize = 0;
74: u.u_ssize = 0;
75: }
76:
77: /*
78: * Change the size of the data+stack regions of the process.
79: * If the size is shrinking, it's easy-- just release virtual memory.
80: * If it's growing, initalize new page table entries as
81: * 'zero fill on demand' pages.
82: */
83: expand(change, region)
84: {
85: register struct proc *p;
86: register struct pte *base, *p0, *p1;
87: struct pte proto;
88: int a0, a1;
89:
90: p = u.u_procp;
91: if (change == 0)
92: return;
93: if (change % CLSIZE)
94: panic("expand");
95: #ifdef PGINPROF
96: vmsizmon();
97: #endif
98: /*
99: * Update the sizes to reflect the change. Note that we may
100: * swap as a result of a ptexpand, but this will work, because
101: * the routines which swap out will get the current text and data
102: * sizes from the arguments they are passed, and when the process
103: * resumes the lengths in the proc structure are used to
104: * build the new page tables.
105: */
106: if (region == P0BR) {
107: p->p_dsize += change;
108: u.u_dsize += change;
109: } else {
110: p->p_ssize += change;
111: u.u_ssize += change;
112: }
113: /*
114: * Compute the end of the text+data regions and the beginning
115: * of the stack region in the page tables,
116: * and expand the page tables if necessary.
117: */
118: p0 = (struct pte *)mfpr(P0BR) + mfpr(P0LR);
119: p1 = (struct pte *)mfpr(P1BR) + mfpr(P1LR);
120: if (change > p1 - p0)
121: ptexpand(clrnd(ctopt(change - (p1 - p0))));
122: /* PTEXPAND SHOULD GIVE BACK EXCESS PAGE TABLE PAGES */
123: /*
124: * Compute the base of the allocated/freed region.
125: */
126: if (region == P0BR) {
127: base = (struct pte *)mfpr(P0BR);
128: base += (a0 = mfpr(P0LR)) + (change > 0 ? 0 : change);
129: } else {
130: base = (struct pte *)mfpr(P1BR);
131: base += (a1 = mfpr(P1LR)) - (change > 0 ? change : 0);
132: }
133:
134: /*
135: * If we shrunk, give back the virtual memory.
136: */
137: if (change < 0)
138: p->p_rssize -= vmemfree(base, -change);
139:
140: /*
141: * Update the processor length registers and copies in the pcb.
142: */
143: if (region == P0BR) {
144: mtpr(P0LR, a0 + change);
145: u.u_pcb.pcb_p0lr = a0 + change | (u.u_pcb.pcb_p0lr & AST_CLR);
146: } else {
147: mtpr(P1LR, a1 - change);
148: u.u_pcb.pcb_p1lr = a1 - change;
149: }
150: *(int *)&proto = PG_UW;
151: if (change < 0)
152: change = -change;
153: else {
154: proto.pg_fod = 1;
155: ((struct fpte *)&proto)->pg_source = PG_FZERO;
156: cnt.v_nzfod += change;
157: }
158: while (--change >= 0)
159: *base++ = proto;
160: mtpr(TBIA,0);
161: }
162:
163: /*
164: * Create a duplicate copy of the current process
165: * in process slot p, which has been partially initialized
166: * by newproc().
167: *
168: * Could deadlock here if two large proc's get page tables
169: * and then each gets part of his UPAGES if they then have
170: * consumed all the available memory. This can only happen when
171: * USRPTSIZE + UPAGES * NPROC > maxmem
172: * which happens only when large procs fork on machines with tiny real memories
173: */
174: procdup(p)
175: register struct proc *p;
176: {
177: extern struct map kernelmap[];
178:
179: /*
180: * allocate page tables and a user block;
181: * copy parent's user to child
182: */
183: while (vgetpt(p, vmemall) == 0) {
184: kmapwnt++;
185: sleep((caddr_t)kernelmap, PSWP+4);
186: }
187: resume(pcbb(u.u_procp));
188: (void) vgetu(p, vmemall, Forkmap, forkutl, &u);
189: /*
190: * child: return here when scheduled and returns 1
191: */
192: forkutl->u_pcb.pcb_sswap = u.u_ssav;
193: if (savectx(forkutl->u_ssav))
194: return (1);
195: /*
196: * parent:
197: * finish setting up child:
198: * clear vm counters, attach text, copy data and stack
199: * return 0
200: */
201: forkutl->u_vm = zvms;
202: forkutl->u_cvm = zvms;
203: forkutl->u_dmap = u.u_cdmap;
204: forkutl->u_smap = u.u_csmap;
205: forkutl->u_outime = 0;
206: if (p->p_textp && ((p->p_textp->x_flag&XTRC) == 0 || vmxdup(p))) {
207: p->p_textp->x_count++;
208: xlink(p);
209: }
210: vmdup(p, dptopte(p, 0), dptov(p, 0), p->p_dsize, CDATA);
211: vmdup(p, sptopte(p, p->p_ssize - 1), sptov(p, p->p_ssize - 1), p->p_ssize, CSTACK);
212: return (0);
213: }
214:
215: /*
216: * Duplicate text segment (cf. xalloc).
217: */
218: vmxdup(p)
219: register struct proc *p;
220: {
221: register struct text *xp, *uxp;
222: register clicks_t ts;
223:
224: if ((uxp = u.u_procp->p_textp) == 0)
225: return 0;
226:
227: for (xp = text; xp < textNTEXT && xp->x_iptr; xp++)
228: /* void */ ;
229: if (xp >= textNTEXT)
230: return 1;
231:
232: xp->x_flag = XLOCK|XTRC|XLOAD;
233: xp->x_size = ts = uxp->x_size;
234: if (vsxalloc(xp) == NULL)
235: return 1;
236:
237: xp->x_count = 1;
238: xp->x_ccount = 0;
239: xp->x_rssize = 0;
240: (xp->x_iptr = uxp->x_iptr)->i_count++;
241: p->p_textp = xp;
242: xlink(p);
243: vmdup(p, tptopte(p, 0), tptov(p, 0), ts, CTEXT);
244: xp->x_flag |= XWRIT;
245: xp->x_flag &= ~XLOAD;
246: xunlock(xp);
247:
248: return 0;
249: }
250:
251: vmdup(p, pte, v, count, type)
252: struct proc *p;
253: register struct pte *pte;
254: register unsigned v;
255: register clicks_t count;
256: int type;
257: {
258: register struct pte *opte = vtopte(u.u_procp, v);
259: register int i;
260:
261: while (count != 0) {
262: count -= CLSIZE;
263: if (opte->pg_fod && type != CTEXT) {
264: v += CLSIZE;
265: for (i = 0; i < CLSIZE; i++)
266: *(int *)pte++ = *(int *)opte++;
267: continue;
268: }
269: opte += CLSIZE;
270: (void) vmemall(pte, CLSIZE, p, type);
271: if (type == CTEXT)
272: p->p_textp->x_rssize += CLSIZE;
273: else
274: p->p_rssize += CLSIZE;
275: for (i = 0; i < CLSIZE; i++) {
276: copyseg((caddr_t)ctob(v+i), (pte+i)->pg_pfnum);
277: *(int *)(pte+i) |= (type == CTEXT) ?
278: ((PG_V|PG_M) + PG_URKR) : ((PG_V|PG_M) + PG_UW);
279: }
280: v += CLSIZE;
281: munlock(pte->pg_pfnum);
282: pte += CLSIZE;
283: }
284: }
285:
286: /*
287: * Check that a process will not be too large.
288: */
289: chksize(ts, ds, ss)
290: clicks_t ts, ds, ss;
291: {
292:
293: if (ts>maxtsize || ds>maxdsize || ss>maxssize) {
294: u.u_error = ENOMEM;
295: return(1);
296: }
297: return (0);
298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.