FreeBSD/Linux Kernel Cross Reference
sys/kern/ipc_mig.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990 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 Software.Distribution@CS.CMU.EDU
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 * HISTORY
28 * $Log: ipc_mig.c,v $
29 * Revision 2.23 93/11/17 17:11:36 dbg
30 * Moved syscall_timer_sleep to kern/mach_timer.c
31 * [93/07/21 dbg]
32 *
33 * Add traps for timers and real-time threads.
34 * [93/07/13 dbg]
35 *
36 * Use thread_lock instead of ith_lock.
37 * [93/07/12 dbg]
38 *
39 * Added ANSI function prototypes. Removed unneeded routines:
40 * thread_{get,set}_state_KERNEL. Conditionalized mach_msg,
41 * mig_get_reply_port, mig_dealloc_reply_port on NORMA_TASK
42 * || NORMA_VM.
43 * [93/03/30 dbg]
44 *
45 * Revision 2.22 93/08/10 15:11:34 mrt
46 * Fixed the case where device write traps are called with reply ports.
47 * [93/07/29 cmaeda]
48 *
49 * Device traps and scatter/gather IO (actually just gather IO) --
50 * Added port_name_to_device, syscall_device_write_request,
51 * and syscall_device_writev_request.
52 * (Original version of this code from rfr, many moons ago.)
53 * [93/04/14 cmaeda]
54 *
55 * Revision 2.21 93/03/26 17:54:47 mrt
56 * Merge botch got rid of the above.
57 * [93/03/23 af]
58 *
59 * Revision 2.20 93/01/14 17:34:34 danner
60 * 64bit cleanup.
61 * [92/12/01 af]
62 *
63 * Revision 2.19 92/08/03 17:37:30 jfriedl
64 * removed silly prototypes
65 * [92/08/02 jfriedl]
66 *
67 * Revision 2.18 92/05/21 17:13:55 jfriedl
68 * Removed unsed var 'addr' from syscall_vm_deallocate.
69 * [92/05/16 jfriedl]
70 *
71 * Revision 2.17 92/03/10 16:26:34 jsb
72 * Corrected log.
73 * [91/12/24 14:42:53 jsb]
74 *
75 * Revision 2.16 92/02/19 16:06:28 elf
76 * Added syscall_thread_depress_abort.
77 * [92/01/20 rwd]
78 *
79 * Revision 2.15 91/11/14 16:56:39 rpd
80 * Replaced call to ipc_kmsg_copyout_dest with ipc_kmsg_copyout_to_kernel
81 * in mach_msg_rpc_from_kernel, to preserve rights and memory.
82 * [91/11/00 jsb]
83 *
84 * Revision 2.14 91/08/28 11:14:34 jsb
85 * Fixed syscall_mach_port_insert_right and syscall_task_set_special_port
86 * to handle non-valid port names correctly.
87 * [91/08/15 rpd]
88 *
89 * Changed MACH_RCV_TOO_LARGE and MACH_RCV_INVALID_NOTIFY to work
90 * like MACH_RCV_HEADER_ERROR, using ipc_kmsg_copyout_dest.
91 * [91/08/12 rpd]
92 *
93 * Added seqno argument to ipc_mqueue_receive.
94 * [91/08/10 rpd]
95 * Conditionalize mach_msg_rpc_from_kernel on NORMA_VM, not NORMA_TASK.
96 * [91/08/14 18:34:30 jsb]
97 *
98 * Revision 2.13 91/08/03 18:18:53 jsb
99 * Corrected comment for mach_msg_send_from_kernel.
100 * [91/07/04 10:08:23 jsb]
101 *
102 * Revision 2.12 91/07/30 15:45:43 rvb
103 * Fixed syscall_vm_map to handle non-valid memory objects correctly.
104 * [91/07/12 rpd]
105 *
106 * Revision 2.11 91/06/17 15:47:05 jsb
107 * Renamed NORMA conditionals.
108 * [91/06/17 10:50:07 jsb]
109 *
110 * Revision 2.10 91/06/06 17:07:09 jsb
111 * NORMA_TASK: We still need mach_msg_rpc_from_kernel.
112 * [91/05/14 09:13:45 jsb]
113 *
114 * Revision 2.9 91/05/20 22:22:16 rpd
115 * Cleaned up the semantics of the syscall forms of kernel RPCs.
116 * [91/05/20 rpd]
117 *
118 * Revision 2.8 91/05/14 16:42:22 mrt
119 * Correcting copyright
120 *
121 * Revision 2.7 91/02/05 17:26:46 mrt
122 * Changed to new Mach copyright
123 * [91/02/01 16:13:09 mrt]
124 *
125 * Revision 2.6 91/01/08 15:15:44 rpd
126 * Don't need mach_msg_rpc_from_kernel.
127 * [90/12/26 rpd]
128 * Updated ipc_mqueue_receive calls.
129 * [90/11/21 rpd]
130 * Removed MACH_IPC_GENNOS.
131 * [90/11/09 rpd]
132 *
133 * Revision 2.5 90/11/05 14:30:59 rpd
134 * Changed ip_reference to ipc_port_reference.
135 * Changed ip_release to ipc_port_release.
136 * Removed ipc_object_release_macro.
137 * Use new ip_reference and ip_release.
138 * [90/10/29 rpd]
139 *
140 * Revision 2.4 90/09/09 14:32:13 rpd
141 * Added mach_port_allocate_name.
142 * [90/09/03 rwd]
143 *
144 * Revision 2.3 90/06/19 22:58:57 rpd
145 * Optimized port_name_to_task, port_name_to_thread, etc.
146 * [90/06/03 rpd]
147 *
148 * Added mach_port_allocate, mach_port_deallocate, mach_port_insert_right.
149 * [90/06/02 rpd]
150 *
151 * Revision 2.2 90/06/02 14:54:16 rpd
152 * Moved trap versions of kernel calls here
153 * from vm/vm_user.c, kern/task.c.
154 * Converted them to new IPC.
155 * [90/05/31 rpd]
156 *
157 * Created for new IPC.
158 * [90/03/26 23:47:15 rpd]
159 *
160 */
161
162 #include <mach_rt.h>
163 #include <norma_ipc.h>
164 #include <norma_task.h>
165 #include <norma_vm.h>
166
167 #include <mach/boolean.h>
168 #include <mach/port.h>
169 #include <mach/message.h>
170 #include <mach/thread_status.h>
171 #include <kern/ast.h>
172 #include <kern/ipc_tt.h>
173 #include <kern/memory.h>
174 #include <kern/syscall_subr.h>
175 #include <kern/thread.h>
176 #include <kern/task.h>
177 #include <kern/rt_thread.h>
178 #include <kern/ipc_kobject.h>
179 #include <vm/vm_map.h>
180 #include <vm/vm_user.h>
181 #include <ipc/port.h>
182 #include <ipc/ipc_kmsg.h>
183 #include <ipc/ipc_entry.h>
184 #include <ipc/ipc_object.h>
185 #include <ipc/ipc_mqueue.h>
186 #include <ipc/ipc_space.h>
187 #include <ipc/ipc_port.h>
188 #include <ipc/ipc_pset.h>
189 #include <ipc/ipc_thread.h>
190 #include <device/device_types.h>
191
192
193 /*
194 * Routine: mach_msg_send_from_kernel
195 * Purpose:
196 * Send a message from the kernel.
197 *
198 * This is used by the client side of KernelUser interfaces
199 * to implement SimpleRoutines. Currently, this includes
200 * device_reply and memory_object messages.
201 * Conditions:
202 * Nothing locked.
203 * Returns:
204 * MACH_MSG_SUCCESS Sent the message.
205 * MACH_SEND_INVALID_DATA Bad destination port.
206 */
207
208 mach_msg_return_t
209 mach_msg_send_from_kernel(
210 mach_msg_header_t *msg,
211 mach_msg_size_t send_size)
212 {
213 ipc_kmsg_t kmsg;
214 mach_msg_return_t mr;
215
216 if (!MACH_PORT_VALID(msg->msgh_remote_port))
217 return MACH_SEND_INVALID_DEST;
218
219 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
220 if (mr != MACH_MSG_SUCCESS)
221 panic("mach_msg_send_from_kernel");
222
223 ipc_kmsg_copyin_from_kernel(kmsg);
224 ipc_mqueue_send_always(kmsg);
225
226 return MACH_MSG_SUCCESS;
227 }
228
229 #if NORMA_VM
230 /*
231 * Routine: mach_msg_rpc_from_kernel
232 * Purpose:
233 * Send a message from the kernel and receive a reply.
234 * Uses ith_rpc_reply for the reply port.
235 *
236 * This is used by the client side of KernelUser interfaces
237 * to implement Routines. Currently, this is only
238 * used by norma code.
239 * Conditions:
240 * Nothing locked.
241 * Returns:
242 * MACH_MSG_SUCCESS Sent the message.
243 * MACH_RCV_PORT_DIED The reply port was deallocated.
244 */
245
246 mach_msg_return_t
247 mach_msg_rpc_from_kernel(
248 mach_msg_header_t *msg,
249 mach_msg_size_t send_size,
250 mach_msg_size_t rcv_size)
251 {
252 ipc_thread_t self = current_thread();
253 ipc_port_t reply;
254 ipc_kmsg_t kmsg;
255 mach_port_seqno_t seqno;
256 mach_msg_return_t mr;
257
258 assert(MACH_PORT_VALID(msg->msgh_remote_port));
259 assert(msg->msgh_local_port == MACH_PORT_NULL);
260
261 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
262 if (mr != MACH_MSG_SUCCESS)
263 panic("mach_msg_rpc_from_kernel");
264
265 ipc_kmsg_copyin_from_kernel(kmsg);
266
267 thread_lock(self);
268 assert(self->active);
269
270 reply = self->ith_rpc_reply;
271 if (reply == IP_NULL) {
272 thread_unlock(self);
273 reply = ipc_port_alloc_reply();
274 thread_lock(self);
275 if ((reply == IP_NULL) ||
276 (self->ith_rpc_reply != IP_NULL))
277 panic("mach_msg_rpc_from_kernel");
278 self->ith_rpc_reply = reply;
279 }
280
281 /* insert send-once right for the reply port */
282 kmsg->ikm_header.msgh_local_port =
283 (mach_port_t) ipc_port_make_sonce(reply);
284
285 ipc_port_reference(reply);
286 thread_unlock(self);
287
288 ipc_mqueue_send_always(kmsg);
289
290 for (;;) {
291 ipc_mqueue_t mqueue;
292
293 ip_lock(reply);
294 if (!ip_active(reply)) {
295 ip_unlock(reply);
296 ipc_port_release(reply);
297 return MACH_RCV_PORT_DIED;
298 }
299
300 assert(reply->ip_pset == IPS_NULL);
301 mqueue = &reply->ip_messages;
302 imq_lock(mqueue);
303 ip_unlock(reply);
304
305 mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
306 MACH_MSG_SIZE_MAX,
307 MACH_MSG_TIMEOUT_NONE,
308 FALSE, CONTINUE_NULL,
309 &kmsg, &seqno);
310 /* mqueue is unlocked */
311 if (mr == MACH_MSG_SUCCESS)
312 break;
313
314 assert((mr == MACH_RCV_INTERRUPTED) ||
315 (mr == MACH_RCV_PORT_DIED));
316
317 if (self->ast & AST_HALT) {
318 thread_halt_self(CONTINUE_NULL);
319 }
320 if (self->ast & AST_TERMINATE) {
321 /* don't terminate while holding a reference */
322 ipc_port_release(reply);
323 thread_terminate_self();
324 }
325 }
326 ipc_port_release(reply);
327
328 kmsg->ikm_header.msgh_seqno = seqno;
329
330 if (rcv_size < kmsg->ikm_header.msgh_size) {
331 ipc_kmsg_copyout_dest(kmsg, ipc_space_reply);
332 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
333 return MACH_RCV_TOO_LARGE;
334 }
335
336 /*
337 * We want to preserve rights and memory in reply!
338 * We don't have to put them anywhere; just leave them
339 * as they are.
340 */
341
342 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
343 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
344 return MACH_MSG_SUCCESS;
345 }
346 #endif /* NORMA_VM */
347
348 /*
349 * Routine: mach_msg_abort_rpc
350 * Purpose:
351 * Destroy the thread's ith_rpc_reply port.
352 * This will interrupt a mach_msg_rpc_from_kernel
353 * with a MACH_RCV_PORT_DIED return code.
354 * Conditions:
355 * Nothing locked.
356 */
357
358 void
359 mach_msg_abort_rpc(
360 ipc_thread_t thread)
361 {
362 ipc_port_t reply = IP_NULL;
363
364 thread_lock(thread);
365 if (thread->active) {
366 reply = thread->ith_rpc_reply;
367 thread->ith_rpc_reply = IP_NULL;
368 }
369 thread_unlock(thread);
370
371 if (reply != IP_NULL)
372 ipc_port_dealloc_reply(reply);
373 }
374
375 #if NORMA_TASK || NORMA_VM
376 /*
377 * Routine: mach_msg
378 * Purpose:
379 * Like mach_msg_trap except that message buffers
380 * live in kernel space. Doesn't handle any options.
381 *
382 * This is used by in-kernel server threads to make
383 * kernel calls, to receive request messages, and
384 * to send reply messages. Currently, this is
385 * only used by NORMA code.
386 * Conditions:
387 * Nothing locked.
388 * Returns:
389 */
390
391 mach_msg_return_t
392 mach_msg(
393 mach_msg_header_t *msg,
394 mach_msg_option_t option,
395 mach_msg_size_t send_size,
396 mach_msg_size_t rcv_size,
397 mach_port_t rcv_name,
398 mach_msg_timeout_t time_out,
399 mach_port_t notify)
400 {
401 ipc_space_t space = current_space();
402 vm_map_t map = current_map();
403 ipc_kmsg_t kmsg;
404 mach_port_seqno_t seqno;
405 mach_msg_return_t mr;
406
407 if (option & MACH_SEND_MSG) {
408 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
409 if (mr != MACH_MSG_SUCCESS)
410 panic("mach_msg");
411
412 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
413 if (mr != MACH_MSG_SUCCESS) {
414 ikm_free(kmsg);
415 return mr;
416 }
417
418 do
419 mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
420 MACH_MSG_TIMEOUT_NONE);
421 while (mr == MACH_SEND_INTERRUPTED);
422 assert(mr == MACH_MSG_SUCCESS);
423 }
424
425 if (option & MACH_RCV_MSG) {
426 do {
427 ipc_object_t object;
428 ipc_mqueue_t mqueue;
429
430 mr = ipc_mqueue_copyin(space, rcv_name,
431 &mqueue, &object);
432 if (mr != MACH_MSG_SUCCESS)
433 return mr;
434 /* hold ref for object; mqueue is locked */
435
436 mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
437 MACH_MSG_SIZE_MAX,
438 MACH_MSG_TIMEOUT_NONE,
439 FALSE, CONTINUE_NULL,
440 &kmsg, &seqno);
441 /* mqueue is unlocked */
442 ipc_object_release(object);
443 } while (mr == MACH_RCV_INTERRUPTED);
444 if (mr != MACH_MSG_SUCCESS)
445 return mr;
446
447 kmsg->ikm_header.msgh_seqno = seqno;
448
449 if (rcv_size < kmsg->ikm_header.msgh_size) {
450 ipc_kmsg_copyout_dest(kmsg, space);
451 ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
452 return MACH_RCV_TOO_LARGE;
453 }
454
455 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
456 if (mr != MACH_MSG_SUCCESS) {
457 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
458 ipc_kmsg_put_to_kernel(msg, kmsg,
459 kmsg->ikm_header.msgh_size);
460 } else {
461 ipc_kmsg_copyout_dest(kmsg, space);
462 ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
463 }
464
465 return mr;
466 }
467
468 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
469 }
470
471 return MACH_MSG_SUCCESS;
472 }
473
474 /*
475 * Routine: mig_get_reply_port
476 * Purpose:
477 * Called by client side interfaces living in the kernel
478 * to get a reply port. This port is used for
479 * mach_msg() calls which are kernel calls.
480 */
481
482 mach_port_t
483 mig_get_reply_port(void)
484 {
485 ipc_thread_t self = current_thread();
486
487 if (self->ith_mig_reply == MACH_PORT_NULL)
488 self->ith_mig_reply = mach_reply_port();
489
490 return self->ith_mig_reply;
491 }
492
493 /*
494 * Routine: mig_dealloc_reply_port
495 * Purpose:
496 * Called by client side interfaces to get rid of a reply port.
497 * Shouldn't ever be called inside the kernel, because
498 * kernel calls shouldn't prompt Mig to call it.
499 */
500
501 void
502 mig_dealloc_reply_port(mach_port_t port)
503 {
504 panic("mig_dealloc_reply_port");
505 }
506 #endif /* NORMA_TASK || NORMA_VM */
507
508 /*
509 * mig_strncpy.c - by Joshua Block
510 *
511 * mig_strncp -- Bounded string copy. Does what the library routine strncpy
512 * OUGHT to do: Copies the (null terminated) string in src into dest, a
513 * buffer of length len. Assures that the copy is still null terminated
514 * and doesn't overflow the buffer, truncating the copy if necessary.
515 *
516 * Parameters:
517 *
518 * dest - Pointer to destination buffer.
519 *
520 * src - Pointer to source string.
521 *
522 * len - Length of destination buffer.
523 */
524 void mig_strncpy(
525 char *dest,
526 char *src,
527 int len)
528 {
529 int i;
530
531 if (len <= 0)
532 return;
533
534 for (i=1; i<len; i++)
535 if (! (*dest++ = *src++))
536 return;
537
538 *dest = '\0';
539 return;
540 }
541
542 #define fast_send_right_lookup(name, port, abort) \
543 MACRO_BEGIN \
544 register ipc_space_t space = current_space(); \
545 register ipc_entry_t entry; \
546 register mach_port_index_t index = MACH_PORT_INDEX(name); \
547 \
548 is_read_lock(space); \
549 assert(space->is_active); \
550 \
551 if ((index >= space->is_table_size) || \
552 (((entry = &space->is_table[index])->ie_bits & \
553 (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != \
554 (MACH_PORT_GEN(name) | MACH_PORT_TYPE_SEND))) { \
555 is_read_unlock(space); \
556 abort; \
557 } \
558 \
559 port = (ipc_port_t) entry->ie_object; \
560 assert(port != IP_NULL); \
561 \
562 ip_lock(port); \
563 /* can safely unlock space now that port is locked */ \
564 is_read_unlock(space); \
565 MACRO_END
566
567 device_t
568 port_name_to_device(
569 mach_port_t name)
570 {
571 register ipc_port_t port;
572 register device_t device;
573
574 fast_send_right_lookup(name, port, goto abort);
575 /* port is locked */
576
577 /*
578 * Now map the port object to a device object.
579 * This is an inline version of dev_port_lookup().
580 */
581 if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
582 device = (device_t) port->ip_kobject;
583 device_reference(device);
584 ip_unlock(port);
585 return device;
586 }
587
588 ip_unlock(port);
589 return DEVICE_NULL;
590
591 /*
592 * The slow case. The port wasn't easily accessible.
593 */
594 abort: {
595 ipc_port_t kern_port;
596 kern_return_t kr;
597
598 kr = ipc_object_copyin(current_space(), name,
599 MACH_MSG_TYPE_COPY_SEND,
600 (ipc_object_t *) &kern_port);
601 if (kr != KERN_SUCCESS)
602 return DEVICE_NULL;
603
604 device = dev_port_lookup(kern_port);
605 if (IP_VALID(kern_port))
606 ipc_port_release_send(kern_port);
607 return device;
608 }
609 }
610
611 thread_t
612 port_name_to_thread(
613 mach_port_t name)
614 {
615 register ipc_port_t port;
616
617 fast_send_right_lookup(name, port, goto abort);
618 /* port is locked */
619
620 if (ip_active(port) &&
621 (ip_kotype(port) == IKOT_THREAD)) {
622 register thread_t thread;
623
624 thread = (thread_t) port->ip_kobject;
625 assert(thread != THREAD_NULL);
626
627 /* thread referencing is a bit complicated,
628 so don't bother to expand inline */
629 thread_reference(thread);
630 ip_unlock(port);
631
632 return thread;
633 }
634
635 ip_unlock(port);
636 return THREAD_NULL;
637
638 abort: {
639 thread_t thread;
640 ipc_port_t kern_port;
641 kern_return_t kr;
642
643 kr = ipc_object_copyin(current_space(), name,
644 MACH_MSG_TYPE_COPY_SEND,
645 (ipc_object_t *) &kern_port);
646 if (kr != KERN_SUCCESS)
647 return THREAD_NULL;
648
649 thread = convert_port_to_thread(kern_port);
650 if (IP_VALID(kern_port))
651 ipc_port_release_send(kern_port);
652
653 return thread;
654 }
655 }
656
657 task_t
658 port_name_to_task(
659 mach_port_t name)
660 {
661 register ipc_port_t port;
662
663 fast_send_right_lookup(name, port, goto abort);
664 /* port is locked */
665
666 if (ip_active(port) &&
667 (ip_kotype(port) == IKOT_TASK)) {
668 register task_t task;
669
670 task = (task_t) port->ip_kobject;
671 assert(task != TASK_NULL);
672
673 task_lock(task);
674 /* can safely unlock port now that task is locked */
675 ip_unlock(port);
676
677 task->ref_count++;
678 task_unlock(task);
679
680 return task;
681 }
682
683 ip_unlock(port);
684 return TASK_NULL;
685
686 abort: {
687 task_t task;
688 ipc_port_t kern_port;
689 kern_return_t kr;
690
691 kr = ipc_object_copyin(current_space(), name,
692 MACH_MSG_TYPE_COPY_SEND,
693 (ipc_object_t *) &kern_port);
694 if (kr != KERN_SUCCESS)
695 return TASK_NULL;
696
697 task = convert_port_to_task(kern_port);
698 if (IP_VALID(kern_port))
699 ipc_port_release_send(kern_port);
700
701 return task;
702 }
703 }
704
705 vm_map_t
706 port_name_to_map(
707 mach_port_t name)
708 {
709 register ipc_port_t port;
710
711 fast_send_right_lookup(name, port, goto abort);
712 /* port is locked */
713
714 if (ip_active(port) &&
715 (ip_kotype(port) == IKOT_TASK)) {
716 register vm_map_t map;
717
718 map = ((task_t) port->ip_kobject)->map;
719 assert(map != VM_MAP_NULL);
720
721 simple_lock(&map->ref_lock);
722 /* can safely unlock port now that map is locked */
723 ip_unlock(port);
724
725 map->ref_count++;
726 simple_unlock(&map->ref_lock);
727
728 return map;
729 }
730
731 ip_unlock(port);
732 return VM_MAP_NULL;
733
734 abort: {
735 vm_map_t map;
736 ipc_port_t kern_port;
737 kern_return_t kr;
738
739 kr = ipc_object_copyin(current_space(), name,
740 MACH_MSG_TYPE_COPY_SEND,
741 (ipc_object_t *) &kern_port);
742 if (kr != KERN_SUCCESS)
743 return VM_MAP_NULL;
744
745 map = convert_port_to_map(kern_port);
746 if (IP_VALID(kern_port))
747 ipc_port_release_send(kern_port);
748
749 return map;
750 }
751 }
752
753 ipc_space_t
754 port_name_to_space(
755 mach_port_t name)
756 {
757 register ipc_port_t port;
758
759 fast_send_right_lookup(name, port, goto abort);
760 /* port is locked */
761
762 if (ip_active(port) &&
763 (ip_kotype(port) == IKOT_TASK)) {
764 register ipc_space_t space;
765
766 space = ((task_t) port->ip_kobject)->itk_space;
767 assert(space != IS_NULL);
768
769 simple_lock(&space->is_ref_lock_data);
770 /* can safely unlock port now that space is locked */
771 ip_unlock(port);
772
773 space->is_references++;
774 simple_unlock(&space->is_ref_lock_data);
775
776 return space;
777 }
778
779 ip_unlock(port);
780 return IS_NULL;
781
782 abort: {
783 ipc_space_t space;
784 ipc_port_t kern_port;
785 kern_return_t kr;
786
787 kr = ipc_object_copyin(current_space(), name,
788 MACH_MSG_TYPE_COPY_SEND,
789 (ipc_object_t *) &kern_port);
790 if (kr != KERN_SUCCESS)
791 return IS_NULL;
792
793 space = convert_port_to_space(kern_port);
794 if (IP_VALID(kern_port))
795 ipc_port_release_send(kern_port);
796
797 return space;
798 }
799 }
800
801 mach_timer_t
802 port_name_to_timer(
803 mach_port_t name)
804 {
805 register ipc_port_t port;
806
807 fast_send_right_lookup(name, port, goto abort);
808 /* port is locked */
809
810 if (ip_active(port) &&
811 (ip_kotype(port) == IKOT_TIMER)) {
812 register mach_timer_t timer;
813
814 timer = (mach_timer_t) port->ip_kobject;
815 assert(timer != TIMER_NULL);
816
817 timer_ref_lock(timer);
818 timer->tm_ref_count++;
819 timer_ref_unlock(timer);
820
821 ip_unlock(port);
822
823 return timer;
824 }
825
826 ip_unlock(port);
827 return TIMER_NULL;
828
829 abort: {
830 mach_timer_t timer;
831 ipc_port_t kern_port;
832 kern_return_t kr;
833
834 kr = ipc_object_copyin(current_space(), name,
835 MACH_MSG_TYPE_COPY_SEND,
836 (ipc_object_t *) &kern_port);
837 if (kr != KERN_SUCCESS)
838 return TIMER_NULL;
839
840 timer = convert_port_to_timer(kern_port);
841 if (IP_VALID(kern_port))
842 ipc_port_release_send(kern_port);
843
844 return timer;
845 }
846 }
847
848 /*
849 * Things to keep in mind:
850 *
851 * The idea here is to duplicate the semantics of the true kernel RPC.
852 * The destination port/object should be checked first, before anything
853 * that the user might notice (like ipc_object_copyin). Return
854 * MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
855 * knows to fall back on an RPC. For other return values, it won't
856 * retry with an RPC. The retry might get a different (incorrect) rc.
857 * Return values are only set (and should only be set, with copyout)
858 * on successfull calls.
859 */
860
861 kern_return_t syscall_vm_map(
862 mach_port_t target_map,
863 vm_offset_t *address,
864 vm_size_t size,
865 vm_offset_t mask,
866 boolean_t anywhere,
867 mach_port_t memory_object,
868 vm_offset_t offset,
869 boolean_t copy,
870 vm_prot_t cur_protection,
871 vm_prot_t max_protection,
872 vm_inherit_t inheritance)
873 {
874 vm_map_t map;
875 ipc_port_t port;
876 vm_offset_t addr;
877 kern_return_t result;
878
879 map = port_name_to_map(target_map);
880 if (map == VM_MAP_NULL)
881 return MACH_SEND_INTERRUPTED;
882
883 if (MACH_PORT_VALID(memory_object)) {
884 result = ipc_object_copyin(current_space(), memory_object,
885 MACH_MSG_TYPE_COPY_SEND,
886 (ipc_object_t *) &port);
887 if (result != KERN_SUCCESS) {
888 vm_map_deallocate(map);
889 return result;
890 }
891 } else
892 port = (ipc_port_t) memory_object;
893
894 copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
895 result = vm_map(map, &addr, size, mask, anywhere,
896 port, offset, copy,
897 cur_protection, max_protection, inheritance);
898 if (result == KERN_SUCCESS)
899 copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
900 if (IP_VALID(port))
901 ipc_port_release_send(port);
902 vm_map_deallocate(map);
903
904 return result;
905 }
906
907 kern_return_t syscall_vm_allocate(
908 mach_port_t target_map,
909 vm_offset_t *address,
910 vm_size_t size,
911 boolean_t anywhere)
912 {
913 vm_map_t map;
914 vm_offset_t addr;
915 kern_return_t result;
916
917 map = port_name_to_map(target_map);
918 if (map == VM_MAP_NULL)
919 return MACH_SEND_INTERRUPTED;
920
921 copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
922 result = vm_allocate(map, &addr, size, anywhere);
923 if (result == KERN_SUCCESS)
924 copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
925 vm_map_deallocate(map);
926
927 return result;
928 }
929
930 kern_return_t syscall_vm_deallocate(
931 mach_port_t target_map,
932 vm_offset_t start,
933 vm_size_t size)
934 {
935 vm_map_t map;
936 kern_return_t result;
937
938 map = port_name_to_map(target_map);
939 if (map == VM_MAP_NULL)
940 return MACH_SEND_INTERRUPTED;
941
942 result = vm_deallocate(map, start, size);
943 vm_map_deallocate(map);
944
945 return result;
946 }
947
948 kern_return_t syscall_task_create(
949 mach_port_t parent_task,
950 boolean_t inherit_memory,
951 mach_port_t *child_task) /* OUT */
952 {
953 task_t t, c;
954 ipc_port_t port;
955 mach_port_t name;
956 kern_return_t result;
957
958 t = port_name_to_task(parent_task);
959 if (t == TASK_NULL)
960 return MACH_SEND_INTERRUPTED;
961
962 result = task_create(t, inherit_memory, &c);
963 if (result == KERN_SUCCESS) {
964 port = (ipc_port_t) convert_task_to_port(c);
965 /* always returns a name, even for non-success return codes */
966 (void) ipc_kmsg_copyout_object(current_space(),
967 (ipc_object_t) port,
968 MACH_MSG_TYPE_PORT_SEND, &name);
969 copyout((char *)&name, (char *)child_task,
970 sizeof(mach_port_t));
971 }
972 task_deallocate(t);
973
974 return result;
975 }
976
977 kern_return_t syscall_task_terminate(
978 mach_port_t task)
979 {
980 task_t t;
981 kern_return_t result;
982
983 t = port_name_to_task(task);
984 if (t == TASK_NULL)
985 return MACH_SEND_INTERRUPTED;
986
987 result = task_terminate(t);
988 task_deallocate(t);
989
990 return result;
991 }
992
993 kern_return_t syscall_task_suspend(
994 mach_port_t task)
995 {
996 task_t t;
997 kern_return_t result;
998
999 t = port_name_to_task(task);
1000 if (t == TASK_NULL)
1001 return MACH_SEND_INTERRUPTED;
1002
1003 result = task_suspend(t);
1004 task_deallocate(t);
1005
1006 return result;
1007 }
1008
1009 kern_return_t syscall_task_set_special_port(
1010 mach_port_t task,
1011 int which_port,
1012 mach_port_t port_name)
1013 {
1014 task_t t;
1015 ipc_port_t port;
1016 kern_return_t result;
1017
1018 t = port_name_to_task(task);
1019 if (t == TASK_NULL)
1020 return MACH_SEND_INTERRUPTED;
1021
1022 if (MACH_PORT_VALID(port_name)) {
1023 result = ipc_object_copyin(current_space(), port_name,
1024 MACH_MSG_TYPE_COPY_SEND,
1025 (ipc_object_t *) &port);
1026 if (result != KERN_SUCCESS) {
1027 task_deallocate(t);
1028 return result;
1029 }
1030 } else
1031 port = (ipc_port_t) port_name;
1032
1033 result = task_set_special_port(t, which_port, port);
1034 if ((result != KERN_SUCCESS) && IP_VALID(port))
1035 ipc_port_release_send(port);
1036 task_deallocate(t);
1037
1038 return result;
1039 }
1040
1041 kern_return_t
1042 syscall_mach_port_allocate(
1043 mach_port_t task,
1044 mach_port_right_t right,
1045 mach_port_t *namep)
1046 {
1047 ipc_space_t space;
1048 mach_port_t name;
1049 kern_return_t kr;
1050
1051 space = port_name_to_space(task);
1052 if (space == IS_NULL)
1053 return MACH_SEND_INTERRUPTED;
1054
1055 kr = mach_port_allocate(space, right, &name);
1056 if (kr == KERN_SUCCESS)
1057 copyout((char *)&name, (char *)namep, sizeof(mach_port_t));
1058 is_release(space);
1059
1060 return kr;
1061 }
1062
1063 kern_return_t
1064 syscall_mach_port_allocate_name(
1065 mach_port_t task,
1066 mach_port_right_t right,
1067 mach_port_t name)
1068 {
1069 ipc_space_t space;
1070 kern_return_t kr;
1071
1072 space = port_name_to_space(task);
1073 if (space == IS_NULL)
1074 return MACH_SEND_INTERRUPTED;
1075
1076 kr = mach_port_allocate_name(space, right, name);
1077 is_release(space);
1078
1079 return kr;
1080 }
1081
1082 kern_return_t
1083 syscall_mach_port_deallocate(
1084 mach_port_t task,
1085 mach_port_t name)
1086 {
1087 ipc_space_t space;
1088 kern_return_t kr;
1089
1090 space = port_name_to_space(task);
1091 if (space == IS_NULL)
1092 return MACH_SEND_INTERRUPTED;
1093
1094 kr = mach_port_deallocate(space, name);
1095 is_release(space);
1096
1097 return kr;
1098 }
1099
1100 kern_return_t
1101 syscall_mach_port_insert_right(
1102 mach_port_t task,
1103 mach_port_t name,
1104 mach_port_t right,
1105 mach_msg_type_name_t rightType)
1106 {
1107 ipc_space_t space;
1108 ipc_object_t object;
1109 mach_msg_type_name_t newtype;
1110 kern_return_t kr;
1111
1112 space = port_name_to_space(task);
1113 if (space == IS_NULL)
1114 return MACH_SEND_INTERRUPTED;
1115
1116 if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
1117 is_release(space);
1118 return KERN_INVALID_VALUE;
1119 }
1120
1121 if (MACH_PORT_VALID(right)) {
1122 kr = ipc_object_copyin(current_space(), right, rightType,
1123 &object);
1124 if (kr != KERN_SUCCESS) {
1125 is_release(space);
1126 return kr;
1127 }
1128 } else
1129 object = (ipc_object_t) right;
1130 newtype = ipc_object_copyin_type(rightType);
1131
1132 kr = mach_port_insert_right(space, name, object, newtype);
1133 if ((kr != KERN_SUCCESS) && IO_VALID(object))
1134 ipc_object_destroy(object, newtype);
1135 is_release(space);
1136
1137 return kr;
1138 }
1139
1140 kern_return_t syscall_thread_depress_abort(
1141 mach_port_t thread)
1142 {
1143 thread_t t;
1144 kern_return_t result;
1145
1146 t = port_name_to_thread(thread);
1147 if (t == THREAD_NULL)
1148 return MACH_SEND_INTERRUPTED;
1149
1150 result = thread_depress_abort(t);
1151 thread_deallocate(t);
1152
1153 return result;
1154 }
1155
1156 kern_return_t syscall_timer_arm(
1157 mach_port_t timer,
1158 time_spec_t expire_time,
1159 time_spec_t interval_time,
1160 mach_port_t expire_port,
1161 mach_port_t thread,
1162 int flags)
1163 {
1164 mach_timer_t tm;
1165 ipc_port_t ex_port;
1166 thread_t th;
1167 kern_return_t result;
1168
1169 tm = port_name_to_timer(timer);
1170 if (tm == TIMER_NULL)
1171 return MACH_SEND_INTERRUPTED;
1172
1173 if (MACH_PORT_VALID(thread)) {
1174 th = port_name_to_thread(thread);
1175 if (th == THREAD_NULL) {
1176 mach_timer_deallocate(tm);
1177 return KERN_INVALID_ARGUMENT;
1178 }
1179 }
1180 else {
1181 th = THREAD_NULL;
1182 }
1183 if (MACH_PORT_VALID(expire_port)) {
1184 result = ipc_object_copyin(current_space(), expire_port,
1185 MACH_MSG_TYPE_COPY_SEND,
1186 (ipc_object_t *) &ex_port);
1187 if (result != KERN_SUCCESS) {
1188 thread_deallocate(th);
1189 mach_timer_deallocate(tm);
1190 return result;
1191 }
1192 }
1193 else
1194 ex_port = (ipc_port_t) expire_port;
1195
1196 result = timer_arm(tm, expire_time, interval_time,
1197 ex_port, th, flags);
1198
1199 if (result != KERN_SUCCESS && IP_VALID(ex_port))
1200 ipc_port_release_send(ex_port);
1201 thread_deallocate(th);
1202 mach_timer_deallocate(tm);
1203
1204 return result;
1205 }
1206
1207 kern_return_t syscall_timer_cancel(
1208 mach_port_t timer,
1209 int flags)
1210 {
1211 mach_timer_t tm;
1212 kern_return_t result;
1213
1214 tm = port_name_to_timer(timer);
1215 if (tm == TIMER_NULL)
1216 return MACH_SEND_INTERRUPTED;
1217
1218 result = timer_cancel(tm, flags);
1219
1220 mach_timer_deallocate(tm);
1221
1222 return result;
1223 }
1224
1225 kern_return_t syscall_periodic_thread_restart(
1226 mach_port_t thread)
1227 {
1228 thread_t t;
1229 kern_return_t result;
1230
1231 t = port_name_to_thread(thread);
1232 if (t == THREAD_NULL)
1233 return MACH_SEND_INTERRUPTED;
1234
1235 result = periodic_thread_restart(t);
1236 thread_deallocate(t);
1237
1238 return result;
1239 }
1240
1241
1242 /*
1243 * Device traps -- these are way experimental.
1244 */
1245
1246 extern io_return_t ds_device_write_trap();
1247 extern io_return_t ds_device_writev_trap();
1248
1249 io_return_t
1250 syscall_device_write_request(mach_port_t device_name,
1251 mach_port_t reply_name,
1252 dev_mode_t mode,
1253 recnum_t recnum,
1254 vm_offset_t data,
1255 vm_size_t data_count)
1256 {
1257 device_t dev;
1258 ipc_port_t reply_port;
1259 io_return_t res;
1260
1261 /*
1262 * First try to translate the device name.
1263 *
1264 * If this fails, return KERN_INVALID_CAPABILITY.
1265 * Caller knows that this most likely means that
1266 * device is not local to node and IPC should be used.
1267 *
1268 * If kernel doesn't do device traps, kern_invalid()
1269 * will be called instead of this function which will
1270 * return KERN_INVALID_ARGUMENT.
1271 */
1272 dev = port_name_to_device(device_name);
1273 if (dev == DEVICE_NULL)
1274 return KERN_INVALID_CAPABILITY;
1275
1276 /*
1277 * Translate reply port.
1278 */
1279 if (reply_name == MACH_PORT_NULL)
1280 reply_port = IP_NULL;
1281 else {
1282 /* Homey don't play that. */
1283 device_deallocate(dev);
1284 return KERN_INVALID_RIGHT;
1285 }
1286
1287 /* note: doesn't take reply_port arg yet. */
1288 res = ds_device_write_trap(dev, /*reply_port,*/
1289 mode, recnum,
1290 data, data_count);
1291
1292 /*
1293 * Give up reference from port_name_to_device.
1294 */
1295 device_deallocate(dev);
1296 return res;
1297 }
1298
1299 io_return_t
1300 syscall_device_writev_request(mach_port_t device_name,
1301 mach_port_t reply_name,
1302 dev_mode_t mode,
1303 recnum_t recnum,
1304 io_buf_vec_t *iovec,
1305 vm_size_t iocount)
1306 {
1307 device_t dev;
1308 ipc_port_t reply_port;
1309 io_return_t res;
1310
1311 /*
1312 * First try to translate the device name.
1313 *
1314 * If this fails, return KERN_INVALID_CAPABILITY.
1315 * Caller knows that this most likely means that
1316 * device is not local to node and IPC should be used.
1317 *
1318 * If kernel doesn't do device traps, kern_invalid()
1319 * will be called instead of this function which will
1320 * return KERN_INVALID_ARGUMENT.
1321 */
1322 dev = port_name_to_device(device_name);
1323 if (dev == DEVICE_NULL)
1324 return KERN_INVALID_CAPABILITY;
1325
1326 /*
1327 * Translate reply port.
1328 */
1329 if (reply_name == MACH_PORT_NULL)
1330 reply_port = IP_NULL;
1331 else {
1332 /* Homey don't play that. */
1333 device_deallocate(dev);
1334 return KERN_INVALID_RIGHT;
1335 }
1336
1337 /* note: doesn't take reply_port arg yet. */
1338 res = ds_device_writev_trap(dev, /*reply_port,*/
1339 mode, recnum,
1340 iovec, iocount);
1341
1342 /*
1343 * Give up reference from port_name_to_device.
1344 */
1345 device_deallocate(dev);
1346 return res;
1347 }
1348
1349
Cache object: ed814ce3fb818b65d533345b8f295632
|