|
|
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: */
60: void eml_init()
61: {
62: }
63:
64: /*
65: * eml_task_reference() [Exported]
66: *
67: * Bumps the reference count on the common emulation
68: * vector.
69: */
70:
71: void eml_task_reference(task, parent)
72: task_t task, parent;
73: {
74: register eml_dispatch_t eml;
75:
76: if (parent == TASK_NULL)
77: eml = EML_DISPATCH_NULL;
78: else
79: eml = parent->eml_dispatch;
80:
81: if (eml != EML_DISPATCH_NULL) {
82: simple_lock(&eml->lock);
83: eml->ref_count++;
84: simple_unlock(&eml->lock);
85: }
86: task->eml_dispatch = eml;
87: }
88:
89:
90: /*
91: * eml_task_deallocate() [Exported]
92: *
93: * Cleans up after the emulation code when a process exits.
94: */
95:
96: void eml_task_deallocate(task)
97: task_t task;
98: {
99: register eml_dispatch_t eml;
100:
101: eml = task->eml_dispatch;
102: if (eml != EML_DISPATCH_NULL) {
103: int count;
104:
105: simple_lock(&eml->lock);
106: count = --eml->ref_count;
107: simple_unlock(&eml->lock);
108:
109: if (count == 0)
110: kfree((vm_offset_t)eml, count_to_size(eml->disp_count));
111: }
112: }
113:
114: /*
115: * task_set_emulation_vector: [Server Entry]
116: * set a list of emulated system calls for this task.
117: */
118: kern_return_t
119: task_set_emulation_vector_internal(task, vector_start, emulation_vector,
120: emulation_vector_count)
121: task_t task;
122: int vector_start;
123: emulation_vector_t emulation_vector;
124: unsigned int emulation_vector_count;
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
298: task_set_emulation_vector(task, vector_start, emulation_vector,
299: emulation_vector_count)
300: task_t task;
301: int vector_start;
302: emulation_vector_t emulation_vector;
303: unsigned int emulation_vector_count;
304: {
305: kern_return_t kr;
306: vm_offset_t emul_vector_addr;
307:
308: if (task == TASK_NULL)
309: return EML_BAD_TASK; /* XXX sb KERN_INVALID_ARGUMENT */
310:
311: /*
312: * The emulation vector is really a vm_map_copy_t.
313: */
314: kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
315: (vm_map_copy_t) emulation_vector);
316: if (kr != KERN_SUCCESS)
317: return kr;
318:
319: /*
320: * Do the work.
321: */
322: kr = task_set_emulation_vector_internal(
323: task,
324: vector_start,
325: (emulation_vector_t) emul_vector_addr,
326: emulation_vector_count);
327:
328: /*
329: * Discard the memory
330: */
331: (void) kmem_free(ipc_kernel_map,
332: emul_vector_addr,
333: emulation_vector_count * sizeof(eml_dispatch_t));
334:
335: return kr;
336: }
337:
338: /*
339: * task_get_emulation_vector: [Server Entry]
340: *
341: * Get the list of emulated system calls for this task.
342: * List is returned out-of-line.
343: */
344: kern_return_t
345: task_get_emulation_vector(task, vector_start, emulation_vector,
346: emulation_vector_count)
347: task_t task;
348: int *vector_start; /* out */
349: emulation_vector_t *emulation_vector; /* out */
350: unsigned int *emulation_vector_count; /* out */
351: {
352: eml_dispatch_t eml;
353: vm_size_t vector_size, size;
354: vm_offset_t addr;
355:
356: if (task == TASK_NULL)
357: return EML_BAD_TASK;
358:
359: addr = 0;
360: size = 0;
361:
362: for(;;) {
363: vm_size_t size_needed;
364:
365: task_lock(task);
366: eml = task->eml_dispatch;
367: if (eml == EML_DISPATCH_NULL) {
368: task_unlock(task);
369: if (addr)
370: (void) kmem_free(ipc_kernel_map, addr, size);
371: *vector_start = 0;
372: *emulation_vector = 0;
373: *emulation_vector_count = 0;
374: return KERN_SUCCESS;
375: }
376:
377: /*
378: * Do we have the memory we need?
379: */
380: vector_size = eml->disp_count * sizeof(vm_offset_t);
381:
382: size_needed = round_page(vector_size);
383: if (size_needed <= size)
384: break;
385:
386: /*
387: * If not, unlock the task and allocate more memory.
388: */
389: task_unlock(task);
390:
391: if (size != 0)
392: kmem_free(ipc_kernel_map, addr, size);
393:
394: size = size_needed;
395: if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS)
396: return KERN_RESOURCE_SHORTAGE;
397: }
398:
399: /*
400: * Copy out the dispatch addresses
401: */
402: *vector_start = eml->disp_min;
403: *emulation_vector_count = eml->disp_count;
1.1.1.2 ! root 404: memcpy((void *)addr,
! 405: eml->disp_vector,
! 406: vector_size);
1.1 root 407:
408: /*
409: * Unlock the task and free any memory we did not need
410: */
411: task_unlock(task);
412:
413: {
414: vm_size_t size_used, size_left;
415: vm_map_copy_t memory;
416:
417: /*
418: * Free any unused memory beyond the end of the last page used
419: */
420: size_used = round_page(vector_size);
421: if (size_used != size)
422: (void) kmem_free(ipc_kernel_map,
423: addr + size_used,
424: size - size_used);
425:
426: /*
427: * Zero the remainder of the page being returned.
428: */
429: size_left = size_used - vector_size;
430: if (size_left > 0)
1.1.1.2 ! root 431: memset((char *)addr + vector_size, 0, size_left);
1.1 root 432:
433: /*
434: * Make memory into copyin form - this unwires it.
435: */
436: (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory);
437:
438: *emulation_vector = (emulation_vector_t) memory;
439: }
440:
441: return KERN_SUCCESS;
442: }
443:
444: /*
445: * task_set_emulation: [Server Entry]
446: * set up for user space emulation of syscalls within this task.
447: */
448: kern_return_t task_set_emulation(task, routine_entry_pt, routine_number)
449: task_t task;
450: vm_offset_t routine_entry_pt;
451: int routine_number;
452: {
453: return task_set_emulation_vector_internal(task, routine_number,
454: &routine_entry_pt, 1);
455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.