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