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