|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: ! 27: #include <mach/error.h> ! 28: #include <mach/vm_param.h> ! 29: #include <kern/syscall_emulation.h> ! 30: #include <kern/task.h> ! 31: #include <kern/kalloc.h> ! 32: #include <vm/vm_kern.h> ! 33: ! 34: /* XXX */ ! 35: #define syscall_emulation_sync(task) ! 36: ! 37: ! 38: ! 39: /* ! 40: * WARNING: ! 41: * This code knows that kalloc() allocates memory most efficiently ! 42: * in sizes that are powers of 2, and asks for those sizes. ! 43: */ ! 44: ! 45: /* ! 46: * Go from number of entries to size of struct eml_dispatch and back. ! 47: */ ! 48: #define base_size (sizeof(struct eml_dispatch) - sizeof(eml_routine_t)) ! 49: #define count_to_size(count) \ ! 50: (base_size + sizeof(vm_offset_t) * (count)) ! 51: ! 52: #define size_to_count(size) \ ! 53: ( ((size) - base_size) / sizeof(vm_offset_t) ) ! 54: ! 55: /* ! 56: * eml_init: initialize user space emulation code ! 57: */ ! 58: void eml_init() ! 59: { ! 60: } ! 61: ! 62: /* ! 63: * eml_task_reference() [Exported] ! 64: * ! 65: * Bumps the reference count on the common emulation ! 66: * vector. ! 67: */ ! 68: ! 69: void eml_task_reference(task, parent) ! 70: task_t task, parent; ! 71: { ! 72: register eml_dispatch_t eml; ! 73: ! 74: if (parent == TASK_NULL) ! 75: eml = EML_DISPATCH_NULL; ! 76: else ! 77: eml = parent->eml_dispatch; ! 78: ! 79: if (eml != EML_DISPATCH_NULL) { ! 80: simple_lock(&eml->lock); ! 81: eml->ref_count++; ! 82: simple_unlock(&eml->lock); ! 83: } ! 84: task->eml_dispatch = eml; ! 85: } ! 86: ! 87: ! 88: /* ! 89: * eml_task_deallocate() [Exported] ! 90: * ! 91: * Cleans up after the emulation code when a process exits. ! 92: */ ! 93: ! 94: void eml_task_deallocate(task) ! 95: task_t task; ! 96: { ! 97: register eml_dispatch_t eml; ! 98: ! 99: eml = task->eml_dispatch; ! 100: if (eml != EML_DISPATCH_NULL) { ! 101: int count; ! 102: ! 103: simple_lock(&eml->lock); ! 104: count = --eml->ref_count; ! 105: simple_unlock(&eml->lock); ! 106: ! 107: if (count == 0) ! 108: kfree((vm_offset_t)eml, count_to_size(eml->disp_count)); ! 109: } ! 110: } ! 111: ! 112: /* ! 113: * task_set_emulation_vector: [Server Entry] ! 114: * set a list of emulated system calls for this task. ! 115: */ ! 116: kern_return_t ! 117: task_set_emulation_vector_internal(task, vector_start, emulation_vector, ! 118: emulation_vector_count) ! 119: task_t task; ! 120: int vector_start; ! 121: emulation_vector_t emulation_vector; ! 122: unsigned int emulation_vector_count; ! 123: { ! 124: eml_dispatch_t cur_eml, new_eml, old_eml; ! 125: vm_size_t new_size; ! 126: int cur_start, cur_end; ! 127: int new_start = 0, new_end = 0; ! 128: int vector_end; ! 129: ! 130: if (task == TASK_NULL) ! 131: return EML_BAD_TASK; ! 132: ! 133: vector_end = vector_start + emulation_vector_count; ! 134: ! 135: /* ! 136: * We try to re-use the existing emulation vector ! 137: * if possible. We can reuse the vector if it ! 138: * is not shared with another task and if it is ! 139: * large enough to contain the entries we are ! 140: * supplying. ! 141: * ! 142: * We must grab the lock on the task to check whether ! 143: * there is an emulation vector. ! 144: * If the vector is shared or not large enough, we ! 145: * need to drop the lock and allocate a new emulation ! 146: * vector. ! 147: * ! 148: * While the lock is dropped, the emulation vector ! 149: * may be released by all other tasks (giving us ! 150: * exclusive use), or may be enlarged by another ! 151: * task_set_emulation_vector call. Therefore, ! 152: * after allocating the new emulation vector, we ! 153: * must grab the lock again to check whether we ! 154: * really need the new vector we just allocated. ! 155: * ! 156: * Since an emulation vector cannot be altered ! 157: * if it is in use by more than one task, the ! 158: * task lock is sufficient to protect the vector`s ! 159: * start, count, and contents. The lock in the ! 160: * vector protects only the reference count. ! 161: */ ! 162: ! 163: old_eml = EML_DISPATCH_NULL; /* vector to discard */ ! 164: new_eml = EML_DISPATCH_NULL; /* new vector */ ! 165: ! 166: for (;;) { ! 167: /* ! 168: * Find the current emulation vector. ! 169: * See whether we can overwrite it. ! 170: */ ! 171: task_lock(task); ! 172: cur_eml = task->eml_dispatch; ! 173: if (cur_eml != EML_DISPATCH_NULL) { ! 174: cur_start = cur_eml->disp_min; ! 175: cur_end = cur_eml->disp_count + cur_start; ! 176: ! 177: simple_lock(&cur_eml->lock); ! 178: if (cur_eml->ref_count == 1 && ! 179: cur_start <= vector_start && ! 180: cur_end >= vector_end) ! 181: { ! 182: /* ! 183: * Can use the existing emulation vector. ! 184: * Discard any new one we allocated. ! 185: */ ! 186: simple_unlock(&cur_eml->lock); ! 187: old_eml = new_eml; ! 188: break; ! 189: } ! 190: ! 191: if (new_eml != EML_DISPATCH_NULL && ! 192: new_start <= cur_start && ! 193: new_end >= cur_end) ! 194: { ! 195: /* ! 196: * A new vector was allocated, and it is large enough ! 197: * to hold all the entries from the current vector. ! 198: * Copy the entries to the new emulation vector, ! 199: * deallocate the current one, and use the new one. ! 200: */ ! 201: bcopy((char *)&cur_eml->disp_vector[0], ! 202: (char *)&new_eml->disp_vector[cur_start-new_start], ! 203: cur_eml->disp_count * sizeof(vm_offset_t)); ! 204: ! 205: if (--cur_eml->ref_count == 0) ! 206: old_eml = cur_eml; /* discard old vector */ ! 207: simple_unlock(&cur_eml->lock); ! 208: ! 209: task->eml_dispatch = new_eml; ! 210: syscall_emulation_sync(task); ! 211: cur_eml = new_eml; ! 212: break; ! 213: } ! 214: simple_unlock(&cur_eml->lock); ! 215: ! 216: /* ! 217: * Need a new emulation vector. ! 218: * Ensure it will hold all the entries from ! 219: * both the old and new emulation vectors. ! 220: */ ! 221: new_start = vector_start; ! 222: if (new_start > cur_start) ! 223: new_start = cur_start; ! 224: new_end = vector_end; ! 225: if (new_end < cur_end) ! 226: new_end = cur_end; ! 227: } ! 228: else { ! 229: /* ! 230: * There is no current emulation vector. ! 231: * If a new one was allocated, use it. ! 232: */ ! 233: if (new_eml != EML_DISPATCH_NULL) { ! 234: task->eml_dispatch = new_eml; ! 235: cur_eml = new_eml; ! 236: break; ! 237: } ! 238: ! 239: /* ! 240: * Compute the size needed for the new vector. ! 241: */ ! 242: new_start = vector_start; ! 243: new_end = vector_end; ! 244: } ! 245: ! 246: /* ! 247: * Have no vector (or one that is no longer large enough). ! 248: * Drop all the locks and allocate a new vector. ! 249: * Repeat the loop to check whether the old vector was ! 250: * changed while we didn`t hold the locks. ! 251: */ ! 252: ! 253: task_unlock(task); ! 254: ! 255: if (new_eml != EML_DISPATCH_NULL) ! 256: kfree((vm_offset_t)new_eml, count_to_size(new_eml->disp_count)); ! 257: ! 258: new_size = count_to_size(new_end - new_start); ! 259: new_eml = (eml_dispatch_t) kalloc(new_size); ! 260: ! 261: bzero((char *)new_eml, new_size); ! 262: simple_lock_init(&new_eml->lock); ! 263: new_eml->ref_count = 1; ! 264: new_eml->disp_min = new_start; ! 265: new_eml->disp_count = new_end - new_start; ! 266: ! 267: continue; ! 268: } ! 269: ! 270: /* ! 271: * We have the emulation vector. ! 272: * Install the new emulation entries. ! 273: */ ! 274: bcopy((char *)&emulation_vector[0], ! 275: (char *)&cur_eml->disp_vector[vector_start - cur_eml->disp_min], ! 276: emulation_vector_count * sizeof(vm_offset_t)); ! 277: ! 278: task_unlock(task); ! 279: ! 280: /* ! 281: * Discard any old emulation vector we don`t need. ! 282: */ ! 283: if (old_eml) ! 284: kfree((vm_offset_t) old_eml, count_to_size(old_eml->disp_count)); ! 285: ! 286: return KERN_SUCCESS; ! 287: } ! 288: ! 289: /* ! 290: * task_set_emulation_vector: [Server Entry] ! 291: * ! 292: * Set the list of emulated system calls for this task. ! 293: * The list is out-of-line. ! 294: */ ! 295: kern_return_t ! 296: task_set_emulation_vector(task, vector_start, emulation_vector, ! 297: emulation_vector_count) ! 298: task_t task; ! 299: int vector_start; ! 300: emulation_vector_t emulation_vector; ! 301: unsigned int emulation_vector_count; ! 302: { ! 303: kern_return_t kr; ! 304: vm_offset_t emul_vector_addr; ! 305: ! 306: if (task == TASK_NULL) ! 307: return EML_BAD_TASK; /* XXX sb KERN_INVALID_ARGUMENT */ ! 308: ! 309: /* ! 310: * The emulation vector is really a vm_map_copy_t. ! 311: */ ! 312: kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr, ! 313: (vm_map_copy_t) emulation_vector); ! 314: if (kr != KERN_SUCCESS) ! 315: return kr; ! 316: ! 317: /* ! 318: * Do the work. ! 319: */ ! 320: kr = task_set_emulation_vector_internal( ! 321: task, ! 322: vector_start, ! 323: (emulation_vector_t) emul_vector_addr, ! 324: emulation_vector_count); ! 325: ! 326: /* ! 327: * Discard the memory ! 328: */ ! 329: (void) kmem_free(ipc_kernel_map, ! 330: emul_vector_addr, ! 331: emulation_vector_count * sizeof(eml_dispatch_t)); ! 332: ! 333: return kr; ! 334: } ! 335: ! 336: /* ! 337: * Compatibility entry. Vector is passed inline. ! 338: */ ! 339: kern_return_t ! 340: xxx_task_set_emulation_vector(task, vector_start, emulation_vector, ! 341: emulation_vector_count) ! 342: task_t task; ! 343: int vector_start; ! 344: emulation_vector_t emulation_vector; ! 345: unsigned int emulation_vector_count; ! 346: { ! 347: return task_set_emulation_vector_internal( ! 348: task, ! 349: vector_start, ! 350: emulation_vector, ! 351: emulation_vector_count); ! 352: } ! 353: ! 354: /* ! 355: * task_get_emulation_vector: [Server Entry] ! 356: * ! 357: * Get the list of emulated system calls for this task. ! 358: * List is returned out-of-line. ! 359: */ ! 360: kern_return_t ! 361: task_get_emulation_vector(task, vector_start, emulation_vector, ! 362: emulation_vector_count) ! 363: task_t task; ! 364: int *vector_start; /* out */ ! 365: emulation_vector_t *emulation_vector; /* out */ ! 366: unsigned int *emulation_vector_count; /* out */ ! 367: { ! 368: eml_dispatch_t eml; ! 369: vm_size_t vector_size, size; ! 370: vm_offset_t addr; ! 371: ! 372: if (task == TASK_NULL) ! 373: return EML_BAD_TASK; ! 374: ! 375: addr = 0; ! 376: size = 0; ! 377: ! 378: for(;;) { ! 379: vm_size_t size_needed; ! 380: ! 381: task_lock(task); ! 382: eml = task->eml_dispatch; ! 383: if (eml == EML_DISPATCH_NULL) { ! 384: task_unlock(task); ! 385: if (addr) ! 386: (void) kmem_free(ipc_kernel_map, addr, size); ! 387: *vector_start = 0; ! 388: *emulation_vector = 0; ! 389: *emulation_vector_count = 0; ! 390: return KERN_SUCCESS; ! 391: } ! 392: ! 393: /* ! 394: * Do we have the memory we need? ! 395: */ ! 396: vector_size = eml->disp_count * sizeof(vm_offset_t); ! 397: ! 398: size_needed = round_page(vector_size); ! 399: if (size_needed <= size) ! 400: break; ! 401: ! 402: /* ! 403: * If not, unlock the task and allocate more memory. ! 404: */ ! 405: task_unlock(task); ! 406: ! 407: if (size != 0) ! 408: kmem_free(ipc_kernel_map, addr, size); ! 409: ! 410: size = size_needed; ! 411: if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS) ! 412: return KERN_RESOURCE_SHORTAGE; ! 413: } ! 414: ! 415: /* ! 416: * Copy out the dispatch addresses ! 417: */ ! 418: *vector_start = eml->disp_min; ! 419: *emulation_vector_count = eml->disp_count; ! 420: bcopy((char *)eml->disp_vector, ! 421: (char *)addr, ! 422: vector_size); ! 423: ! 424: /* ! 425: * Unlock the task and free any memory we did not need ! 426: */ ! 427: task_unlock(task); ! 428: ! 429: { ! 430: vm_size_t size_used, size_left; ! 431: vm_map_copy_t memory; ! 432: ! 433: /* ! 434: * Free any unused memory beyond the end of the last page used ! 435: */ ! 436: size_used = round_page(vector_size); ! 437: if (size_used != size) ! 438: (void) kmem_free(ipc_kernel_map, ! 439: addr + size_used, ! 440: size - size_used); ! 441: ! 442: /* ! 443: * Zero the remainder of the page being returned. ! 444: */ ! 445: size_left = size_used - vector_size; ! 446: if (size_left > 0) ! 447: bzero((char *)addr + vector_size, size_left); ! 448: ! 449: /* ! 450: * Make memory into copyin form - this unwires it. ! 451: */ ! 452: (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory); ! 453: ! 454: *emulation_vector = (emulation_vector_t) memory; ! 455: } ! 456: ! 457: return KERN_SUCCESS; ! 458: } ! 459: ! 460: /* ! 461: * xxx_task_get_emulation: [Server Entry] ! 462: * get the list of emulated system calls for this task. ! 463: * Compatibility code: return list in-line. ! 464: */ ! 465: kern_return_t ! 466: xxx_task_get_emulation_vector(task, vector_start, emulation_vector, ! 467: emulation_vector_count) ! 468: task_t task; ! 469: int *vector_start; ! 470: emulation_vector_t emulation_vector; /* pointer to OUT array */ ! 471: unsigned int *emulation_vector_count; /*IN/OUT*/ ! 472: { ! 473: register eml_dispatch_t eml; ! 474: ! 475: if (task == TASK_NULL) ! 476: return( EML_BAD_TASK ); ! 477: ! 478: task_lock(task); ! 479: ! 480: eml = task->eml_dispatch; ! 481: if (eml == EML_DISPATCH_NULL) { ! 482: task_unlock(task); ! 483: *vector_start = 0; ! 484: *emulation_vector_count = 0; ! 485: return( KERN_SUCCESS ); ! 486: } ! 487: ! 488: simple_lock(&eml->lock); ! 489: ! 490: if (*emulation_vector_count < eml->disp_count) { ! 491: simple_unlock(&eml->lock); ! 492: task_unlock(task); ! 493: return( EML_BAD_CNT ); ! 494: } ! 495: ! 496: *vector_start = eml->disp_min; ! 497: *emulation_vector_count = eml->disp_count; ! 498: bcopy((char *)eml->disp_vector, (char *)emulation_vector, ! 499: *emulation_vector_count * sizeof(vm_offset_t)); ! 500: simple_unlock(&eml->lock); ! 501: ! 502: task_unlock(task); ! 503: ! 504: return( KERN_SUCCESS ); ! 505: } ! 506: ! 507: /* ! 508: * task_set_emulation: [Server Entry] ! 509: * set up for user space emulation of syscalls within this task. ! 510: */ ! 511: kern_return_t task_set_emulation(task, routine_entry_pt, routine_number) ! 512: task_t task; ! 513: vm_offset_t routine_entry_pt; ! 514: int routine_number; ! 515: { ! 516: return task_set_emulation_vector_internal(task, routine_number, ! 517: &routine_entry_pt, 1); ! 518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.