|
|
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:
1.1.1.2 root 27: #include <string.h>
28:
1.1 root 29: #include <mach/error.h>
30: #include <mach/vm_param.h>
31: #include <kern/syscall_emulation.h>
32: #include <kern/task.h>
33: #include <kern/kalloc.h>
34: #include <vm/vm_kern.h>
35:
36: /* XXX */
37: #define syscall_emulation_sync(task)
38:
39:
40:
41: /*
42: * WARNING:
43: * This code knows that kalloc() allocates memory most efficiently
44: * in sizes that are powers of 2, and asks for those sizes.
45: */
46:
47: /*
48: * Go from number of entries to size of struct eml_dispatch and back.
49: */
50: #define base_size (sizeof(struct eml_dispatch) - sizeof(eml_routine_t))
51: #define count_to_size(count) \
52: (base_size + sizeof(vm_offset_t) * (count))
53:
54: #define size_to_count(size) \
55: ( ((size) - base_size) / sizeof(vm_offset_t) )
56:
57: /*
58: * eml_init: initialize user space emulation code
59: */
1.1.1.3 ! root 60: void eml_init(void)
1.1 root 61: {
62: }
63:
64: /*
65: * eml_task_reference() [Exported]
66: *
67: * Bumps the reference count on the common emulation
68: * vector.
69: */
70:
1.1.1.3 ! root 71: void eml_task_reference(
! 72: task_t task,
! 73: task_t parent)
1.1 root 74: {
1.1.1.3 ! root 75: eml_dispatch_t eml;
1.1 root 76:
77: if (parent == TASK_NULL)
78: eml = EML_DISPATCH_NULL;
79: else
80: eml = parent->eml_dispatch;
81:
82: if (eml != EML_DISPATCH_NULL) {
83: simple_lock(&eml->lock);
84: eml->ref_count++;
85: simple_unlock(&eml->lock);
86: }
87: task->eml_dispatch = eml;
88: }
89:
90:
91: /*
92: * eml_task_deallocate() [Exported]
93: *
94: * Cleans up after the emulation code when a process exits.
95: */
96:
97: void eml_task_deallocate(task)
1.1.1.3 ! root 98: const task_t task;
1.1 root 99: {
1.1.1.3 ! root 100: eml_dispatch_t eml;
1.1 root 101:
102: eml = task->eml_dispatch;
103: if (eml != EML_DISPATCH_NULL) {
104: int count;
105:
106: simple_lock(&eml->lock);
107: count = --eml->ref_count;
108: simple_unlock(&eml->lock);
109:
110: if (count == 0)
111: kfree((vm_offset_t)eml, count_to_size(eml->disp_count));
112: }
113: }
114:
115: /*
116: * task_set_emulation_vector: [Server Entry]
117: * set a list of emulated system calls for this task.
118: */
119: kern_return_t
1.1.1.3 ! root 120: task_set_emulation_vector_internal(
! 121: task_t task,
! 122: int vector_start,
! 123: emulation_vector_t emulation_vector,
! 124: unsigned int emulation_vector_count)
1.1 root 125: {
126: eml_dispatch_t cur_eml, new_eml, old_eml;
127: vm_size_t new_size;
128: int cur_start, cur_end;
129: int new_start = 0, new_end = 0;
130: int vector_end;
131:
132: if (task == TASK_NULL)
133: return EML_BAD_TASK;
134:
135: vector_end = vector_start + emulation_vector_count;
136:
137: /*
138: * We try to re-use the existing emulation vector
139: * if possible. We can reuse the vector if it
140: * is not shared with another task and if it is
141: * large enough to contain the entries we are
142: * supplying.
143: *
144: * We must grab the lock on the task to check whether
145: * there is an emulation vector.
146: * If the vector is shared or not large enough, we
147: * need to drop the lock and allocate a new emulation
148: * vector.
149: *
150: * While the lock is dropped, the emulation vector
151: * may be released by all other tasks (giving us
152: * exclusive use), or may be enlarged by another
153: * task_set_emulation_vector call. Therefore,
154: * after allocating the new emulation vector, we
155: * must grab the lock again to check whether we
156: * really need the new vector we just allocated.
157: *
158: * Since an emulation vector cannot be altered
159: * if it is in use by more than one task, the
160: * task lock is sufficient to protect the vector`s
161: * start, count, and contents. The lock in the
162: * vector protects only the reference count.
163: */
164:
165: old_eml = EML_DISPATCH_NULL; /* vector to discard */
166: new_eml = EML_DISPATCH_NULL; /* new vector */
167:
168: for (;;) {
169: /*
170: * Find the current emulation vector.
171: * See whether we can overwrite it.
172: */
173: task_lock(task);
174: cur_eml = task->eml_dispatch;
175: if (cur_eml != EML_DISPATCH_NULL) {
176: cur_start = cur_eml->disp_min;
177: cur_end = cur_eml->disp_count + cur_start;
178:
179: simple_lock(&cur_eml->lock);
180: if (cur_eml->ref_count == 1 &&
181: cur_start <= vector_start &&
182: cur_end >= vector_end)
183: {
184: /*
185: * Can use the existing emulation vector.
186: * Discard any new one we allocated.
187: */
188: simple_unlock(&cur_eml->lock);
189: old_eml = new_eml;
190: break;
191: }
192:
193: if (new_eml != EML_DISPATCH_NULL &&
194: new_start <= cur_start &&
195: new_end >= cur_end)
196: {
197: /*
198: * A new vector was allocated, and it is large enough
199: * to hold all the entries from the current vector.
200: * Copy the entries to the new emulation vector,
201: * deallocate the current one, and use the new one.
202: */
1.1.1.2 root 203: memcpy(&new_eml->disp_vector[cur_start-new_start],
204: &cur_eml->disp_vector[0],
205: cur_eml->disp_count * sizeof(vm_offset_t));
1.1 root 206:
207: if (--cur_eml->ref_count == 0)
208: old_eml = cur_eml; /* discard old vector */
209: simple_unlock(&cur_eml->lock);
210:
211: task->eml_dispatch = new_eml;
212: syscall_emulation_sync(task);
213: cur_eml = new_eml;
214: break;
215: }
216: simple_unlock(&cur_eml->lock);
217:
218: /*
219: * Need a new emulation vector.
220: * Ensure it will hold all the entries from
221: * both the old and new emulation vectors.
222: */
223: new_start = vector_start;
224: if (new_start > cur_start)
225: new_start = cur_start;
226: new_end = vector_end;
227: if (new_end < cur_end)
228: new_end = cur_end;
229: }
230: else {
231: /*
232: * There is no current emulation vector.
233: * If a new one was allocated, use it.
234: */
235: if (new_eml != EML_DISPATCH_NULL) {
236: task->eml_dispatch = new_eml;
237: cur_eml = new_eml;
238: break;
239: }
240:
241: /*
242: * Compute the size needed for the new vector.
243: */
244: new_start = vector_start;
245: new_end = vector_end;
246: }
247:
248: /*
249: * Have no vector (or one that is no longer large enough).
250: * Drop all the locks and allocate a new vector.
251: * Repeat the loop to check whether the old vector was
252: * changed while we didn`t hold the locks.
253: */
254:
255: task_unlock(task);
256:
257: if (new_eml != EML_DISPATCH_NULL)
258: kfree((vm_offset_t)new_eml, count_to_size(new_eml->disp_count));
259:
260: new_size = count_to_size(new_end - new_start);
261: new_eml = (eml_dispatch_t) kalloc(new_size);
262:
1.1.1.2 root 263: memset(new_eml, 0, new_size);
1.1 root 264: simple_lock_init(&new_eml->lock);
265: new_eml->ref_count = 1;
266: new_eml->disp_min = new_start;
267: new_eml->disp_count = new_end - new_start;
268:
269: continue;
270: }
271:
272: /*
273: * We have the emulation vector.
274: * Install the new emulation entries.
275: */
1.1.1.2 root 276: memcpy(&cur_eml->disp_vector[vector_start - cur_eml->disp_min],
277: &emulation_vector[0],
278: emulation_vector_count * sizeof(vm_offset_t));
1.1 root 279:
280: task_unlock(task);
281:
282: /*
283: * Discard any old emulation vector we don`t need.
284: */
285: if (old_eml)
286: kfree((vm_offset_t) old_eml, count_to_size(old_eml->disp_count));
287:
288: return KERN_SUCCESS;
289: }
290:
291: /*
292: * task_set_emulation_vector: [Server Entry]
293: *
294: * Set the list of emulated system calls for this task.
295: * The list is out-of-line.
296: */
297: kern_return_t
1.1.1.3 ! root 298: task_set_emulation_vector(
! 299: task_t task,
! 300: int vector_start,
! 301: emulation_vector_t emulation_vector,
! 302: unsigned int emulation_vector_count)
1.1 root 303: {
304: kern_return_t kr;
305: vm_offset_t emul_vector_addr;
306:
307: if (task == TASK_NULL)
308: return EML_BAD_TASK; /* XXX sb KERN_INVALID_ARGUMENT */
309:
310: /*
311: * The emulation vector is really a vm_map_copy_t.
312: */
313: kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
314: (vm_map_copy_t) emulation_vector);
315: if (kr != KERN_SUCCESS)
316: return kr;
317:
318: /*
319: * Do the work.
320: */
321: kr = task_set_emulation_vector_internal(
322: task,
323: vector_start,
324: (emulation_vector_t) emul_vector_addr,
325: emulation_vector_count);
326:
327: /*
328: * Discard the memory
329: */
330: (void) kmem_free(ipc_kernel_map,
331: emul_vector_addr,
332: emulation_vector_count * sizeof(eml_dispatch_t));
333:
334: return kr;
335: }
336:
337: /*
338: * task_get_emulation_vector: [Server Entry]
339: *
340: * Get the list of emulated system calls for this task.
341: * List is returned out-of-line.
342: */
343: kern_return_t
1.1.1.3 ! root 344: task_get_emulation_vector(
! 345: task_t task,
! 346: int *vector_start, /* out */
! 347: emulation_vector_t *emulation_vector, /* out */
! 348: unsigned int *emulation_vector_count) /* out */
1.1 root 349: {
350: eml_dispatch_t eml;
351: vm_size_t vector_size, size;
352: vm_offset_t addr;
353:
354: if (task == TASK_NULL)
355: return EML_BAD_TASK;
356:
357: addr = 0;
358: size = 0;
359:
360: for(;;) {
361: vm_size_t size_needed;
362:
363: task_lock(task);
364: eml = task->eml_dispatch;
365: if (eml == EML_DISPATCH_NULL) {
366: task_unlock(task);
367: if (addr)
368: (void) kmem_free(ipc_kernel_map, addr, size);
369: *vector_start = 0;
370: *emulation_vector = 0;
371: *emulation_vector_count = 0;
372: return KERN_SUCCESS;
373: }
374:
375: /*
376: * Do we have the memory we need?
377: */
378: vector_size = eml->disp_count * sizeof(vm_offset_t);
379:
380: size_needed = round_page(vector_size);
381: if (size_needed <= size)
382: break;
383:
384: /*
385: * If not, unlock the task and allocate more memory.
386: */
387: task_unlock(task);
388:
389: if (size != 0)
390: kmem_free(ipc_kernel_map, addr, size);
391:
392: size = size_needed;
393: if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS)
394: return KERN_RESOURCE_SHORTAGE;
395: }
396:
397: /*
398: * Copy out the dispatch addresses
399: */
400: *vector_start = eml->disp_min;
401: *emulation_vector_count = eml->disp_count;
1.1.1.2 root 402: memcpy((void *)addr,
403: eml->disp_vector,
404: vector_size);
1.1 root 405:
406: /*
407: * Unlock the task and free any memory we did not need
408: */
409: task_unlock(task);
410:
411: {
412: vm_size_t size_used, size_left;
413: vm_map_copy_t memory;
414:
415: /*
416: * Free any unused memory beyond the end of the last page used
417: */
418: size_used = round_page(vector_size);
419: if (size_used != size)
420: (void) kmem_free(ipc_kernel_map,
421: addr + size_used,
422: size - size_used);
423:
424: /*
425: * Zero the remainder of the page being returned.
426: */
427: size_left = size_used - vector_size;
428: if (size_left > 0)
1.1.1.2 root 429: memset((char *)addr + vector_size, 0, size_left);
1.1 root 430:
431: /*
432: * Make memory into copyin form - this unwires it.
433: */
434: (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory);
435:
436: *emulation_vector = (emulation_vector_t) memory;
437: }
438:
439: return KERN_SUCCESS;
440: }
441:
442: /*
443: * task_set_emulation: [Server Entry]
444: * set up for user space emulation of syscalls within this task.
445: */
1.1.1.3 ! root 446: kern_return_t task_set_emulation(
! 447: task_t task,
! 448: vm_offset_t routine_entry_pt,
! 449: int routine_number)
1.1 root 450: {
451: return task_set_emulation_vector_internal(task, routine_number,
452: &routine_entry_pt, 1);
453: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.