|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute 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: #include <mach/boolean.h>
52: #include <mach/port.h>
53: #include <mach/message.h>
54: #include <mach/thread_status.h>
55: #include <kern/ast.h>
56: #include <kern/ipc_tt.h>
57: #include <kern/thread.h>
58: #include <kern/task.h>
59: #include <kern/ipc_kobject.h>
60: #include <vm/vm_map.h>
61: #include <vm/vm_user.h>
62: #include <ipc/port.h>
63: #include <ipc/ipc_kmsg.h>
64: #include <ipc/ipc_entry.h>
65: #include <ipc/ipc_object.h>
66: #include <ipc/ipc_mqueue.h>
67: #include <ipc/ipc_space.h>
68: #include <ipc/ipc_port.h>
69: #include <ipc/ipc_pset.h>
70: #include <ipc/ipc_thread.h>
71:
72:
73: /*
74: * Routine: mach_msg_send_from_kernel
75: * Purpose:
76: * Send a message from the kernel.
77: *
78: * This is used by the client side of KernelUser interfaces
79: * to implement SimpleRoutines. Currently, this includes
80: * device_reply and memory_object messages.
81: * Conditions:
82: * Nothing locked.
83: * Returns:
84: * MACH_MSG_SUCCESS Sent the message.
85: * MACH_SEND_INVALID_DATA Bad destination port.
86: */
87:
88: mach_msg_return_t
89: mach_msg_send_from_kernel(msg, send_size)
90: mach_msg_header_t *msg;
91: mach_msg_size_t send_size;
92: {
93: ipc_kmsg_t kmsg;
94: mach_msg_return_t mr;
95:
96: if (!MACH_PORT_VALID(msg->msgh_remote_port))
97: return MACH_SEND_INVALID_DEST;
98:
99: mr = ipc_kmsg_get_from_kernel(msg, MACH_MSG_OPTION_NONE,
100: send_size, MAX_TRAILER_SIZE,
101: &kmsg);
102: if (mr != MACH_MSG_SUCCESS)
103: panic("mach_msg_send_from_kernel");
104:
105: ipc_kmsg_copyin_from_kernel(kmsg);
106: ipc_mqueue_send_always(kmsg);
107:
108: return MACH_MSG_SUCCESS;
109: }
110:
111: /*
112: * Routine: mach_msg_abort_rpc
113: * Purpose:
114: * Destroy the thread's ith_rpc_reply port.
115: * This will interrupt a mach_msg_rpc_from_kernel
116: * with a MACH_RCV_PORT_DIED return code.
117: * Conditions:
118: * Nothing locked.
119: */
120:
121: void
122: mach_msg_abort_rpc(thread)
123: ipc_thread_t thread;
124: {
125: ipc_port_t reply = IP_NULL;
126:
127: ith_lock(thread);
128: if (thread->ith_self != IP_NULL) {
129: reply = thread->ith_rpc_reply;
130: thread->ith_rpc_reply = IP_NULL;
131: }
132: ith_unlock(thread);
133:
134: if (reply != IP_NULL)
135: ipc_port_dealloc_reply(reply);
136: }
137:
138: msg_return_t
139: msg_send_from_kernel(msg, option, time_out)
140: msg_header_t *msg;
141: msg_option_t option;
142: msg_timeout_t time_out;
143: {
144: msg_size_t send_size = msg->msg_size;
145: ipc_kmsg_t kmsg;
146: integer_t send_delta = send_size;
147: mach_msg_return_t mr;
148:
149: send_size = (send_size + 3) & ~3; /* round up */
150: send_delta -= send_size;
151:
152: mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
153: MACH_MSG_OPTION_NONE,
154: (mach_msg_size_t) send_size,
155: send_delta,
156: &kmsg);
157: if (mr != MACH_MSG_SUCCESS)
158: return msg_return_translate(mr);
159:
160: ipc_kmsg_copyin_compat_from_kernel(kmsg);
161: if (option & SEND_NOTIFY) {
162: panic("msg_send_from_kernel");
163: } else
164: mr = ipc_mqueue_send(kmsg,
165: ((option & SEND_TIMEOUT) ?
166: MACH_SEND_TIMEOUT :
167: MACH_MSG_OPTION_NONE) |
168: MACH_SEND_ALWAYS | MACH_SEND_SWITCH,
169: (mach_msg_timeout_t) time_out,
170: IMQ_NULL_CONTINUE);
171:
172: if (mr != MACH_MSG_SUCCESS)
173: ipc_kmsg_destroy(kmsg);
174:
175: return msg_return_translate(mr);
176: }
177:
178: msg_return_t
179: msg_send(msg, option, time_out)
180: msg_header_t *msg;
181: msg_option_t option;
182: msg_timeout_t time_out;
183: {
184: ipc_space_t space = current_space();
185: vm_map_t map = current_map();
186: msg_size_t send_size = msg->msg_size;
187: ipc_kmsg_t kmsg;
188: integer_t send_delta = send_size;
189: mach_msg_return_t mr;
190:
191: send_size = (send_size + 3) & ~3; /* round up */
192: send_delta -= send_size;
193:
194: if (send_size > MSG_SIZE_MAX)
195: return SEND_MSG_TOO_LARGE;
196:
197: mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
198: MACH_MSG_OPTION_NONE,
199: (mach_msg_size_t) send_size,
200: send_delta,
201: &kmsg);
202: if (mr != MACH_MSG_SUCCESS)
203: return msg_return_translate(mr);
204:
205: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
206: if (mr != MACH_MSG_SUCCESS) {
207: ikm_free(kmsg);
208: return msg_return_translate(mr);
209: }
210: if (option & SEND_NOTIFY) {
211: panic("msg_send notify");
212: } else
213: do {
214: if (option & SEND_SWITCH)
215: mr = ipc_mqueue_send(kmsg,
216: ((option & SEND_TIMEOUT) ?
217: MACH_SEND_TIMEOUT :
218: MACH_MSG_OPTION_NONE) |
219: MACH_SEND_SWITCH,
220: (mach_msg_timeout_t) time_out,
221: IMQ_NULL_CONTINUE);
222: else
223: mr = ipc_mqueue_send(kmsg,
224: ((option & SEND_TIMEOUT) ?
225: MACH_SEND_TIMEOUT :
226: MACH_MSG_OPTION_NONE),
227: (mach_msg_timeout_t) time_out,
228: IMQ_NULL_CONTINUE);
229: if (mr == MACH_SEND_INTERRUPTED) {
230: while (thread_should_halt(current_thread()))
231: thread_halt_self_with_continuation(
232: (void (*)(void)) 0);
233:
234: if (option & SEND_INTERRUPT)
235: break;
236: }
237: } while (mr == MACH_SEND_INTERRUPTED);
238:
239: if (mr != MACH_MSG_SUCCESS)
240: ipc_kmsg_destroy(kmsg);
241:
242: return msg_return_translate(mr);
243: }
244:
245: msg_return_t
246: msg_receive(msg, option, time_out)
247: msg_header_t *msg;
248: msg_option_t option;
249: msg_timeout_t time_out;
250: {
251: ipc_space_t space = current_space();
252: vm_map_t map = current_map();
253: port_name_t rcv_name = msg->msg_local_port;
254: msg_size_t rcv_size = msg->msg_size;
255: ipc_object_t object;
256: ipc_mqueue_t mqueue;
257: ipc_kmsg_t kmsg;
258: mach_port_seqno_t seqno;
259: mach_msg_return_t mr;
260:
261: do {
262: mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
263: &mqueue, &object);
264: if (mr != MACH_MSG_SUCCESS)
265: return msg_return_translate(mr);
266: /* hold ref for object; mqueue is locked */
267:
268: mr = ipc_mqueue_receive(mqueue,
269: ((option & RCV_TIMEOUT) ?
270: MACH_RCV_TIMEOUT :
271: MACH_MSG_OPTION_NONE) |
272: MACH_RCV_OLD_FORMAT,
273: (option & RCV_LARGE) ?
274: (mach_msg_size_t) rcv_size :
275: MACH_MSG_SIZE_MAX,
276: (mach_msg_timeout_t) time_out,
277: FALSE, IMQ_NULL_CONTINUE,
278: &kmsg, &seqno, 0);
279: /* mqueue is unlocked */
280: ipc_object_release(object);
281: if (mr == MACH_RCV_INTERRUPTED) {
282: while (thread_should_halt(current_thread()))
283: thread_halt_self_with_continuation(
284: (void (*)(void)) 0);
285:
286: if (option & RCV_INTERRUPT)
287: break;
288: }
289: } while (mr == MACH_RCV_INTERRUPTED);
290: if (mr != MACH_MSG_SUCCESS) {
291: if (mr == MACH_RCV_TOO_LARGE) {
292: msg_size_t real_size =
293: (msg_size_t) (mach_msg_size_t) kmsg;
294:
295: assert(real_size > rcv_size);
296:
297: msg->msg_size = real_size;
298: }
299:
300: return msg_return_translate(mr);
301: }
302:
303: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
304: assert(!(option & RCV_LARGE));
305:
306: ipc_kmsg_destroy(kmsg);
307: return msg_return_translate(MACH_RCV_TOO_LARGE);
308: }
309:
310: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
311:
312: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
313: assert(mr == MACH_MSG_SUCCESS);
314:
315: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
316: ipc_kmsg_put_to_kernel((mach_msg_header_t *) msg, kmsg,
317: kmsg->ikm_header.msgh_size);
318: return msg_return_translate(mr);
319: }
320:
321: msg_return_t
322: msg_rpc(msg, option, rcv_size, send_timeout, rcv_timeout)
323: msg_header_t *msg; /* in/out */
324: msg_option_t option;
325: msg_size_t rcv_size;
326: msg_timeout_t send_timeout;
327: msg_timeout_t rcv_timeout;
328: {
329: ipc_space_t space = current_space();
330: vm_map_t map = current_map();
331: msg_size_t send_size = msg->msg_size;
332: ipc_port_t reply;
333: ipc_pset_t pset;
334: ipc_mqueue_t mqueue;
335: ipc_kmsg_t kmsg;
336: integer_t send_delta = send_size;
337: mach_port_seqno_t seqno;
338: mach_msg_return_t mr;
339:
340: /*
341: * Instead of using msg_send and msg_receive,
342: * we implement msg_rpc directly. The difference
343: * is how the reply port is handled. Instead of using
344: * ipc_mqueue_copyin, we save a reference for the reply
345: * port carried in the sent message. For example,
346: * consider a rename kernel call which changes the name
347: * of the call's own reply port. This is the behaviour
348: * of the Mach 2.5 msg_rpc_trap.
349: */
350:
351: send_size = (send_size + 3) & ~3; /* round up */
352: send_delta -= send_size;
353:
354: if (send_size > MSG_SIZE_MAX)
355: return SEND_MSG_TOO_LARGE;
356:
357: mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
358: MACH_MSG_OPTION_NONE,
359: (mach_msg_size_t) send_size,
360: send_delta,
361: &kmsg);
362: if (mr != MACH_MSG_SUCCESS)
363: return msg_return_translate(mr);
364:
365: mr = ipc_kmsg_copyin_compat(kmsg, space, map);
366: if (mr != MACH_MSG_SUCCESS) {
367: ikm_free(kmsg);
368: return msg_return_translate(mr);
369: }
370:
371: reply = (ipc_port_t)kmsg->ikm_header.msgh_local_port;
372: if (IP_VALID(reply)) {
373: ipc_port_t dest = (ipc_port_t)
374: kmsg->ikm_header.msgh_remote_port;
375:
376: ipc_port_reference(reply);
377: assert(IP_VALID(dest));
378:
379: ip_lock(dest);
380:
381: if (dest->ip_receiver == ipc_space_kernel) {
382: ipc_mqueue_t mqueue;
383:
384: assert(ip_active(dest));
385: ip_unlock(dest);
386:
387: kmsg = ipc_kobject_server(kmsg);
388: if (kmsg == IKM_NULL)
389: goto receive_reply;
390:
391: ip_lock(reply);
392:
393: if ((!ip_active(reply)) ||
394: (reply->ip_receiver != space) ||
395: (reply->ip_pset != IPS_NULL) ||
396: (rcv_size < (kmsg->ikm_header.msgh_size +
397: kmsg->ikm_delta)))
398: {
399: ip_unlock(reply);
400: ipc_mqueue_send_always(kmsg);
401: goto receive_reply;
402: }
403:
404: mqueue = &reply->ip_messages;
405: imq_lock(mqueue);
406:
407: if ((ipc_thread_queue_first(&mqueue->imq_threads)
408: != ITH_NULL) ||
409: (ipc_kmsg_queue_first(&mqueue->imq_messages)
410: != IKM_NULL))
411: {
412: imq_unlock(mqueue);
413: ip_unlock(reply);
414: ipc_mqueue_send_always(kmsg);
415: goto receive_reply;
416: }
417:
418: assert(kmsg->ikm_marequest == IMAR_NULL);
419: assert(ipc_thread_queue_first(&reply->ip_blocked)
420: == ITH_NULL);
421:
422: reply->ip_seqno++;
423: imq_unlock(mqueue);
424:
425: ip_release(reply);
426: ip_unlock(reply);
427:
428: goto copyout_reply;
429: }
430:
431: ip_unlock(dest);
432: }
433:
434: if (option & SEND_NOTIFY) {
435: panic("msg_rpc notify");
436: } else
437: do {
438: if (option & SEND_SWITCH)
439: mr = ipc_mqueue_send(kmsg,
440: ((option & SEND_TIMEOUT) ?
441: MACH_SEND_TIMEOUT :
442: MACH_MSG_OPTION_NONE) |
443: MACH_SEND_SWITCH,
444: (mach_msg_timeout_t)
445: send_timeout,
446: IMQ_NULL_CONTINUE);
447: else
448: mr = ipc_mqueue_send(kmsg,
449: ((option & SEND_TIMEOUT) ?
450: MACH_SEND_TIMEOUT :
451: MACH_MSG_OPTION_NONE),
452: (mach_msg_timeout_t)
453: send_timeout,
454: IMQ_NULL_CONTINUE);
455: if (mr == MACH_SEND_INTERRUPTED) {
456: while (thread_should_halt(current_thread()))
457: thread_halt_self_with_continuation(
458: (void (*)(void)) 0);
459:
460: if (option & SEND_INTERRUPT)
461: break;
462: }
463: } while (mr == MACH_SEND_INTERRUPTED);
464:
465: if (mr != MACH_MSG_SUCCESS) {
466: ipc_kmsg_destroy(kmsg);
467: if (IP_VALID(reply))
468: ipc_port_release(reply);
469: return msg_return_translate(mr);
470: }
471:
472: receive_reply:
473: if (!IP_VALID(reply))
474: return RCV_INVALID_PORT;
475:
476: ip_lock(reply);
477: if (reply->ip_receiver != space) {
478: ip_release(reply);
479: ip_check_unlock(reply);
480: return RCV_INVALID_PORT;
481: }
482:
483: assert(ip_active(reply));
484: pset = reply->ip_pset;
485:
486: if (pset != IPS_NULL) {
487: ips_lock(pset);
488: if (ips_active(pset)) {
489: ips_unlock(pset);
490: ip_release(reply);
491: ip_unlock(reply);
492: return RCV_INVALID_PORT;
493: }
494:
495: ipc_pset_remove(pset, reply);
496: ips_check_unlock(pset);
497: assert(reply->ip_pset == IPS_NULL);
498: }
499:
500: mqueue = &reply->ip_messages;
501: imq_lock(mqueue);
502: ip_unlock(reply);
503:
504: mr = ipc_mqueue_receive(mqueue,
505: ((option & RCV_TIMEOUT) ?
506: MACH_RCV_TIMEOUT :
507: MACH_MSG_OPTION_NONE) |
508: MACH_RCV_OLD_FORMAT,
509: (option & RCV_LARGE) ?
510: (mach_msg_size_t) rcv_size :
511: MACH_MSG_SIZE_MAX,
512: (mach_msg_timeout_t) rcv_timeout,
513: FALSE, IMQ_NULL_CONTINUE,
514: &kmsg, &seqno, 0);
515: /* mqueue is unlocked */
516: ipc_port_release(reply);
517: if (mr != MACH_MSG_SUCCESS) {
518: if (mr == MACH_RCV_INTERRUPTED) {
519: while (thread_should_halt(current_thread()))
520: thread_halt_self_with_continuation(
521: (void (*)(void)) 0);
522:
523: msg->msg_size = rcv_size; /* XXX */
524:
525: if (!(option & RCV_INTERRUPT))
526: return msg_receive(msg, option, rcv_timeout);
527: } else if (mr == MACH_RCV_TOO_LARGE) {
528: msg_size_t real_size =
529: (msg_size_t) (mach_msg_size_t) kmsg;
530:
531: assert(real_size > rcv_size);
532:
533: msg->msg_size = real_size;
534: }
535:
536: return msg_return_translate(mr);
537: }
538:
539: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
540: assert(!(option & RCV_LARGE));
541:
542: ipc_kmsg_destroy(kmsg);
543: return msg_return_translate(MACH_RCV_TOO_LARGE);
544: }
545:
546: copyout_reply:
547: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
548:
549: mr = ipc_kmsg_copyout_compat(kmsg, space, map);
550: assert(mr == MACH_MSG_SUCCESS);
551:
552: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
553: ipc_kmsg_put_to_kernel((mach_msg_header_t *) msg, kmsg,
554: kmsg->ikm_header.msgh_size);
555: return msg_return_translate(mr);
556:
557: }
558:
559: /*
560: * Routine: mig_get_reply_port
561: * Purpose:
562: * Called by client side interfaces living in the kernel
563: * to get a reply port. This port is used for
564: * mach_msg() calls which are kernel calls.
565: */
566:
567: mach_port_t
568: mig_get_reply_port()
569: {
570: ipc_thread_t self = current_thread();
571:
572: if (self->ith_mig_reply == MACH_PORT_NULL)
573: self->ith_mig_reply = mach_reply_port();
574:
575: return self->ith_mig_reply;
576: }
577:
578: /*
579: * Routine: mig_dealloc_reply_port
580: * Purpose:
581: * Called by client side interfaces to get rid of a reply port.
582: * Shouldn't ever be called inside the kernel, because
583: * kernel calls shouldn't prompt Mig to call it.
584: */
585:
586: void
587: mig_dealloc_reply_port()
588: {
589: panic("mig_dealloc_reply_port");
590: }
591:
592: /*
593: * mig_strncpy.c - by Joshua Block
594: *
595: * mig_strncp -- Bounded string copy. Does what the library routine strncpy
596: * OUGHT to do: Copies the (null terminated) string in src into dest, a
597: * buffer of length len. Assures that the copy is still null terminated
598: * and doesn't overflow the buffer, truncating the copy if necessary.
599: *
600: * Parameters:
601: *
602: * dest - Pointer to destination buffer.
603: *
604: * src - Pointer to source string.
605: *
606: * len - Length of destination buffer.
607: */
608: vm_size_t mig_strncpy(
609: char *dest,
610: const char *src,
611: vm_size_t len)
612: {
613: vm_size_t i;
614:
615: if (len <= 0)
616: return 0;
617:
618: for (i=1; i<len; i++)
619: if (! (*dest++ = *src++))
620: return i;
621:
622: *dest = '\0';
623: return i;
624: }
625:
626: #if 0
627:
628: #define fast_send_right_lookup(name, port, abort) \
629: MACRO_BEGIN \
630: register ipc_space_t space = current_space(); \
631: register ipc_entry_t entry; \
632: register mach_port_index_t index = MACH_PORT_INDEX(name); \
633: \
634: is_read_lock(space); \
635: assert(space->is_active); \
636: \
637: if ((index >= space->is_table_size) || \
638: (((entry = &space->is_table[index])->ie_bits & \
639: (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != \
640: (MACH_PORT_GEN(name) | MACH_PORT_TYPE_SEND))) { \
641: is_read_unlock(space); \
642: abort; \
643: } \
644: \
645: port = (ipc_port_t) entry->ie_object; \
646: assert(port != IP_NULL); \
647: \
648: ip_lock(port); \
649: /* can safely unlock space now that port is locked */ \
650: is_read_unlock(space); \
651: MACRO_END
652:
653: thread_t
654: port_name_to_thread(name)
655: mach_port_t name;
656: {
657: register ipc_port_t port;
658:
659: fast_send_right_lookup(name, port, goto abort);
660: /* port is locked */
661:
662: if (ip_active(port) &&
663: (ip_kotype(port) == IKOT_THREAD)) {
664: register thread_t thread;
665:
666: thread = (thread_t) port->ip_kobject;
667: assert(thread != THREAD_NULL);
668:
669: /* thread referencing is a bit complicated,
670: so don't bother to expand inline */
671: thread_reference(thread);
672: ip_unlock(port);
673:
674: return thread;
675: }
676:
677: ip_unlock(port);
678: return THREAD_NULL;
679:
680: abort: {
681: thread_t thread;
682: ipc_port_t kern_port;
683: kern_return_t kr;
684:
685: kr = ipc_object_copyin(current_space(), name,
686: MACH_MSG_TYPE_COPY_SEND,
687: (ipc_object_t *) &kern_port);
688: if (kr != KERN_SUCCESS)
689: return THREAD_NULL;
690:
691: thread = convert_port_to_thread(kern_port);
692: if (IP_VALID(kern_port))
693: ipc_port_release_send(kern_port);
694:
695: return thread;
696: }
697: }
698:
699: task_t
700: port_name_to_task(name)
701: mach_port_t name;
702: {
703: register ipc_port_t port;
704:
705: fast_send_right_lookup(name, port, goto abort);
706: /* port is locked */
707:
708: if (ip_active(port) &&
709: (ip_kotype(port) == IKOT_TASK)) {
710: register task_t task;
711:
712: task = (task_t) port->ip_kobject;
713: assert(task != TASK_NULL);
714:
715: task_lock(task);
716: /* can safely unlock port now that task is locked */
717: ip_unlock(port);
718:
719: task->ref_count++;
720: task_unlock(task);
721:
722: return task;
723: }
724:
725: ip_unlock(port);
726: return TASK_NULL;
727:
728: abort: {
729: task_t task;
730: ipc_port_t kern_port;
731: kern_return_t kr;
732:
733: kr = ipc_object_copyin(current_space(), name,
734: MACH_MSG_TYPE_COPY_SEND,
735: (ipc_object_t *) &kern_port);
736: if (kr != KERN_SUCCESS)
737: return TASK_NULL;
738:
739: task = convert_port_to_task(kern_port);
740: if (IP_VALID(kern_port))
741: ipc_port_release_send(kern_port);
742:
743: return task;
744: }
745: }
746:
747: vm_map_t
748: port_name_to_map(name)
749: mach_port_t name;
750: {
751: register ipc_port_t port;
752:
753: fast_send_right_lookup(name, port, goto abort);
754: /* port is locked */
755:
756: if (ip_active(port) &&
757: (ip_kotype(port) == IKOT_TASK)) {
758: register vm_map_t map;
759:
760: map = ((task_t) port->ip_kobject)->map;
761: assert(map != VM_MAP_NULL);
762:
763: simple_lock(&map->ref_lock);
764: /* can safely unlock port now that map is locked */
765: ip_unlock(port);
766:
767: map->ref_count++;
768: simple_unlock(&map->ref_lock);
769:
770: return map;
771: }
772:
773: ip_unlock(port);
774: return VM_MAP_NULL;
775:
776: abort: {
777: vm_map_t map;
778: ipc_port_t kern_port;
779: kern_return_t kr;
780:
781: kr = ipc_object_copyin(current_space(), name,
782: MACH_MSG_TYPE_COPY_SEND,
783: (ipc_object_t *) &kern_port);
784: if (kr != KERN_SUCCESS)
785: return VM_MAP_NULL;
786:
787: map = convert_port_to_map(kern_port);
788: if (IP_VALID(kern_port))
789: ipc_port_release_send(kern_port);
790:
791: return map;
792: }
793: }
794:
795: ipc_space_t
796: port_name_to_space(name)
797: mach_port_t name;
798: {
799: register ipc_port_t port;
800:
801: fast_send_right_lookup(name, port, goto abort);
802: /* port is locked */
803:
804: if (ip_active(port) &&
805: (ip_kotype(port) == IKOT_TASK)) {
806: register ipc_space_t space;
807:
808: space = ((task_t) port->ip_kobject)->itk_space;
809: assert(space != IS_NULL);
810:
811: simple_lock(&space->is_ref_lock_data);
812: /* can safely unlock port now that space is locked */
813: ip_unlock(port);
814:
815: space->is_references++;
816: simple_unlock(&space->is_ref_lock_data);
817:
818: return space;
819: }
820:
821: ip_unlock(port);
822: return IS_NULL;
823:
824: abort: {
825: ipc_space_t space;
826: ipc_port_t kern_port;
827: kern_return_t kr;
828:
829: kr = ipc_object_copyin(current_space(), name,
830: MACH_MSG_TYPE_COPY_SEND,
831: (ipc_object_t *) &kern_port);
832: if (kr != KERN_SUCCESS)
833: return IS_NULL;
834:
835: space = convert_port_to_space(kern_port);
836: if (IP_VALID(kern_port))
837: ipc_port_release_send(kern_port);
838:
839: return space;
840: }
841: }
842:
843: /*
844: * Hack to translate a thread port to a thread pointer for calling
845: * thread_get_state and thread_set_state. This is only necessary
846: * because the IPC message for these two operations overflows the
847: * kernel stack.
848: *
849: * AARGH!
850: */
851:
852: kern_return_t thread_get_state_KERNEL(thread_port, flavor,
853: old_state, old_state_count)
854: mach_port_t thread_port; /* port right for thread */
855: int flavor;
856: thread_state_t old_state; /* pointer to OUT array */
857: natural_t *old_state_count; /* IN/OUT */
858: {
859: thread_t thread;
860: kern_return_t result;
861:
862: thread = port_name_to_thread(thread_port);
863: result = thread_get_state(thread, flavor, old_state, old_state_count);
864: thread_deallocate(thread);
865:
866: return result;
867: }
868:
869: kern_return_t thread_set_state_KERNEL(thread_port, flavor,
870: new_state, new_state_count)
871: mach_port_t thread_port; /* port right for thread */
872: int flavor;
873: thread_state_t new_state;
874: natural_t new_state_count;
875: {
876: thread_t thread;
877: kern_return_t result;
878:
879: thread = port_name_to_thread(thread_port);
880: result = thread_set_state(thread, flavor, new_state, new_state_count);
881: thread_deallocate(thread);
882:
883: return result;
884: }
885:
886: /*
887: * Things to keep in mind:
888: *
889: * The idea here is to duplicate the semantics of the true kernel RPC.
890: * The destination port/object should be checked first, before anything
891: * that the user might notice (like ipc_object_copyin). Return
892: * MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
893: * knows to fall back on an RPC. For other return values, it won't
894: * retry with an RPC. The retry might get a different (incorrect) rc.
895: * Return values are only set (and should only be set, with copyout)
896: * on successfull calls.
897: */
898:
899: kern_return_t syscall_vm_map(
900: target_map,
901: address, size, mask, anywhere,
902: memory_object, offset,
903: copy,
904: cur_protection, max_protection, inheritance)
905: mach_port_t target_map;
906: vm_offset_t *address;
907: vm_size_t size;
908: vm_offset_t mask;
909: boolean_t anywhere;
910: mach_port_t memory_object;
911: vm_offset_t offset;
912: boolean_t copy;
913: vm_prot_t cur_protection;
914: vm_prot_t max_protection;
915: vm_inherit_t inheritance;
916: {
917: vm_map_t map;
918: ipc_port_t port;
919: vm_offset_t addr;
920: kern_return_t result;
921:
922: map = port_name_to_map(target_map);
923: if (map == VM_MAP_NULL)
924: return MACH_SEND_INTERRUPTED;
925:
926: if (MACH_PORT_VALID(memory_object)) {
927: result = ipc_object_copyin(current_space(), memory_object,
928: MACH_MSG_TYPE_COPY_SEND,
929: (ipc_object_t *) &port);
930: if (result != KERN_SUCCESS) {
931: vm_map_deallocate(map);
932: return result;
933: }
934: } else
935: port = (ipc_port_t) memory_object;
936:
937: copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
938: result = vm_map(map, &addr, size, mask, anywhere,
939: port, offset, copy,
940: cur_protection, max_protection, inheritance);
941: if (result == KERN_SUCCESS)
942: copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
943: if (IP_VALID(port))
944: ipc_port_release_send(port);
945: vm_map_deallocate(map);
946:
947: return result;
948: }
949:
950: kern_return_t syscall_vm_allocate(target_map, address, size, anywhere)
951: mach_port_t target_map;
952: vm_offset_t *address;
953: vm_size_t size;
954: boolean_t anywhere;
955: {
956: vm_map_t map;
957: vm_offset_t addr;
958: kern_return_t result;
959:
960: map = port_name_to_map(target_map);
961: if (map == VM_MAP_NULL)
962: return MACH_SEND_INTERRUPTED;
963:
964: copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
965: result = vm_allocate(map, &addr, size, anywhere);
966: if (result == KERN_SUCCESS)
967: copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
968: vm_map_deallocate(map);
969:
970: return result;
971: }
972:
973: kern_return_t syscall_vm_deallocate(target_map, start, size)
974: mach_port_t target_map;
975: vm_offset_t start;
976: vm_size_t size;
977: {
978: vm_map_t map;
979: kern_return_t result;
980:
981: map = port_name_to_map(target_map);
982: if (map == VM_MAP_NULL)
983: return MACH_SEND_INTERRUPTED;
984:
985: result = vm_deallocate(map, start, size);
986: vm_map_deallocate(map);
987:
988: return result;
989: }
990:
991: kern_return_t syscall_task_create(parent_task, inherit_memory, child_task)
992: mach_port_t parent_task;
993: boolean_t inherit_memory;
994: mach_port_t *child_task; /* OUT */
995: {
996: task_t t, c;
997: ipc_port_t port;
998: mach_port_t name;
999: kern_return_t result;
1000:
1001: t = port_name_to_task(parent_task);
1002: if (t == TASK_NULL)
1003: return MACH_SEND_INTERRUPTED;
1004:
1005: result = task_create(t, inherit_memory, &c);
1006: if (result == KERN_SUCCESS) {
1007: port = (ipc_port_t) convert_task_to_port(c);
1008: /* always returns a name, even for non-success return codes */
1009: (void) ipc_kmsg_copyout_object(current_space(),
1010: (ipc_object_t) port,
1011: MACH_MSG_TYPE_PORT_SEND, &name);
1012: copyout((char *)&name, (char *)child_task,
1013: sizeof(mach_port_t));
1014: }
1015: task_deallocate(t);
1016:
1017: return result;
1018: }
1019:
1020: kern_return_t syscall_task_terminate(task)
1021: mach_port_t task;
1022: {
1023: task_t t;
1024: kern_return_t result;
1025:
1026: t = port_name_to_task(task);
1027: if (t == TASK_NULL)
1028: return MACH_SEND_INTERRUPTED;
1029:
1030: result = task_terminate(t);
1031: task_deallocate(t);
1032:
1033: return result;
1034: }
1035:
1036: kern_return_t syscall_task_suspend(task)
1037: mach_port_t task;
1038: {
1039: task_t t;
1040: kern_return_t result;
1041:
1042: t = port_name_to_task(task);
1043: if (t == TASK_NULL)
1044: return MACH_SEND_INTERRUPTED;
1045:
1046: result = task_suspend(t);
1047: task_deallocate(t);
1048:
1049: return result;
1050: }
1051:
1052: kern_return_t syscall_task_set_special_port(task, which_port, port_name)
1053: mach_port_t task;
1054: int which_port;
1055: mach_port_t port_name;
1056: {
1057: task_t t;
1058: ipc_port_t port;
1059: kern_return_t result;
1060:
1061: t = port_name_to_task(task);
1062: if (t == TASK_NULL)
1063: return MACH_SEND_INTERRUPTED;
1064:
1065: if (MACH_PORT_VALID(port_name)) {
1066: result = ipc_object_copyin(current_space(), port_name,
1067: MACH_MSG_TYPE_COPY_SEND,
1068: (ipc_object_t *) &port);
1069: if (result != KERN_SUCCESS) {
1070: task_deallocate(t);
1071: return result;
1072: }
1073: } else
1074: port = (ipc_port_t) port_name;
1075:
1076: result = task_set_special_port(t, which_port, port);
1077: if ((result != KERN_SUCCESS) && IP_VALID(port))
1078: ipc_port_release_send(port);
1079: task_deallocate(t);
1080:
1081: return result;
1082: }
1083:
1084: kern_return_t
1085: syscall_mach_port_allocate(task, right, namep)
1086: mach_port_t task;
1087: mach_port_right_t right;
1088: mach_port_t *namep;
1089: {
1090: ipc_space_t space;
1091: mach_port_t name;
1092: kern_return_t kr;
1093:
1094: space = port_name_to_space(task);
1095: if (space == IS_NULL)
1096: return MACH_SEND_INTERRUPTED;
1097:
1098: kr = mach_port_allocate(space, right, &name);
1099: if (kr == KERN_SUCCESS)
1100: copyout((char *)&name, (char *)namep, sizeof(mach_port_t));
1101: is_release(space);
1102:
1103: return kr;
1104: }
1105:
1106: kern_return_t
1107: syscall_mach_port_allocate_name(task, right, name)
1108: mach_port_t task;
1109: mach_port_right_t right;
1110: mach_port_t name;
1111: {
1112: ipc_space_t space;
1113: kern_return_t kr;
1114:
1115: space = port_name_to_space(task);
1116: if (space == IS_NULL)
1117: return MACH_SEND_INTERRUPTED;
1118:
1119: kr = mach_port_allocate_name(space, right, name);
1120: is_release(space);
1121:
1122: return kr;
1123: }
1124:
1125: kern_return_t
1126: syscall_mach_port_deallocate(task, name)
1127: mach_port_t task;
1128: mach_port_t name;
1129: {
1130: ipc_space_t space;
1131: kern_return_t kr;
1132:
1133: space = port_name_to_space(task);
1134: if (space == IS_NULL)
1135: return MACH_SEND_INTERRUPTED;
1136:
1137: kr = mach_port_deallocate(space, name);
1138: is_release(space);
1139:
1140: return kr;
1141: }
1142:
1143: kern_return_t
1144: syscall_mach_port_insert_right(task, name, right, rightType)
1145: mach_port_t task;
1146: mach_port_t name;
1147: mach_port_t right;
1148: mach_msg_type_name_t rightType;
1149: {
1150: ipc_space_t space;
1151: ipc_object_t object;
1152: mach_msg_type_name_t newtype;
1153: kern_return_t kr;
1154:
1155: space = port_name_to_space(task);
1156: if (space == IS_NULL)
1157: return MACH_SEND_INTERRUPTED;
1158:
1159: if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
1160: is_release(space);
1161: return KERN_INVALID_VALUE;
1162: }
1163:
1164: if (MACH_PORT_VALID(right)) {
1165: kr = ipc_object_copyin(current_space(), right, rightType,
1166: &object);
1167: if (kr != KERN_SUCCESS) {
1168: is_release(space);
1169: return kr;
1170: }
1171: } else
1172: object = (ipc_object_t) right;
1173: newtype = ipc_object_copyin_type(rightType);
1174:
1175: kr = mach_port_insert_right(space, name, object, newtype);
1176: if ((kr != KERN_SUCCESS) && IO_VALID(object))
1177: ipc_object_destroy(object, newtype);
1178: is_release(space);
1179:
1180: return kr;
1181: }
1182:
1183: kern_return_t syscall_thread_depress_abort(thread)
1184: mach_port_t thread;
1185: {
1186: thread_t t;
1187: kern_return_t result;
1188:
1189: t = port_name_to_thread(thread);
1190: if (t == THREAD_NULL)
1191: return MACH_SEND_INTERRUPTED;
1192:
1193: result = thread_depress_abort(t);
1194: thread_deallocate(t);
1195:
1196: return result;
1197: }
1198:
1199: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.