|
|
1.1 root 1: /*
2: * File: shm1.c
3: *
4: * Purpose: System V Compatible Shared Memory Device Driver
5: *
6: * $Log: shm1.c,v $
7: * Revision 1.3 93/06/14 13:39:25 bin
8: * hal: kernel 78 update
9: *
10: * Revision 1.3 93/04/14 10:23:10 root
11: * r75
12: *
13: */
14:
15: /*
16: * ----------------------------------------------------------------------
17: * Includes.
18: */
19: #include <sys/coherent.h>
20: #include <sys/types.h>
21: #include <sys/proc.h>
22: #include <sys/ipc.h>
23: #include <sys/shm.h>
24: #include <errno.h>
25:
26: /*
27: * ----------------------------------------------------------------------
28: * Definitions.
29: * Constants.
30: * Macros with argument lists.
31: * Typedefs.
32: * Enums.
33: */
34: #define SHMBASE 0x80000000 /* Base shared memory address */
35: /* These macros should be somewhere in the headers ???*/
36: #define DATAST 0x400000 /* Start of the data virtual address */
37: #define DATAEND 0x7FFFFF /* End of the data virtual address */
38: #define STACKST 0x7C000000 /* Start of the stack */
39: #define STACKEN 0x7FFFFFFF /* End of the stack virtual address */
40:
41: /*
42: * ----------------------------------------------------------------------
43: * Functions.
44: * Import Functions.
45: * Export Functions.
46: * Local Functions.
47: */
48: extern SEG *shmAlloc(); /* shm0.c */
49: char *ushmat();
50: int ushmdt();
51: int ushmctl();
52: int ushmget();
53: int iShmPerm(); /* Check permissions */
54: caddr_t vCheckReqAdd(); /* Check attach address for shmat */
55: /*
56: * ----------------------------------------------------------------------
57: * Global Data.
58: * Import Variables.
59: * Export Variables.
60: * Local Variables.
61: */
62:
63: /* Patchable global variables. */
64: int SHMMNI = 100; /* Maximum # of shared memory segments, systemwide */
65: int SHMMAX = 0x10000; /* Max size in bytes of shared memory segment */
66:
67:
68: struct shmid_ds *shmids = NULL; /* Array of shared memory segments */
69: SEG **shmsegs; /* Array of pointers to segments */
70: /*
71: * ----------------------------------------------------------------------
72: * Code.
73: */
74:
75: /*
76: * Shmctl - Shared Memory Control Operations.
77: */
78: int
79: ushmctl(iShmId, iCmd, pstShmId)
80: int iShmId, /* Shared memory id */
81: iCmd; /* Command */
82: struct shmid_ds *pstShmId; /* User shmid_ds buffer */
83: {
84: register struct shmid_ds *rstIdp;
85: int iRet = 0;
86:
87: /* Check if id is in proper range. */
88: if (iShmId >= SHMMNI || iShmId < 0) {
89: u.u_error = EINVAL;
90: return;
91: }
92: /* Check we did alloc. All allocatable arrays are alloced after
93: * the first ~correct usage of shmget.
94: */
95: if (shmids == NULL) {
96: u.u_error = EINVAL;
97: return;
98: }
99: rstIdp = &shmids[iShmId]; /* Requested segment */
100:
101: /* Check if segment is in used */
102: if ((rstIdp->shm_perm.mode & IPC_ALLOC) == 0) {
103: u.u_error = EINVAL;
104: return;
105: }
106:
107: switch (iCmd) {
108: case IPC_STAT:
109: /* Check read permission for stat. */
110: if (iShmPerm((rstIdp), SHM_R)) {
111: u.u_error = EACCES;
112: return;
113: }
114: /* Check if user gives a valid buffer */
115: if (!useracc(pstShmId, sizeof(struct shmid_ds), 1)) {
116: u.u_error = EFAULT;
117: return;
118: }
119: /* kucopy will set u_error if error occurs */
120: kucopy(rstIdp, pstShmId, sizeof(struct shmid_ds));
121: break;
122:
123: case IPC_SET:
124: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) &&
125: (u.u_uid != rstIdp->shm_perm.cuid)) {
126: u.u_error = EPERM;
127: iRet = -1;
128: break;
129: }
130: rstIdp->shm_perm.uid = getuwd(&(pstShmId->shm_perm.uid));
131: rstIdp->shm_perm.gid = getuwd(&(pstShmId->shm_perm.gid));
132: rstIdp->shm_perm.mode &= ~0777;
133: rstIdp->shm_perm.mode |= getuwd(&(pstShmId->shm_perm.mode))
134: & 0777;
135: break;
136:
137: case IPC_RMID:
138: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) &&
139: (u.u_uid != rstIdp->shm_perm.cuid)) {
140: u.u_error = EPERM;
141: iRet = -1;
142: break;
143: }
144:
145: /* SVR3 allows removing an attached segment. Even worse, the
146: * process that has the segment attached can keep using it.
147: * Some buggy third party software uses this "feature".
148: * So, we have to make it available too;-(
149: */
150: rstIdp->shm_perm.seq = 0;
151: rstIdp->shm_perm.mode = 0;
152:
153: /* If segment is attached, set flag to be removed */
154: if (rstIdp->shm_nattch > 0)
155: shmsegs[iShmId]->s_flags |= SRFBERM;
156: else /* remove it otherwise */
157: shmFree(shmsegs[iShmId]);
158: shmsegs[iShmId] = NULL;
159: break;
160:
161: /* SHM_LOCK and SHM_UNLOCK: lock/unlock shared memory segement
162: * in core. Is not a part of iBCS2.
163: * Has no meaning for current 4.0.* release of COHERENT.
164: * Have been done for binary portability.
165: */
166: case SHM_LOCK:
167: if (!u.u_uid) {
168: u.u_error = EPERM;
169: return;
170: }
171: break;
172: case SHM_UNLOCK:
173: if (!u.u_uid) {
174: u.u_error = EPERM;
175: return;
176: }
177: break;
178:
179: default:
180: u.u_error = EINVAL;
181: iRet = -1;
182: }
183:
184: return iRet;
185: }
186:
187: /*
188: * Shmget - Get Shared Memory Segment
189: * Return shared memory id if succed, -1 and set u_error otheriwse.
190: */
191: int
192: ushmget(kShmKey, iShmSize, iShmFlg)
193: key_t kShmKey; /* Shared memory key */
194: int iShmSize; /* Shared memory segment size */
195: int iShmFlg; /* Flags */
196: {
197: register struct shmid_ds *rstShmId; /* Work pointer */
198: register struct shmid_ds *rstOldest = 0;/* Oldest free segment */
199: register int i; /* Loop index */
200: SEG *pstSeg;
201:
202: /* Check the requested segment size */
203: if (iShmSize < 0 || iShmSize > SHMMAX) {
204: u.u_error = EINVAL;
205: return;
206: }
207: /* Init the shared memory on the first shmget. */
208: if (shmids == NULL)
209: if (shminit()) {
210: u.u_error = ENOSPC;
211: return;
212: }
213:
214: /* Search for desire shared memory segment. */
215: for (rstShmId = shmids, i = 0; i < SHMMNI; i++, rstShmId++) {
216: /* If segment is not alloced, we will look for the oldest
217: * free segment. We will use it to create a new one.
218: * The "oldest" will increase (a little) system reliability.
219: */
220: if ((rstShmId->shm_perm.mode & IPC_ALLOC) == 0) {
221: if ((rstOldest == NULL) ||
222: (rstOldest->shm_ctime > rstShmId->shm_ctime))
223: rstOldest = rstShmId;
224: continue;
225: }
226: /* Do we need a new segment? */
227: if (kShmKey == IPC_PRIVATE)
228: continue;
229: /* Keep going if key is different. The key is an element
230: * number of shmids
231: */
232: if (kShmKey != rstShmId->shm_perm.key)
233: continue;
234:
235: /* We found the segment with requested key. */
236:
237: /* Request was for the exclusive segment should fail. */
238: if ((iShmFlg & IPC_CREAT) && (iShmFlg & IPC_EXCL)) {
239: u.u_error = EEXIST;
240: return;
241: }
242:
243: /* Check the requested size */
244: if (rstShmId->shm_segsz < iShmSize) {
245: u.u_error = EINVAL;
246: return;
247: }
248:
249: /* Check permissions */
250: if (iShmPerm(rstShmId, iShmFlg))
251: return;
252: return i;
253: }
254:
255: /* We need to create a new segment */
256: if (rstOldest == 0) { /* Check system limits */
257: u.u_error = ENOSPC;
258: return;
259: }
260: if (!(iShmFlg & IPC_CREAT)) {
261: u.u_error = ENOENT;
262: return;
263: }
264: rstShmId = rstOldest;
265: /* Allocate a new shared memory segment */
266: pstSeg = shmAlloc(iShmSize);
267: if (pstSeg == NULL) {
268: u.u_error = ENOSPC;
269: return;
270: }
271: /* Save it in shmsegs */
272: shmsegs[rstShmId - shmids] = pstSeg;
273:
274: rstShmId->shm_perm.seq = (unsigned short) (rstShmId - shmids);
275: rstShmId->shm_segsz = iShmSize;
276: rstShmId->shm_atime = 0;
277: rstShmId->shm_dtime = 0;
278: rstShmId->shm_ctime = timer.t_time;
279: rstShmId->shm_cpid = SELF->p_pid;
280: rstShmId->shm_perm.cuid = rstShmId->shm_perm.uid = u.u_uid;
281: rstShmId->shm_perm.cgid = rstShmId->shm_perm.gid = u.u_gid;
282: rstShmId->shm_perm.mode = (iShmFlg & 0777) | IPC_ALLOC;
283: rstShmId->shm_perm.key = kShmKey;
284:
285: if (kShmKey == IPC_PRIVATE)
286: rstShmId->shm_perm.mode |= SHM_DEST;
287:
288: return rstShmId - shmids;
289: }
290:
291: /*
292: * Allocate space for shared memory data structures.
293: */
294: int
295: shminit()
296: {
297: shmids = (struct shmid_ds *) kalloc(sizeof(struct shmid_ds) * SHMMNI);
298: if (shmids == NULL)
299: return -1;
300:
301: /* Allocate array of shared memory segments. We do not have to
302: * initalise it
303: */
304: shmsegs = (SEG *) kalloc(sizeof(SEG *) * SHMMNI);
305: if (shmsegs == NULL)
306: return -1;
307: return 0;
308: }
309:
310: /*
311: * Attach shared memory segment.
312: */
313: char *
314: ushmat(iSysId, pcShmAddr, iShmFlg)
315: int iSysId; /* System segment id */
316: char *pcShmAddr; /* Address to attach */
317: int iShmFlg; /* Flags */
318: {
319: register PROC *rpstProc; /* Current process */
320: register struct sr *rpstSr; /* Shared memory segments */
321: struct sr *pstSrTmp;
322: SEG *pstSegSh; /* Segment to attach */
323: struct shmid_ds *pstShmId; /* Pointer to a system segment*/
324: unsigned int uSegId; /* Segment id */
325: caddr_t vAttAddr; /* Address to attach */
326: int i; /* Loop index */
327: int iReadOnly = 0; /* 1 - read only, 0 - rw */
328:
329: /* Check if iSysId is a valid shared memory id. */
330: if (iSysId < 0 || iSysId > SHMMNI) {
331: u.u_error = EINVAL;
332: return;
333: }
334: /* Do we really have this segment? */
335: pstShmId = shmids + iSysId;
336: if (pstShmId->shm_perm.seq != iSysId) {
337: u.u_error = EINVAL;
338: return;
339: }
340: /* Check permissions. */
341: if (iShmFlg & SHM_RDONLY)
342: iReadOnly = 1;
343: if (iReadOnly) {
344: if (iShmPerm(pstShmId, 0444)) {
345: u.u_error = EACCES;
346: return;
347: }
348: } else {
349: if (iShmPerm(pstShmId, 0666)) {
350: u.u_error = EACCES;
351: return;
352: }
353: }
354: /* Check if process has free shm index. */
355: rpstProc = SELF;
356: /* We will go through all NSHMSEG segments to see if any is free. */
357: for (rpstSr = rpstProc->p_shmsr; rpstSr < rpstProc->p_shmsr + NSHMSEG;
358: rpstSr++)
359: if (rpstSr->sr_segp == NULL)
360: break;
361: /* The segment id is just an element number. */
362: uSegId = rpstSr - rpstProc->p_shmsr;
363: /* If segment id is >= NSHMSEG we cannot attach any new segment. */
364: if (uSegId >= NSHMSEG) {
365: u.u_error = EMFILE;
366: return;
367: }
368: /* Get the pointer to the shared memory segment */
369: pstSegSh = shmsegs[iSysId];
370:
371: /* Find an address to attach.
372: * There are two cases: process does not request the address,
373: * process requests the address.
374: * In the first case we have to take the first available free address.
375: * We will try to put a free page between the segments.
376: * In the second case we have to check if address is an available and
377: * attach to this address.
378: */
379: /* First case. We have to find a free address. */
380: if (pcShmAddr == NULL) {
381: /* Find a free space to attach. */
382: for (pstSrTmp = rpstProc->p_shmsr, i = 0; i < NSHMSEG;
383: i++, pstSrTmp++)
384: if (pstSrTmp->sr_base == NULL)
385: break;
386: /* Check limit of attaches per process */
387: if (i >= NSHMSEG) {
388: u.u_error = EINVAL;
389: return;
390: }
391: /* We will use the addresses starting from SHMBASE.
392: * Each new address can be SHMMAX + NBPC appart.
393: */
394: vAttAddr = (caddr_t) (SHMBASE + i * (SHMMAX + NBPC));
395: } else {
396: /* Requst attach to a specific address. This is none portable
397: * way to use a shared memory.
398: */
399: if ((vAttAddr = vCheckReqAdd(pcShmAddr, iReadOnly)) < 0) {
400: printf("%s: attempt attach to 0x%x\n",
401: u.u_comm, pcShmAddr);
402: u.u_error = EINVAL;
403: return;
404: }
405: }
406:
407: if (!shmAtt(uSegId, vAttAddr, pstSegSh, iReadOnly)) {
408: u.u_error = EINVAL;
409: return;
410: }
411: pstShmId->shm_lpid = SELF->p_pid;
412: pstShmId->shm_atime = timer.t_time;
413: pstShmId->shm_dtime = 0;
414: pstShmId->shm_nattch = pstSegSh->s_urefc - 1;
415: /* Keep all attached addresses. We will need them for detach */
416: return (char *) vAttAddr;
417: }
418:
419: /*
420: * Check requested address for attach.
421: * Just fail for the first release.
422: */
423: caddr_t
424: vCheckReqAdd(pcAdd, iFlg)
425: char *pcAdd; /* Address to atatch */
426: int iFlg; /* Mode flag */
427: {
428: return (caddr_t) -1;
429: }
430:
431: /*
432: * Check permissions of the shared memory segment.
433: * Return 0 on success, -1 and set errno on error.
434: */
435: int
436: iShmPerm(pstShmId, iShmFlg)
437: struct shmid_ds *pstShmId;
438: int iShmFlg;
439: {
440: int iShmMode;
441:
442: /* We need 9 lower order bits. There is a question what we have to do
443: * if someone sets an execute bits on. At this point we just ignore
444: * them.
445: */
446: iShmMode = iShmFlg & 0666;
447:
448: /* For superuser or if mode is 0 */
449: if (u.u_uid == 0 || !iShmMode)
450: return 0;
451: /* For owner or creator */
452: if (u.u_uid == pstShmId->shm_perm.uid || u.u_uid
453: == pstShmId->shm_perm.cuid) {
454: if ((iShmMode & pstShmId->shm_perm.mode) & 0600)
455: return 0;
456: else {
457: u.u_error = EACCES;
458: return -1;
459: }
460: }
461: /* For group */
462: if (u.u_gid == pstShmId->shm_perm.gid
463: || u.u_gid == pstShmId->shm_perm.cgid) {
464: if ((iShmMode & pstShmId->shm_perm.mode) & 060)
465: return 0;
466: else {
467: u.u_error = EACCES;
468: return -1;
469: }
470: }
471: /* For the rest of the world */
472: if ((iShmMode & pstShmId->shm_perm.mode) & 06)
473: return 0;
474: else {
475: u.u_error = EACCES;
476: return -1;
477: }
478: /* We should never come here */
479: u.u_error = EACCES;
480: return -1;
481: }
482:
483: /*
484: * ushmdt() - Detach shared memory segment.
485: * Find segment number and call shmDetach() (shm0.c).
486: */
487: int
488: ushmdt(cpShmAddr)
489: char *cpShmAddr; /* Pointer to a segment */
490: {
491: register PROC *rpstProc; /* Current process */
492: register struct sr *rpstSr; /* Shared memory segments */
493: int i; /* Loop indexe */
494:
495: rpstProc = SELF; /* Get pointer to our process */
496:
497: /* Go through all segments. */
498: for (rpstSr = rpstProc->p_shmsr, i = 0; i < NSHMSEG; i++, rpstSr++) {
499: if (rpstSr->sr_base == (caddr_t) cpShmAddr) {
500: shmDetach(i);
501: return 0;
502: }
503: }
504:
505: /* We can come here only if we have invalid address */
506: u.u_error = EINVAL;
507: return;
508: }
509:
510: /*
511: * shmSetDs(). Called from shm0.c.
512: *
513: * Given a pointer to shared memory segment, set shmid_ds.
514: */
515: void
516: shmSetDs(rpstSeg)
517: register SEG *rpstSeg;
518: {
519: struct shmid_ds *pstShmId; /* Shared memory structure */
520: int iShmId; /* Shared memory id */
521: int j; /* Loop indexe */
522:
523: for (j = 0; j < SHMMNI; j++)
524: if (shmsegs[j] == rpstSeg)
525: break;
526:
527: /* We should have this segment. */
528: if (j >= SHMMNI) {
529: u.u_error = EINVAL;
530: return;
531: }
532:
533: iShmId = j;
534: pstShmId = shmids + iShmId;
535:
536: /* Set proper values */
537: pstShmId->shm_lpid = SELF->p_pid;
538: pstShmId->shm_dtime = timer.t_time;
539: pstShmId->shm_nattch = rpstSeg->s_urefc - 1;
540: return;
541: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.