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