|
|
1.1 root 1: /*
2: * i386/shm0.c
3: *
4: * Shared memory - memory management interface
5: *
6: * Revised: Thu May 27 08:09:19 1993 CDT
7: */
8:
9: /*
10: * ----------------------------------------------------------------------
11: * Includes.
12: */
13: #include <sys/coherent.h>
14: #include <sys/reg.h>
15:
16: /*
17: * ----------------------------------------------------------------------
18: * Definitions.
19: * Constants.
20: * Macros with argument lists.
21: * Typedefs.
22: * Enums.
23: */
24: #define SHMMAX 0x100000 /* one meg limit on shm seg size */
25:
26: /*
27: * ----------------------------------------------------------------------
28: * Functions.
29: * Import Functions.
30: * Export Functions.
31: * Local Functions.
32: */
33: SR * accShm();
34: void pdCheck();
35: void shmAllDt();
36: SEG * shmAlloc();
37: int shmAtt();
38: int shmAttach();
39: void shmDetach();
40: void shmDetachP();
41: void shmDup();
42: void shmFree();
43: void shmLoad();
44:
45: /*
46: * ----------------------------------------------------------------------
47: * Global Data.
48: * Import Variables.
49: * Export Variables.
50: * Local Variables.
51: */
52:
53: /*
54: * ----------------------------------------------------------------------
55: * Code.
56: */
57:
58: /*
59: * shmAlloc()
60: *
61: * Allocate a segment for shared memory that is `bytes_wanted' bytes long.
62: *
63: * if successful, return allocated SEG *
64: * else, return 0
65: *
66: * This routine is cloned from smalloc(), from which it differs by
67: * (a) locking/unlocking seglink,
68: * (b) NOT linking the new segment into segmq,
69: * (c) rounding segment size up to a multiple of 4k bytes.
70: *
71: * The reference counts s_urefc and s_lrefc for a shm segment are 1
72: * at the time of allocation. Each attachment to a new process and
73: * each fork of an already attached process will increment these.
74: */
75: SEG *
76: shmAlloc(bytes_wanted)
77: off_t bytes_wanted;
78: {
79: register SEG *new_seg = 0;
80: unsigned int clicks_wanted;
81:
82: lock(seglink);
83: clicks_wanted = btoc(bytes_wanted);
84:
85: /* Limit size of any shm segment to SHMMAX bytes. */
86: if (bytes_wanted > SHMMAX)
87: goto shmAllocDone;
88:
89: /*
90: * Estimate space needed for new segment and its overhead.
91: * Fail if not enough free RAM available.
92: */
93: if (countsize(clicks_wanted) > allocno())
94: goto shmAllocDone;
95: /*
96: * Allocate a new SEG struct to keep track of the segment, if possible.
97: */
98: if ((new_seg = kalloc(sizeof (SEG))) == NULL)
99: goto shmAllocDone;
100:
101: if ((new_seg->s_vmem = c_alloc(clicks_wanted)) == 0) {
102: kfree(new_seg);
103: goto shmAllocDone;
104: }
105:
106: new_seg->s_urefc = 1;
107: new_seg->s_lrefc = 1;
108: new_seg->s_size = ctob(clicks_wanted);
109: new_seg->s_flags = SFCORE;
110:
111: shmAllocDone:
112: unlock(seglink);
113: return new_seg;
114: }
115:
116: /*
117: * shmAtt()
118: *
119: * Given a pointer "segp" to a SEG which is already allocated, the
120: * virtual base address "base" where the segment is to appear, and an
121: * index "shm_ix" into p_shmsr[] for a process, set up the
122: * SR struct accordingly.
123: *
124: * Argument "ronflag" is nonzero if segment is to be attached read-only.
125: *
126: * Return 0 in case of failure, else nonzero.
127: */
128: int
129: shmAtt(shm_ix, base, segp, ronflag)
130: unsigned int shm_ix;
131: caddr_t base;
132: SEG * segp;
133: int ronflag;
134: {
135: int numBytes = segp->s_size;
136: return shmAttach(shm_ix, numBytes, base, segp, ronflag);
137: }
138:
139: /*
140: * shmAttach()
141: *
142: * Given a pointer "segp" to a SEG which is already allocated, the number
143: * "numBytes" of bytes in the segment visible in this reference, the
144: * virtual base address "base" where the segment is to appear, and an
145: * index "shm_ix" into p_shmsr[] for a process, set up the
146: * SR struct accordingly.
147: *
148: * Argument "ronflag" is nonzero if segment is to be attached read-only.
149: *
150: * Return 0 in case of failure, else nonzero.
151: */
152: int
153: shmAttach(shm_ix, numBytes, base, segp, ronflag)
154: unsigned int shm_ix;
155: off_t numBytes;
156: caddr_t base;
157: SEG * segp;
158: int ronflag;
159: {
160: SR * srp;
161:
162: /* sanity checks */
163: if (shm_ix >= NSHMSEG || numBytes > segp->s_size)
164: return 0;
165:
166: /*
167: * You may find that the base address requested is not
168: * supported in the page directory. Since a shm segment
169: * may straddle a 4 Mb boundary, there is the possibility
170: * of two missing page directory entries. Check for both.
171: */
172: pdCheck(base);
173: pdCheck(base + segp->s_size - 1);
174:
175: srp = SELF->p_shmsr + shm_ix;
176: srp->sr_base = base;
177: srp->sr_flag = (SRFDUMP | SRFDATA);
178: if (ronflag)
179: srp->sr_flag |= SRFRODT;
180: srp->sr_size = numBytes;
181: srp->sr_segp = segp;
182:
183: segp->s_urefc++;
184: segp->s_lrefc++;
185:
186: shmLoad();
187: return 1;
188: }
189:
190: /*
191: * shmDetachP()
192: *
193: * Given an index "shm_ix", into the p_shmsr[] for a process,
194: * and a PROC *, detach the indicated shared memory segment.
195: */
196: void
197: shmDetachP(shm_ix, pp)
198: unsigned int shm_ix;
199: PROC *pp;
200: {
201: SR * srp;
202: SEG * segp;
203:
204: if (shm_ix >= NSHMSEG)
205: return;
206:
207: srp = pp->p_shmsr + shm_ix;
208: segp = srp->sr_segp;
209:
210: if (segp) {
211: segp->s_urefc--;
212: segp->s_lrefc--;
213:
214: /* We have to set detach time and decrement attachment
215: * count.
216: */
217: shmSetDs(segp); /* shm1.c */
218:
219: /* If it was last attachment and segment was marked to be
220: * removed, remove it.
221: */
222: if ((segp->s_flags & SRFBERM)
223: && segp->s_urefc == 1 && segp->s_lrefc == 1)
224: shmFree(segp);
225: }
226: srp->sr_base = 0;
227: srp->sr_flag = 0;
228: srp->sr_size = 0;
229: srp->sr_segp = 0;
230:
231: if (pp == SELF)
232: shmLoad();
233: }
234:
235: /*
236: * shmDetach()
237: *
238: * Given an index "shm_ix", into the p_shmsr[] for a process,
239: * detach the indicated shared memory segment.
240: */
241: void
242: shmDetach(shm_ix)
243: unsigned int shm_ix;
244: {
245: shmDetachP(shm_ix, SELF);
246: }
247:
248: /*
249: * Scan shared memory for the range of addresses from
250: * "base" up to but not including "base" + "count".
251: *
252: * If any shared memory segment contains the range of addresses, return
253: * its SR pointer, otherwise return zero.
254: *
255: * This routine is used by iomapvp() and sysio().
256: */
257: SR *
258: accShm(base, numBytes)
259: caddr_t base;
260: off_t numBytes;
261: {
262: SR * srp;
263: int i;
264:
265: for (i = 0; i < NSHMSEG; i++) {
266: srp = SELF->p_shmsr + i;
267: if (srp->sr_segp && base >= srp->sr_base
268: && base + numBytes <= srp->sr_base + srp->sr_size)
269: return srp;
270: }
271: return 0;
272: }
273:
274: /*
275: * shmFree()
276: *
277: * Given a non-null SEG pointer "segp" to a shared memory segment,
278: * deallocate the RAM used by that segment.
279: *
280: * The s_urefc field must be 1 when this routine is called, i.e., there
281: * must be no pending attachments to the segment.
282: */
283: void
284: shmFree(segp)
285: SEG * segp;
286: {
287: if (segp == NULL) {
288: printf("shmFree err: NULL argument\n");
289: return;
290: }
291:
292: if (segp->s_urefc != 1 || segp->s_lrefc != 1) {
293: printf("shmFree err: segp=%x count=%d\n", segp, segp->s_urefc);
294: return;
295: }
296:
297: lock(seglink);
298: c_free(segp->s_vmem, btoc(segp->s_size));
299: unlock(seglink);
300:
301: kfree(segp);
302: }
303:
304: /*
305: * Given a PROC pointer "pp", detach ALL shared memory segments from
306: * the process. Done during exec and exit.
307: */
308: void
309: shmAllDt()
310: {
311: PROC * pp = SELF;
312: int i;
313:
314: for (i = 0; i < NSHMSEG; i++)
315: shmDetach(i);
316: }
317:
318: /*
319: * Given a PROC pointer "cpp" (e.g. child-of-current-process),
320: * duplicate ALL shared memory segments for the process, and update
321: * reference counts. Done during fork.
322: */
323: void
324: shmDup(cpp)
325: PROC * cpp;
326: {
327: int i;
328: PROC * pp = SELF;
329: SR * srp;
330:
331: for (i = 0, srp = pp->p_shmsr; i < NSHMSEG; i++, srp++) {
332: cpp->p_shmsr[i] = *srp;
333: if (srp->sr_segp) {
334: srp->sr_segp->s_urefc++;
335: srp->sr_segp->s_lrefc++;
336: }
337: }
338: }
339:
340: /*
341: * Load mmu according to shared memory segments.
342: */
343:
344: void
345: shmLoad()
346: {
347: register int i;
348: register SR *srp;
349: static SR ushmtab[NSHMSEG];
350:
351: /*
352: * Unprogram the currently active segments.
353: * Reset ushmtab.
354: */
355: for (i = 0, srp = ushmtab; i < NSHMSEG; i++, srp++) {
356: if (srp->sr_segp)
357: unload(srp);
358: srp->sr_segp = 0;
359: }
360:
361: /*
362: * Load each segment in the SELF->p_shmsr list into the MMU.
363: * Remember values in ushmtab.
364: */
365: for (i = 0, srp = SELF->p_shmsr; i < NSHMSEG; i++, srp++) {
366: if (srp->sr_segp) {
367: ushmtab[i] = *srp;
368: doload(srp);
369: }
370: }
371: }
372:
373: /*
374: * Given a virtual address "base", check the page directory. If the page
375: * directory can't access "base", allocate a 4k page table for the segment and
376: * point the page directory at the new page table.
377: *
378: * This routine is really tricky, so here is a picture of virtual memory:
379: *
380: * +--------------------+
381: * | U area, etc |
382: * |--------------------| 0xFFFF_F000
383: * | Page directory |
384: * |--------------------| 0xFFFF_E000
385: * | ... |
386: * | Kernel text, data |
387: * |--------------------| 0xFFC0_0000
388: * | ----- | <- 4k page table that maps ptable1_v[] (unmapped!)
389: * | ... |
390: * | ----- | <- 4k page table that maps base (basePTvadd[])
391: * | Page tables |
392: * | (ptable1_v[]) |
393: * |--------------------| 0xFF80_0000
394: * | ... |
395: * | base |
396: * | ... |
397: * +--------------------+ 0x0000_0000
398: *
399: * In comments below, "segment number" is a value in range 0..0x3FF.
400: */
401: void
402: pdCheck(base)
403: {
404: int baseSeg; /* Segment number of base */
405: int ptable1_vSeg; /* Segment number of ptable1_v */
406:
407: int tabPadd; /* Physical address of new 4k page table */
408: int basePTvadd; /* Virtual address where we want the new page
409: table click (in ptable1_v[]). */
410:
411: int ptable1_vPTpadd; /* Physical address of page table covering
412: segment ptable1_v[]. */
413: int w; /* Temporary virtual click number for
414: * ptable1_vPTpadd. */
415: int basePTindex; /* Offset of entry for page table for "base"
416: within its page table. */
417: int *unmapped;
418:
419: baseSeg = btosrd(base);
420:
421: /* If there is already a page table for "base", nothing to do. */
422: if (ptable0_v[baseSeg] & SEG_PRE)
423: return;
424:
425: /* Get a free click. */
426: DV(baseSeg);
427: tabPadd = clickseg(*--sysmem.pfree);
428: DV(tabPadd);
429:
430: /* Point the page directory at the new click. */
431: ptable0_v[baseSeg] = tabPadd | DIR_RW;
432:
433: /* Now update the page tables so we can access the new click. */
434:
435: /* Get physical address for the page table for segment ptable1_v[]. */
436: ptable1_vSeg = btosrd(ptable1_v)&0x3ff;
437: DV(ptable1_vSeg);
438: ptable1_vPTpadd = ptable0_v[ptable1_vSeg] & ~SEG_BITS;
439: DV(ptable1_vPTpadd);
440:
441: /* Map the click at ptable1_vPTpadd into virtual memory somewhere. */
442: w = workAlloc();
443: DV(w);
444: ptable1_v[w] = ptable1_vPTpadd | SEG_SRW;
445: mmuupd();
446:
447: /* Point page table at new page table click. */
448: basePTvadd = (int)(ptable1_v + btocrd(base));
449: DV(basePTvadd);
450: basePTindex = btocrd(basePTvadd) & 0x3FF;
451: DV(basePTindex);
452: unmapped = (int *)(ctob(w)) + basePTindex;
453: DV(unmapped);
454: *unmapped = tabPadd | SEG_SRW;
455: mmuupd();
456:
457: /* Release the temporary click of virtual space. */
458: workFree(w);
459:
460: /* Now we can write to the new page table. Initialize it empty. */
461: memset(basePTvadd, 0, NBPC);
462: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.