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