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