|
|
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.