]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_msg.c
7600f56ecd2edc74eb3e6b29933cba703b90294a
[apple/xnu.git] / osfmk / ipc / mach_msg.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 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 Software.Distribution@CS.CMU.EDU
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 */
52 /*
53 * File: ipc/mach_msg.c
54 * Author: Rich Draves
55 * Date: 1989
56 *
57 * Exported message traps. See mach/message.h.
58 */
59
60 #include <mach/mach_types.h>
61 #include <mach/kern_return.h>
62 #include <mach/port.h>
63 #include <mach/message.h>
64 #include <mach/mig_errors.h>
65 #include <mach/mach_traps.h>
66
67 #include <kern/kern_types.h>
68 #include <kern/assert.h>
69 #include <kern/counters.h>
70 #include <kern/cpu_number.h>
71 #include <kern/ipc_kobject.h>
72 #include <kern/ipc_mig.h>
73 #include <kern/task.h>
74 #include <kern/thread.h>
75 #include <kern/lock.h>
76 #include <kern/sched_prim.h>
77 #include <kern/exception.h>
78 #include <kern/misc_protos.h>
79 #include <kern/kalloc.h>
80 #include <kern/processor.h>
81 #include <kern/syscall_subr.h>
82
83 #include <vm/vm_map.h>
84
85 #include <ipc/ipc_types.h>
86 #include <ipc/ipc_kmsg.h>
87 #include <ipc/ipc_mqueue.h>
88 #include <ipc/ipc_object.h>
89 #include <ipc/ipc_notify.h>
90 #include <ipc/ipc_port.h>
91 #include <ipc/ipc_pset.h>
92 #include <ipc/ipc_space.h>
93 #include <ipc/ipc_entry.h>
94
95 #include <machine/machine_routines.h>
96
97 #include <sys/kdebug.h>
98
99 #ifndef offsetof
100 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
101 #endif /* offsetof */
102
103 /*
104 * Forward declarations - kernel internal routines
105 */
106
107 mach_msg_return_t mach_msg_send(
108 mach_msg_header_t *msg,
109 mach_msg_option_t option,
110 mach_msg_size_t send_size,
111 mach_msg_timeout_t send_timeout,
112 mach_port_name_t notify);
113
114 mach_msg_return_t mach_msg_receive(
115 mach_msg_header_t *msg,
116 mach_msg_option_t option,
117 mach_msg_size_t rcv_size,
118 mach_port_name_t rcv_name,
119 mach_msg_timeout_t rcv_timeout,
120 void (*continuation)(mach_msg_return_t),
121 mach_msg_size_t slist_size);
122
123
124 mach_msg_return_t mach_msg_receive_results(void);
125
126 mach_msg_return_t msg_receive_error(
127 ipc_kmsg_t kmsg,
128 mach_vm_address_t msg_addr,
129 mach_msg_option_t option,
130 mach_port_seqno_t seqno,
131 ipc_space_t space);
132
133 security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE;
134 audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE;
135
136 mach_msg_format_0_trailer_t trailer_template = {
137 /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0,
138 /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE,
139 /* mach_port_seqno_t */ 0,
140 /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE
141 };
142
143 /*
144 * Routine: mach_msg_send
145 * Purpose:
146 * Send a message.
147 * Conditions:
148 * Nothing locked.
149 * Returns:
150 * MACH_MSG_SUCCESS Sent the message.
151 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
152 * MACH_SEND_NO_BUFFER Couldn't allocate buffer.
153 * MACH_SEND_INVALID_DATA Couldn't copy message data.
154 * MACH_SEND_INVALID_HEADER
155 * Illegal value in the message header bits.
156 * MACH_SEND_INVALID_DEST The space is dead.
157 * MACH_SEND_INVALID_NOTIFY Bad notify port.
158 * MACH_SEND_INVALID_DEST Can't copyin destination port.
159 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
160 * MACH_SEND_TIMED_OUT Timeout expired without delivery.
161 * MACH_SEND_INTERRUPTED Delivery interrupted.
162 * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request.
163 * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested.
164 * MACH_SEND_NOTIFY_IN_PROGRESS
165 * This space has already forced a message to this port.
166 */
167
168 mach_msg_return_t
169 mach_msg_send(
170 mach_msg_header_t *msg,
171 mach_msg_option_t option,
172 mach_msg_size_t send_size,
173 mach_msg_timeout_t send_timeout,
174 mach_port_name_t notify)
175 {
176 ipc_space_t space = current_space();
177 vm_map_t map = current_map();
178 ipc_kmsg_t kmsg;
179 mach_msg_return_t mr;
180 mach_msg_size_t msg_and_trailer_size;
181 mach_msg_max_trailer_t *trailer;
182
183 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3))
184 return MACH_SEND_MSG_TOO_SMALL;
185
186 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE;
187
188 kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
189
190 if (kmsg == IKM_NULL)
191 return MACH_SEND_NO_BUFFER;
192
193 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size);
194
195 kmsg->ikm_header->msgh_size = send_size;
196
197 /*
198 * reserve for the trailer the largest space (MAX_TRAILER_SIZE)
199 * However, the internal size field of the trailer (msgh_trailer_size)
200 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
201 * the cases where no implicit data is requested.
202 */
203 trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size);
204 trailer->msgh_sender = current_thread()->task->sec_token;
205 trailer->msgh_audit = current_thread()->task->audit_token;
206 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
207 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
208
209 if (option & MACH_SEND_CANCEL) {
210 if (notify == MACH_PORT_NULL)
211 mr = MACH_SEND_INVALID_NOTIFY;
212 else
213 mr = ipc_kmsg_copyin(kmsg, space, map, notify);
214 } else
215 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
216 if (mr != MACH_MSG_SUCCESS) {
217 ipc_kmsg_free(kmsg);
218 return mr;
219 }
220
221 mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, send_timeout);
222
223 if (mr != MACH_MSG_SUCCESS) {
224 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL);
225 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header,
226 kmsg->ikm_header->msgh_size);
227 ipc_kmsg_free(kmsg);
228 }
229
230 return mr;
231 }
232
233 /*
234 * Routine: mach_msg_receive
235 * Purpose:
236 * Receive a message.
237 * Conditions:
238 * Nothing locked.
239 * Returns:
240 * MACH_MSG_SUCCESS Received a message.
241 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
242 * or the denoted right is not receive or port set.
243 * MACH_RCV_IN_SET Receive right is a member of a set.
244 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
245 * MACH_RCV_TIMED_OUT Timeout expired without a message.
246 * MACH_RCV_INTERRUPTED Reception interrupted.
247 * MACH_RCV_PORT_DIED Port/set died while receiving.
248 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
249 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
250 * MACH_RCV_INVALID_NOTIFY Bad notify port.
251 * MACH_RCV_HEADER_ERROR
252 */
253
254 mach_msg_return_t
255 mach_msg_receive_results(void)
256 {
257 thread_t self = current_thread();
258 ipc_space_t space = current_space();
259 vm_map_t map = current_map();
260
261 ipc_object_t object = self->ith_object;
262 mach_msg_return_t mr = self->ith_state;
263 mach_vm_address_t msg_addr = self->ith_msg_addr;
264 mach_msg_option_t option = self->ith_option;
265 ipc_kmsg_t kmsg = self->ith_kmsg;
266 mach_port_seqno_t seqno = self->ith_seqno;
267
268 mach_msg_format_0_trailer_t *trailer;
269
270 ipc_object_release(object);
271
272 if (mr != MACH_MSG_SUCCESS) {
273
274 if (mr == MACH_RCV_TOO_LARGE ) {
275 if (option & MACH_RCV_LARGE) {
276 /*
277 * We need to inform the user-level code that it needs more
278 * space. The value for how much space was returned in the
279 * msize save area instead of the message (which was left on
280 * the queue).
281 */
282 if (copyout((char *) &self->ith_msize,
283 msg_addr + offsetof(mach_msg_header_t, msgh_size),
284 sizeof(mach_msg_size_t)))
285 mr = MACH_RCV_INVALID_DATA;
286 goto out;
287 }
288
289 if (msg_receive_error(kmsg, msg_addr, option, seqno, space)
290 == MACH_RCV_INVALID_DATA)
291 mr = MACH_RCV_INVALID_DATA;
292 }
293 goto out;
294 }
295
296 trailer = (mach_msg_format_0_trailer_t *)
297 ((vm_offset_t)kmsg->ikm_header +
298 round_msg(kmsg->ikm_header->msgh_size));
299 if (option & MACH_RCV_TRAILER_MASK) {
300 trailer->msgh_seqno = seqno;
301 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
302 }
303
304 /*
305 * If MACH_RCV_OVERWRITE was specified, try to get the scatter
306 * list and verify it against the contents of the message. If
307 * there is any problem with it, we will continue without it as
308 * normal.
309 */
310 if (option & MACH_RCV_OVERWRITE) {
311 mach_msg_size_t slist_size = self->ith_scatter_list_size;
312 mach_msg_body_t *slist;
313
314 slist = ipc_kmsg_get_scatter(msg_addr, slist_size, kmsg);
315 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, slist);
316 ipc_kmsg_free_scatter(slist, slist_size);
317 } else {
318 mr = ipc_kmsg_copyout(kmsg, space, map,
319 MACH_PORT_NULL, MACH_MSG_BODY_NULL);
320 }
321
322 if (mr != MACH_MSG_SUCCESS) {
323 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
324 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size +
325 trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
326 mr = MACH_RCV_INVALID_DATA;
327 }
328 else {
329 if (msg_receive_error(kmsg, msg_addr, option, seqno, space)
330 == MACH_RCV_INVALID_DATA)
331 mr = MACH_RCV_INVALID_DATA;
332 }
333 goto out;
334 }
335 mr = ipc_kmsg_put(msg_addr,
336 kmsg,
337 kmsg->ikm_header->msgh_size +
338 trailer->msgh_trailer_size);
339 out:
340 return mr;
341 }
342
343 mach_msg_return_t
344 mach_msg_receive(
345 mach_msg_header_t *msg,
346 mach_msg_option_t option,
347 mach_msg_size_t rcv_size,
348 mach_port_name_t rcv_name,
349 mach_msg_timeout_t rcv_timeout,
350 void (*continuation)(mach_msg_return_t),
351 mach_msg_size_t slist_size)
352 {
353 thread_t self = current_thread();
354 ipc_space_t space = current_space();
355 ipc_object_t object;
356 ipc_mqueue_t mqueue;
357 mach_msg_return_t mr;
358
359 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
360 if (mr != MACH_MSG_SUCCESS) {
361 return mr;
362 }
363 /* hold ref for object */
364
365 self->ith_msg_addr = CAST_DOWN(mach_vm_address_t, msg);
366 self->ith_object = object;
367 self->ith_msize = rcv_size;
368 self->ith_option = option;
369 self->ith_scatter_list_size = slist_size;
370 self->ith_continuation = continuation;
371
372 ipc_mqueue_receive(mqueue, option, rcv_size, rcv_timeout, THREAD_ABORTSAFE);
373 if ((option & MACH_RCV_TIMEOUT) && rcv_timeout == 0)
374 thread_poll_yield(self);
375 return mach_msg_receive_results();
376 }
377
378 void
379 mach_msg_receive_continue(void)
380 {
381 thread_t self = current_thread();
382
383 (*self->ith_continuation)(mach_msg_receive_results());
384 }
385
386 /*
387 * Toggle this to compile the hotpath in/out
388 * If compiled in, the run-time toggle "enable_hotpath" below
389 * eases testing & debugging
390 */
391 #define ENABLE_HOTPATH 1 /* Hacked on for now */
392
393 #if ENABLE_HOTPATH
394 /*
395 * These counters allow tracing of hotpath behavior under test loads.
396 * A couple key counters are unconditional (see below).
397 */
398 #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */
399 #if HOTPATH_DEBUG
400 #define HOT(expr) expr
401
402 unsigned int c_mmot_FIRST = 0; /* Unused First Counter */
403 unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */
404 unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */
405 unsigned int c_mmot_kernel_send = 0; /* kernel server */
406 unsigned int c_mmot_cold_000 = 0; /* see below ... */
407 unsigned int c_mmot_smallsendsize = 0;
408 unsigned int c_mmot_oddsendsize = 0;
409 unsigned int c_mmot_bigsendsize = 0;
410 unsigned int c_mmot_copyinmsg_fail = 0;
411 unsigned int c_mmot_g_slow_copyin3 = 0;
412 unsigned int c_mmot_cold_006 = 0;
413 unsigned int c_mmot_cold_007 = 0;
414 unsigned int c_mmot_cold_008 = 0;
415 unsigned int c_mmot_cold_009 = 0;
416 unsigned int c_mmot_cold_010 = 0;
417 unsigned int c_mmot_cold_012 = 0;
418 unsigned int c_mmot_cold_013 = 0;
419 unsigned int c_mmot_cold_014 = 0;
420 unsigned int c_mmot_cold_016 = 0;
421 unsigned int c_mmot_cold_018 = 0;
422 unsigned int c_mmot_cold_019 = 0;
423 unsigned int c_mmot_cold_020 = 0;
424 unsigned int c_mmot_cold_021 = 0;
425 unsigned int c_mmot_cold_022 = 0;
426 unsigned int c_mmot_cold_023 = 0;
427 unsigned int c_mmot_cold_024 = 0;
428 unsigned int c_mmot_cold_025 = 0;
429 unsigned int c_mmot_cold_026 = 0;
430 unsigned int c_mmot_cold_027 = 0;
431 unsigned int c_mmot_hot_fSR_ok = 0;
432 unsigned int c_mmot_cold_029 = 0;
433 unsigned int c_mmot_cold_030 = 0;
434 unsigned int c_mmot_cold_031 = 0;
435 unsigned int c_mmot_cold_032 = 0;
436 unsigned int c_mmot_cold_033 = 0;
437 unsigned int c_mmot_bad_rcvr = 0;
438 unsigned int c_mmot_rcvr_swapped = 0;
439 unsigned int c_mmot_rcvr_locked = 0;
440 unsigned int c_mmot_rcvr_tswapped = 0;
441 unsigned int c_mmot_rcvr_freed = 0;
442 unsigned int c_mmot_g_slow_copyout6 = 0;
443 unsigned int c_mmot_g_slow_copyout5 = 0;
444 unsigned int c_mmot_cold_037 = 0;
445 unsigned int c_mmot_cold_038 = 0;
446 unsigned int c_mmot_cold_039 = 0;
447 unsigned int c_mmot_g_slow_copyout4 = 0;
448 unsigned int c_mmot_g_slow_copyout3 = 0;
449 unsigned int c_mmot_hot_ok1 = 0;
450 unsigned int c_mmot_hot_ok2 = 0;
451 unsigned int c_mmot_hot_ok3 = 0;
452 unsigned int c_mmot_g_slow_copyout1 = 0;
453 unsigned int c_mmot_g_slow_copyout2 = 0;
454 unsigned int c_mmot_getback_fast_copyin = 0;
455 unsigned int c_mmot_cold_048 = 0;
456 unsigned int c_mmot_getback_FastSR = 0;
457 unsigned int c_mmot_cold_050 = 0;
458 unsigned int c_mmot_cold_051 = 0;
459 unsigned int c_mmot_cold_052 = 0;
460 unsigned int c_mmot_cold_053 = 0;
461 unsigned int c_mmot_fastkernelreply = 0;
462 unsigned int c_mmot_cold_055 = 0;
463 unsigned int c_mmot_getback_fast_put = 0;
464 unsigned int c_mmot_LAST = 0; /* End Marker - Unused */
465
466 void db_mmot_zero_counters(void); /* forward; */
467 void db_mmot_show_counters(void); /* forward; */
468
469 void /* Call from the debugger to clear all counters */
470 db_mmot_zero_counters(void)
471 {
472 register unsigned int *ip = &c_mmot_FIRST;
473 while (ip <= &c_mmot_LAST)
474 *ip++ = 0;
475 }
476
477 void /* Call from the debugger to show all counters */
478 db_mmot_show_counters(void)
479 {
480 #define xx(str) printf("%s: %d\n", # str, str);
481
482 xx(c_mmot_combined_S_R);
483 xx(c_mach_msg_trap_switch_fast);
484 xx(c_mmot_kernel_send);
485 xx(c_mmot_cold_000);
486 xx(c_mmot_smallsendsize);
487 xx(c_mmot_oddsendsize);
488 xx(c_mmot_bigsendsize);
489 xx(c_mmot_copyinmsg_fail);
490 xx(c_mmot_g_slow_copyin3);
491 xx(c_mmot_cold_006);
492 xx(c_mmot_cold_007);
493 xx(c_mmot_cold_008);
494 xx(c_mmot_cold_009);
495 xx(c_mmot_cold_010);
496 xx(c_mmot_cold_012);
497 xx(c_mmot_cold_013);
498 xx(c_mmot_cold_014);
499 xx(c_mmot_cold_016);
500 xx(c_mmot_cold_018);
501 xx(c_mmot_cold_019);
502 xx(c_mmot_cold_020);
503 xx(c_mmot_cold_021);
504 xx(c_mmot_cold_022);
505 xx(c_mmot_cold_023);
506 xx(c_mmot_cold_024);
507 xx(c_mmot_cold_025);
508 xx(c_mmot_cold_026);
509 xx(c_mmot_cold_027);
510 xx(c_mmot_hot_fSR_ok);
511 xx(c_mmot_cold_029);
512 xx(c_mmot_cold_030);
513 xx(c_mmot_cold_031);
514 xx(c_mmot_cold_032);
515 xx(c_mmot_cold_033);
516 xx(c_mmot_bad_rcvr);
517 xx(c_mmot_rcvr_swapped);
518 xx(c_mmot_rcvr_locked);
519 xx(c_mmot_rcvr_tswapped);
520 xx(c_mmot_rcvr_freed);
521 xx(c_mmot_g_slow_copyout6);
522 xx(c_mmot_g_slow_copyout5);
523 xx(c_mmot_cold_037);
524 xx(c_mmot_cold_038);
525 xx(c_mmot_cold_039);
526 xx(c_mmot_g_slow_copyout4);
527 xx(c_mmot_g_slow_copyout3);
528 xx(c_mmot_g_slow_copyout1);
529 xx(c_mmot_hot_ok3);
530 xx(c_mmot_hot_ok2);
531 xx(c_mmot_hot_ok1);
532 xx(c_mmot_g_slow_copyout2);
533 xx(c_mmot_getback_fast_copyin);
534 xx(c_mmot_cold_048);
535 xx(c_mmot_getback_FastSR);
536 xx(c_mmot_cold_050);
537 xx(c_mmot_cold_051);
538 xx(c_mmot_cold_052);
539 xx(c_mmot_cold_053);
540 xx(c_mmot_fastkernelreply);
541 xx(c_mmot_cold_055);
542 xx(c_mmot_getback_fast_put);
543
544 #undef xx
545 }
546
547 #else /* !HOTPATH_DEBUG */
548
549 /*
550 * Duplicate just these few so we can always do a quick sanity check
551 */
552 unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */
553 unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */
554 unsigned int c_mmot_kernel_send = 0; /* kernel server calls */
555 #define HOT(expr) /* no optional counters */
556
557 #endif /* !HOTPATH_DEBUG */
558
559 boolean_t enable_hotpath = TRUE; /* Patchable, just in case ... */
560 #endif /* HOTPATH_ENABLE */
561
562 /*
563 * Routine: mach_msg_overwrite_trap [mach trap]
564 * Purpose:
565 * Possibly send a message; possibly receive a message.
566 * Conditions:
567 * Nothing locked.
568 * Returns:
569 * All of mach_msg_send and mach_msg_receive error codes.
570 */
571
572 mach_msg_return_t
573 mach_msg_overwrite_trap(
574 struct mach_msg_overwrite_trap_args *args)
575 {
576 mach_vm_address_t msg_addr = args->msg;
577 mach_msg_option_t option = args->option;
578 mach_msg_size_t send_size = args->send_size;
579 mach_msg_size_t rcv_size = args->rcv_size;
580 mach_port_name_t rcv_name = args->rcv_name;
581 mach_msg_timeout_t msg_timeout = args->timeout;
582 mach_port_name_t notify = args->notify;
583 mach_vm_address_t rcv_msg_addr = args->rcv_msg;
584 mach_msg_size_t scatter_list_size = 0; /* NOT INITIALIZED - but not used in pactice */
585 mach_port_seqno_t temp_seqno = 0;
586
587 register mach_msg_header_t *hdr;
588 mach_msg_return_t mr = MACH_MSG_SUCCESS;
589 /* mask out some of the options before entering the hot path */
590 mach_msg_option_t masked_option =
591 option & ~(MACH_SEND_TRAILER|MACH_RCV_TRAILER_MASK|MACH_RCV_LARGE);
592
593 #if ENABLE_HOTPATH
594 /* BEGINNING OF HOT PATH */
595 if ((masked_option == (MACH_SEND_MSG|MACH_RCV_MSG)) && enable_hotpath) {
596 thread_t self = current_thread();
597 mach_msg_format_0_trailer_t *trailer;
598 ipc_space_t space = self->task->itk_space;
599 ipc_kmsg_t kmsg;
600 register ipc_port_t dest_port;
601 ipc_object_t rcv_object;
602 ipc_mqueue_t rcv_mqueue;
603 mach_msg_size_t reply_size;
604
605 c_mmot_combined_S_R++;
606
607 /*
608 * This case is divided into ten sections, each
609 * with a label. There are five optimized
610 * sections and six unoptimized sections, which
611 * do the same thing but handle all possible
612 * cases and are slower.
613 *
614 * The five sections for an RPC are
615 * 1) Get request message into a buffer.
616 * 2) Copyin request message and rcv_name.
617 * (fast_copyin or slow_copyin)
618 * 3) Enqueue request and dequeue reply.
619 * (fast_send_receive or
620 * slow_send and slow_receive)
621 * 4) Copyout reply message.
622 * (fast_copyout or slow_copyout)
623 * 5) Put reply message to user's buffer.
624 *
625 * Keep the locking hierarchy firmly in mind.
626 * (First spaces, then ports, then port sets,
627 * then message queues.) Only a non-blocking
628 * attempt can be made to acquire locks out of
629 * order, or acquire two locks on the same level.
630 * Acquiring two locks on the same level will
631 * fail if the objects are really the same,
632 * unless simple locking is disabled. This is OK,
633 * because then the extra unlock does nothing.
634 *
635 * There are two major reasons these RPCs can't use
636 * ipc_thread_switch, and use slow_send/slow_receive:
637 * 1) Kernel RPCs.
638 * 2) Servers fall behind clients, so
639 * client doesn't find a blocked server thread and
640 * server finds waiting messages and can't block.
641 */
642
643 mr = ipc_kmsg_get(msg_addr, send_size, &kmsg);
644 if (mr != KERN_SUCCESS) {
645 return mr;
646 }
647 hdr = kmsg->ikm_header;
648 trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
649 send_size);
650
651 /*
652 * fast_copyin:
653 *
654 * optimized ipc_kmsg_copyin/ipc_mqueue_copyin
655 *
656 * We have the request message data in kmsg.
657 * Must still do copyin, send, receive, etc.
658 *
659 * If the message isn't simple, we can't combine
660 * ipc_kmsg_copyin_header and ipc_mqueue_copyin,
661 * because copyin of the message body might
662 * affect rcv_name.
663 */
664
665 switch (hdr->msgh_bits) {
666 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
667 MACH_MSG_TYPE_MAKE_SEND_ONCE): {
668 register ipc_entry_t table;
669 register ipc_entry_num_t size;
670 register ipc_port_t reply_port;
671
672 /* sending a request message */
673
674 {
675 register mach_port_index_t index;
676 register mach_port_gen_t gen;
677
678 {
679 register mach_port_name_t reply_name =
680 (mach_port_name_t)hdr->msgh_local_port;
681
682 if (reply_name != rcv_name) {
683 HOT(c_mmot_g_slow_copyin3++);
684 goto slow_copyin;
685 }
686
687 /* optimized ipc_entry_lookup of reply_name */
688
689 index = MACH_PORT_INDEX(reply_name);
690 gen = MACH_PORT_GEN(reply_name);
691
692 is_read_lock(space);
693 assert(space->is_active);
694
695 size = space->is_table_size;
696 table = space->is_table;
697
698 {
699 register ipc_entry_t entry;
700 register ipc_entry_bits_t bits;
701
702 if (index < size) {
703 entry = &table[index];
704 bits = entry->ie_bits;
705 if (IE_BITS_GEN(bits) != gen ||
706 (bits & IE_BITS_COLLISION)) {
707 entry = IE_NULL;
708 }
709 } else {
710 entry = IE_NULL;
711 bits = 0;
712 }
713 if (entry == IE_NULL) {
714 entry = ipc_entry_lookup(space, reply_name);
715 if (entry == IE_NULL) {
716 HOT(c_mmot_cold_006++);
717 goto abort_request_copyin;
718 }
719 bits = entry->ie_bits;
720 }
721
722 /* check type bit */
723
724 if (! (bits & MACH_PORT_TYPE_RECEIVE)) {
725 HOT(c_mmot_cold_007++);
726 goto abort_request_copyin;
727 }
728
729 reply_port = (ipc_port_t) entry->ie_object;
730 assert(reply_port != IP_NULL);
731 }
732 }
733 }
734
735 /* optimized ipc_entry_lookup of dest_name */
736
737 {
738 register mach_port_index_t index;
739 register mach_port_gen_t gen;
740
741 {
742 register mach_port_name_t dest_name =
743 (mach_port_name_t)hdr->msgh_remote_port;
744
745 index = MACH_PORT_INDEX(dest_name);
746 gen = MACH_PORT_GEN(dest_name);
747
748 {
749 register ipc_entry_t entry;
750 register ipc_entry_bits_t bits;
751
752 if (index < size) {
753 entry = &table[index];
754 bits = entry->ie_bits;
755 if (IE_BITS_GEN(bits) != gen ||
756 (bits & IE_BITS_COLLISION)) {
757 entry = IE_NULL;
758 }
759 } else {
760 entry = IE_NULL;
761 bits = 0;
762 }
763 if (entry == IE_NULL) {
764 entry = ipc_entry_lookup(space, dest_name);
765 if (entry == IE_NULL) {
766 HOT(c_mmot_cold_008++);
767 goto abort_request_copyin;
768 }
769 bits = entry->ie_bits;
770 }
771
772 /* check type bit */
773
774 if (! (bits & MACH_PORT_TYPE_SEND)) {
775 HOT(c_mmot_cold_009++);
776 goto abort_request_copyin;
777 }
778
779 assert(IE_BITS_UREFS(bits) > 0);
780
781 dest_port = (ipc_port_t) entry->ie_object;
782 assert(dest_port != IP_NULL);
783 }
784 }
785 }
786
787 /*
788 * To do an atomic copyin, need simultaneous
789 * locks on both ports and the space. If
790 * dest_port == reply_port, and simple locking is
791 * enabled, then we will abort. Otherwise it's
792 * OK to unlock twice.
793 */
794
795 ip_lock(dest_port);
796 if (!ip_active(dest_port) ||
797 !ip_lock_try(reply_port)) {
798 ip_unlock(dest_port);
799 HOT(c_mmot_cold_010++);
800 goto abort_request_copyin;
801 }
802 is_read_unlock(space);
803
804 assert(dest_port->ip_srights > 0);
805 dest_port->ip_srights++;
806 ip_reference(dest_port);
807
808 assert(ip_active(reply_port));
809 assert(reply_port->ip_receiver_name ==
810 (mach_port_name_t)hdr->msgh_local_port);
811 assert(reply_port->ip_receiver == space);
812
813 reply_port->ip_sorights++;
814 ip_reference(reply_port);
815
816 hdr->msgh_bits =
817 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
818 MACH_MSG_TYPE_PORT_SEND_ONCE);
819 hdr->msgh_remote_port = dest_port;
820 hdr->msgh_local_port = reply_port;
821
822 /* make sure we can queue to the destination */
823
824 if (dest_port->ip_receiver == ipc_space_kernel) {
825 /*
826 * The kernel server has a reference to
827 * the reply port, which it hands back
828 * to us in the reply message. We do
829 * not need to keep another reference to
830 * it.
831 */
832 ip_unlock(reply_port);
833
834 assert(ip_active(dest_port));
835 dest_port->ip_messages.imq_seqno++;
836 ip_unlock(dest_port);
837 goto kernel_send;
838 }
839
840 if (imq_full(&dest_port->ip_messages)) {
841 HOT(c_mmot_cold_013++);
842 goto abort_request_send_receive;
843 }
844
845 /* optimized ipc_mqueue_copyin */
846
847 rcv_object = (ipc_object_t) reply_port;
848 io_reference(rcv_object);
849 rcv_mqueue = &reply_port->ip_messages;
850 io_unlock(rcv_object);
851 HOT(c_mmot_hot_fSR_ok++);
852 goto fast_send_receive;
853
854 abort_request_copyin:
855 is_read_unlock(space);
856 goto slow_copyin;
857
858 abort_request_send_receive:
859 ip_unlock(dest_port);
860 ip_unlock(reply_port);
861 goto slow_send;
862 }
863
864 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
865 register ipc_entry_num_t size;
866 register ipc_entry_t table;
867
868 /* sending a reply message */
869
870 {
871 register mach_port_name_t reply_name =
872 (mach_port_name_t)hdr->msgh_local_port;
873
874 if (reply_name != MACH_PORT_NULL) {
875 HOT(c_mmot_cold_018++);
876 goto slow_copyin;
877 }
878 }
879
880 is_write_lock(space);
881 assert(space->is_active);
882
883 /* optimized ipc_entry_lookup */
884
885 size = space->is_table_size;
886 table = space->is_table;
887
888 {
889 register ipc_entry_t entry;
890 register mach_port_gen_t gen;
891 register mach_port_index_t index;
892
893 {
894 register mach_port_name_t dest_name =
895 (mach_port_name_t)hdr->msgh_remote_port;
896
897 index = MACH_PORT_INDEX(dest_name);
898 gen = MACH_PORT_GEN(dest_name);
899 }
900
901 if (index >= size) {
902 HOT(c_mmot_cold_019++);
903 goto abort_reply_dest_copyin;
904 }
905
906 entry = &table[index];
907
908 /* check generation, collision bit, and type bit */
909
910 if ((entry->ie_bits & (IE_BITS_GEN_MASK|
911 IE_BITS_COLLISION|
912 MACH_PORT_TYPE_SEND_ONCE)) !=
913 (gen | MACH_PORT_TYPE_SEND_ONCE)) {
914 HOT(c_mmot_cold_020++);
915 goto abort_reply_dest_copyin;
916 }
917
918 /* optimized ipc_right_copyin */
919
920 assert(IE_BITS_TYPE(entry->ie_bits) ==
921 MACH_PORT_TYPE_SEND_ONCE);
922 assert(IE_BITS_UREFS(entry->ie_bits) == 1);
923
924 if (entry->ie_request != 0) {
925 HOT(c_mmot_cold_021++);
926 goto abort_reply_dest_copyin;
927 }
928
929 dest_port = (ipc_port_t) entry->ie_object;
930 assert(dest_port != IP_NULL);
931
932 ip_lock(dest_port);
933 if (!ip_active(dest_port)) {
934 ip_unlock(dest_port);
935 HOT(c_mmot_cold_022++);
936 goto abort_reply_dest_copyin;
937 }
938
939 assert(dest_port->ip_sorights > 0);
940
941 /* optimized ipc_entry_dealloc */
942
943
944 entry->ie_bits = gen;
945 entry->ie_next = table->ie_next;
946 table->ie_next = index;
947 entry->ie_object = IO_NULL;
948 }
949
950 hdr->msgh_bits =
951 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
952 0);
953 hdr->msgh_remote_port = dest_port;
954
955 /* make sure we can queue to the destination */
956
957 assert(dest_port->ip_receiver != ipc_space_kernel);
958
959 /* optimized ipc_entry_lookup/ipc_mqueue_copyin */
960
961 {
962 register ipc_entry_t entry;
963 register ipc_entry_bits_t bits;
964
965 {
966 register mach_port_index_t index;
967 register mach_port_gen_t gen;
968
969 index = MACH_PORT_INDEX(rcv_name);
970 gen = MACH_PORT_GEN(rcv_name);
971
972 if (index < size) {
973 entry = &table[index];
974 bits = entry->ie_bits;
975 if (IE_BITS_GEN(bits) != gen ||
976 (bits & IE_BITS_COLLISION)) {
977 entry = IE_NULL;
978 }
979 } else {
980 entry = IE_NULL;
981 bits = 0;
982 }
983 if (entry == IE_NULL) {
984 entry = ipc_entry_lookup(space, rcv_name);
985 if (entry == IE_NULL) {
986 HOT(c_mmot_cold_024++);
987 goto abort_reply_rcv_copyin;
988 }
989 bits = entry->ie_bits;
990 }
991
992 }
993
994 /* check type bits; looking for receive or set */
995 #if 0
996 /*
997 * JMM - The check below for messages in the receive
998 * mqueue is insufficient to work with port sets, since
999 * the messages stay in the port queues. For now, don't
1000 * allow portsets (but receiving on portsets when sending
1001 * a message to a send-once right is actually a very
1002 * common case (so we should re-enable).
1003 */
1004 if (bits & MACH_PORT_TYPE_PORT_SET) {
1005 register ipc_pset_t rcv_pset;
1006
1007 rcv_pset = (ipc_pset_t) entry->ie_object;
1008 assert(rcv_pset != IPS_NULL);
1009
1010 ips_lock(rcv_pset);
1011 assert(ips_active(rcv_pset));
1012
1013 rcv_object = (ipc_object_t) rcv_pset;
1014 rcv_mqueue = &rcv_pset->ips_messages;
1015 } else
1016 #endif /* 0 */
1017 if (bits & MACH_PORT_TYPE_RECEIVE) {
1018 register ipc_port_t rcv_port;
1019
1020 rcv_port = (ipc_port_t) entry->ie_object;
1021 assert(rcv_port != IP_NULL);
1022
1023 if (!ip_lock_try(rcv_port)) {
1024 HOT(c_mmot_cold_025++);
1025 goto abort_reply_rcv_copyin;
1026 }
1027 assert(ip_active(rcv_port));
1028
1029 if (rcv_port->ip_pset_count != 0) {
1030 ip_unlock(rcv_port);
1031 HOT(c_mmot_cold_026++);
1032 goto abort_reply_rcv_copyin;
1033 }
1034
1035 rcv_object = (ipc_object_t) rcv_port;
1036 rcv_mqueue = &rcv_port->ip_messages;
1037 } else {
1038 HOT(c_mmot_cold_027++);
1039 goto abort_reply_rcv_copyin;
1040 }
1041 }
1042
1043 is_write_unlock(space);
1044 io_reference(rcv_object);
1045 io_unlock(rcv_object);
1046 HOT(c_mmot_hot_fSR_ok++);
1047 goto fast_send_receive;
1048
1049 abort_reply_dest_copyin:
1050 is_write_unlock(space);
1051 HOT(c_mmot_cold_029++);
1052 goto slow_copyin;
1053
1054 abort_reply_rcv_copyin:
1055 ip_unlock(dest_port);
1056 is_write_unlock(space);
1057 HOT(c_mmot_cold_030++);
1058 goto slow_send;
1059 }
1060
1061 default:
1062 HOT(c_mmot_cold_031++);
1063 goto slow_copyin;
1064 }
1065 /*NOTREACHED*/
1066
1067 fast_send_receive:
1068 /*
1069 * optimized ipc_mqueue_send/ipc_mqueue_receive
1070 *
1071 * Finished get/copyin of kmsg and copyin of rcv_name.
1072 * space is unlocked, dest_port is locked,
1073 * we can queue kmsg to dest_port,
1074 * rcv_mqueue is set, and rcv_object holds a ref
1075 * so the mqueue cannot go away.
1076 *
1077 * JMM - For now, rcv_object is just a port. Portsets
1078 * are disabled for the time being.
1079 */
1080
1081 assert(ip_active(dest_port));
1082 assert(dest_port->ip_receiver != ipc_space_kernel);
1083 // assert(!imq_full(&dest_port->ip_messages) ||
1084 // (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1085 // MACH_MSG_TYPE_PORT_SEND_ONCE));
1086 assert((hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0);
1087
1088 {
1089 register ipc_mqueue_t dest_mqueue;
1090 wait_queue_t waitq;
1091 thread_t receiver;
1092 processor_t processor;
1093 boolean_t still_running;
1094 spl_t s;
1095
1096 s = splsched();
1097 processor = current_processor();
1098 if (processor->current_pri >= BASEPRI_RTQUEUES)
1099 goto abort_send_receive1;
1100
1101 dest_mqueue = &dest_port->ip_messages;
1102 waitq = &dest_mqueue->imq_wait_queue;
1103 imq_lock(dest_mqueue);
1104
1105 wait_queue_peek64_locked(waitq, IPC_MQUEUE_RECEIVE, &receiver, &waitq);
1106 /* queue still locked, thread locked - but still on q */
1107
1108 if ( receiver == THREAD_NULL ) {
1109 abort_send_receive:
1110 imq_unlock(dest_mqueue);
1111 abort_send_receive1:
1112 splx(s);
1113 ip_unlock(dest_port);
1114 ipc_object_release(rcv_object);
1115 HOT(c_mmot_cold_032++);
1116 goto slow_send;
1117 }
1118
1119 assert(receiver->state & TH_WAIT);
1120 assert(receiver->wait_queue == waitq);
1121 assert(receiver->wait_event == IPC_MQUEUE_RECEIVE);
1122
1123 /*
1124 * Make sure that the scheduling restrictions of the receiver
1125 * are consistent with a handoff here (if it comes down to that).
1126 */
1127 if ( receiver->sched_pri >= BASEPRI_RTQUEUES ||
1128 receiver->processor_set != processor->processor_set ||
1129 (receiver->bound_processor != PROCESSOR_NULL &&
1130 receiver->bound_processor != processor)) {
1131 HOT(c_mmot_cold_033++);
1132 fall_off:
1133 thread_unlock(receiver);
1134 if (waitq != &dest_mqueue->imq_wait_queue)
1135 wait_queue_unlock(waitq);
1136 goto abort_send_receive;
1137 }
1138
1139 /*
1140 * Check that the receiver can stay on the hot path.
1141 */
1142 if (ipc_kmsg_copyout_size(kmsg, receiver->map) +
1143 REQUESTED_TRAILER_SIZE(receiver->ith_option) > receiver->ith_msize) {
1144 /*
1145 * The receiver can't accept the message.
1146 */
1147 HOT(c_mmot_bad_rcvr++);
1148 goto fall_off;
1149 }
1150
1151 /*
1152 * Before committing to the handoff, make sure that we are
1153 * really going to block (i.e. there are no messages already
1154 * queued for us. This violates lock ordering, so make sure
1155 * we don't deadlock. After the trylock succeeds below, we
1156 * may have up to 3 message queues locked:
1157 * - the dest port mqueue
1158 * - a portset mqueue (where waiting receiver was found)
1159 * - finally our own rcv_mqueue
1160 *
1161 * JMM - Need to make this check appropriate for portsets as
1162 * well before re-enabling them.
1163 */
1164 if (!imq_lock_try(rcv_mqueue)) {
1165 goto fall_off;
1166 }
1167 if (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL) {
1168 imq_unlock(rcv_mqueue);
1169 HOT(c_mmot_cold_033++);
1170 goto fall_off;
1171 }
1172
1173 /* At this point we are committed to do the "handoff". */
1174 c_mach_msg_trap_switch_fast++;
1175
1176 /*
1177 * Go ahead and pull the receiver from the waitq. If the
1178 * waitq wasn't the one for the mqueue, unlock it.
1179 */
1180 wait_queue_pull_thread_locked(waitq,
1181 receiver,
1182 (waitq != &dest_mqueue->imq_wait_queue));
1183
1184 /*
1185 * Store the kmsg and seqno where the receiver can pick it up.
1186 */
1187 receiver->ith_state = MACH_MSG_SUCCESS;
1188 receiver->ith_kmsg = kmsg;
1189 receiver->ith_seqno = dest_mqueue->imq_seqno++;
1190
1191 /*
1192 * Unblock the receiver. If it was still running on another
1193 * CPU, we'll give it a chance to run with the message where
1194 * it is (and just select someother thread to run here).
1195 * Otherwise, we'll invoke it here as part of the handoff.
1196 */
1197 still_running = thread_unblock(receiver, THREAD_AWAKENED);
1198
1199 thread_unlock(receiver);
1200
1201 imq_unlock(dest_mqueue);
1202 ip_unlock(dest_port);
1203 current_task()->messages_sent++;
1204
1205
1206 /*
1207 * Put self on receive port's queue.
1208 * Also save state that the sender of
1209 * our reply message needs to determine if it
1210 * can hand off directly back to us.
1211 */
1212 thread_lock(self);
1213 self->ith_msg_addr = (rcv_msg_addr) ? rcv_msg_addr : msg_addr;
1214 self->ith_object = rcv_object; /* still holds reference */
1215 self->ith_msize = rcv_size;
1216 self->ith_option = option;
1217 self->ith_scatter_list_size = scatter_list_size;
1218 self->ith_continuation = thread_syscall_return;
1219
1220 waitq = &rcv_mqueue->imq_wait_queue;
1221 (void)wait_queue_assert_wait64_locked(waitq,
1222 IPC_MQUEUE_RECEIVE,
1223 THREAD_ABORTSAFE, 0,
1224 self);
1225 thread_unlock(self);
1226 imq_unlock(rcv_mqueue);
1227
1228 /*
1229 * If the receiving thread wasn't still running, we switch directly
1230 * to it here. Otherwise we let the scheduler pick something for
1231 * here. In either case, block this thread as though it had called
1232 * ipc_mqueue_receive.
1233 */
1234 if (still_running) {
1235 splx(s);
1236 thread_block(ipc_mqueue_receive_continue);
1237 } else {
1238 thread_run(self, ipc_mqueue_receive_continue, NULL, receiver);
1239 }
1240 /* NOTREACHED */
1241 }
1242
1243 fast_copyout:
1244 /*
1245 * Nothing locked and no references held, except
1246 * we have kmsg with msgh_seqno filled in. Must
1247 * still check against rcv_size and do
1248 * ipc_kmsg_copyout/ipc_kmsg_put.
1249 */
1250
1251 reply_size = send_size + trailer->msgh_trailer_size;
1252 if (rcv_size < reply_size) {
1253 HOT(c_mmot_g_slow_copyout6++);
1254 goto slow_copyout;
1255 }
1256
1257 /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */
1258
1259 switch (hdr->msgh_bits) {
1260 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1261 MACH_MSG_TYPE_PORT_SEND_ONCE): {
1262 ipc_port_t reply_port =
1263 (ipc_port_t) hdr->msgh_local_port;
1264 mach_port_name_t dest_name, reply_name;
1265
1266 /* receiving a request message */
1267
1268 if (!IP_VALID(reply_port)) {
1269 HOT(c_mmot_g_slow_copyout5++);
1270 goto slow_copyout;
1271 }
1272
1273 is_write_lock(space);
1274 assert(space->is_active);
1275
1276 /*
1277 * To do an atomic copyout, need simultaneous
1278 * locks on both ports and the space. If
1279 * dest_port == reply_port, and simple locking is
1280 * enabled, then we will abort. Otherwise it's
1281 * OK to unlock twice.
1282 */
1283
1284 ip_lock(dest_port);
1285 if (!ip_active(dest_port) ||
1286 !ip_lock_try(reply_port)) {
1287 HOT(c_mmot_cold_037++);
1288 goto abort_request_copyout;
1289 }
1290
1291 if (!ip_active(reply_port)) {
1292 ip_unlock(reply_port);
1293 HOT(c_mmot_cold_038++);
1294 goto abort_request_copyout;
1295 }
1296
1297 assert(reply_port->ip_sorights > 0);
1298 ip_unlock(reply_port);
1299
1300 {
1301 register ipc_entry_t table;
1302 register ipc_entry_t entry;
1303 register mach_port_index_t index;
1304
1305 /* optimized ipc_entry_get */
1306
1307 table = space->is_table;
1308 index = table->ie_next;
1309
1310 if (index == 0) {
1311 HOT(c_mmot_cold_039++);
1312 goto abort_request_copyout;
1313 }
1314
1315 entry = &table[index];
1316 table->ie_next = entry->ie_next;
1317 entry->ie_request = 0;
1318
1319 {
1320 register mach_port_gen_t gen;
1321
1322 assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
1323 gen = IE_BITS_NEW_GEN(entry->ie_bits);
1324
1325 reply_name = MACH_PORT_MAKE(index, gen);
1326
1327 /* optimized ipc_right_copyout */
1328
1329 entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
1330 }
1331
1332 assert(MACH_PORT_VALID(reply_name));
1333 entry->ie_object = (ipc_object_t) reply_port;
1334 is_write_unlock(space);
1335 }
1336
1337 /* optimized ipc_object_copyout_dest */
1338
1339 assert(dest_port->ip_srights > 0);
1340 ip_release(dest_port);
1341
1342 if (dest_port->ip_receiver == space)
1343 dest_name = dest_port->ip_receiver_name;
1344 else
1345 dest_name = MACH_PORT_NULL;
1346
1347 if ((--dest_port->ip_srights == 0) &&
1348 (dest_port->ip_nsrequest != IP_NULL)) {
1349 ipc_port_t nsrequest;
1350 mach_port_mscount_t mscount;
1351
1352 /* a rather rare case */
1353
1354 nsrequest = dest_port->ip_nsrequest;
1355 mscount = dest_port->ip_mscount;
1356 dest_port->ip_nsrequest = IP_NULL;
1357 ip_unlock(dest_port);
1358 ipc_notify_no_senders(nsrequest, mscount);
1359 } else
1360 ip_unlock(dest_port);
1361
1362 hdr->msgh_bits =
1363 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1364 MACH_MSG_TYPE_PORT_SEND);
1365 hdr->msgh_remote_port = (mach_port_t)reply_name;
1366 hdr->msgh_local_port = (mach_port_t)dest_name;
1367 HOT(c_mmot_hot_ok1++);
1368 goto fast_put;
1369
1370 abort_request_copyout:
1371 ip_unlock(dest_port);
1372 is_write_unlock(space);
1373 HOT(c_mmot_g_slow_copyout4++);
1374 goto slow_copyout;
1375 }
1376
1377 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1378 register mach_port_name_t dest_name;
1379
1380 /* receiving a reply message */
1381
1382 ip_lock(dest_port);
1383 if (!ip_active(dest_port)) {
1384 ip_unlock(dest_port);
1385 HOT(c_mmot_g_slow_copyout3++);
1386 goto slow_copyout;
1387 }
1388
1389 /* optimized ipc_object_copyout_dest */
1390
1391 assert(dest_port->ip_sorights > 0);
1392
1393 if (dest_port->ip_receiver == space) {
1394 ip_release(dest_port);
1395 dest_port->ip_sorights--;
1396 dest_name = dest_port->ip_receiver_name;
1397 ip_unlock(dest_port);
1398 } else {
1399 ip_unlock(dest_port);
1400
1401 ipc_notify_send_once(dest_port);
1402 dest_name = MACH_PORT_NULL;
1403 }
1404
1405 hdr->msgh_bits = MACH_MSGH_BITS(0,
1406 MACH_MSG_TYPE_PORT_SEND_ONCE);
1407 hdr->msgh_remote_port = MACH_PORT_NULL;
1408 hdr->msgh_local_port = (ipc_port_t)dest_name;
1409 HOT(c_mmot_hot_ok2++);
1410 goto fast_put;
1411 }
1412
1413 case MACH_MSGH_BITS_COMPLEX|
1414 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1415 register mach_port_name_t dest_name;
1416
1417 /* receiving a complex reply message */
1418
1419 ip_lock(dest_port);
1420 if (!ip_active(dest_port)) {
1421 ip_unlock(dest_port);
1422 HOT(c_mmot_g_slow_copyout1++);
1423 goto slow_copyout;
1424 }
1425
1426 /* optimized ipc_object_copyout_dest */
1427
1428 assert(dest_port->ip_sorights > 0);
1429
1430 if (dest_port->ip_receiver == space) {
1431 ip_release(dest_port);
1432 dest_port->ip_sorights--;
1433 dest_name = dest_port->ip_receiver_name;
1434 ip_unlock(dest_port);
1435 } else {
1436 ip_unlock(dest_port);
1437
1438 ipc_notify_send_once(dest_port);
1439 dest_name = MACH_PORT_NULL;
1440 }
1441
1442 hdr->msgh_bits =
1443 MACH_MSGH_BITS_COMPLEX |
1444 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE);
1445 hdr->msgh_remote_port = MACH_PORT_NULL;
1446 hdr->msgh_local_port = (mach_port_t)dest_name;
1447
1448 mr = ipc_kmsg_copyout_body(kmsg, space,
1449 current_map(),
1450 MACH_MSG_BODY_NULL);
1451 /* hdr and send_size may be invalid now - done use */
1452 if (mr != MACH_MSG_SUCCESS) {
1453 if (ipc_kmsg_put(msg_addr, kmsg,
1454 kmsg->ikm_header->msgh_size +
1455 trailer->msgh_trailer_size) ==
1456 MACH_RCV_INVALID_DATA)
1457 return MACH_RCV_INVALID_DATA;
1458 else
1459 return mr | MACH_RCV_BODY_ERROR;
1460 }
1461 HOT(c_mmot_hot_ok3++);
1462 goto fast_put;
1463 }
1464
1465 default:
1466 HOT(c_mmot_g_slow_copyout2++);
1467 goto slow_copyout;
1468 }
1469 /*NOTREACHED*/
1470
1471 fast_put:
1472 mr = ipc_kmsg_put(rcv_msg_addr ? rcv_msg_addr : msg_addr,
1473 kmsg,
1474 kmsg->ikm_header->msgh_size +
1475 trailer->msgh_trailer_size);
1476 if (mr != MACH_MSG_SUCCESS) {
1477 return MACH_RCV_INVALID_DATA;
1478 }
1479 current_task()->messages_received++;
1480 return mr;
1481
1482
1483 /* BEGINNING OF WARM PATH */
1484
1485 /*
1486 * The slow path has a few non-register temporary
1487 * variables used only for call-by-reference.
1488 */
1489
1490 slow_copyin:
1491 {
1492 register mach_port_name_t reply_name =
1493 (mach_port_name_t)hdr->msgh_local_port;
1494
1495
1496 /*
1497 * We have the message data in kmsg, but
1498 * we still need to copyin, send it,
1499 * receive a reply, and do copyout.
1500 */
1501
1502 mr = ipc_kmsg_copyin(kmsg, space, current_map(),
1503 MACH_PORT_NULL);
1504 if (mr != MACH_MSG_SUCCESS) {
1505 ipc_kmsg_free(kmsg);
1506 return(mr);
1507 }
1508
1509 /*
1510 * LP64support - We have to recompute the header pointer
1511 * and send_size - as they could have changed during the
1512 * complex copyin.
1513 */
1514 hdr = kmsg->ikm_header;
1515 send_size = hdr->msgh_size;
1516
1517 /* try to get back on optimized path */
1518 if ((reply_name != rcv_name) ||
1519 (hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR)) {
1520 HOT(c_mmot_cold_048++);
1521 goto slow_send;
1522 }
1523
1524 dest_port = (ipc_port_t) hdr->msgh_remote_port;
1525 assert(IP_VALID(dest_port));
1526
1527 ip_lock(dest_port);
1528 if (!ip_active(dest_port)) {
1529 ip_unlock(dest_port);
1530 goto slow_send;
1531 }
1532
1533 if (dest_port->ip_receiver == ipc_space_kernel) {
1534 dest_port->ip_messages.imq_seqno++;
1535 ip_unlock(dest_port);
1536 goto kernel_send;
1537 }
1538
1539 if (!imq_full(&dest_port->ip_messages) ||
1540 (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) ==
1541 MACH_MSG_TYPE_PORT_SEND_ONCE))
1542 {
1543 /*
1544 * Try an optimized ipc_mqueue_copyin.
1545 * It will work if this is a request message.
1546 */
1547
1548 register ipc_port_t reply_port;
1549
1550 reply_port = (ipc_port_t) hdr->msgh_local_port;
1551 if (IP_VALID(reply_port)) {
1552 if (ip_lock_try(reply_port)) {
1553 if (ip_active(reply_port) &&
1554 reply_port->ip_receiver == space &&
1555 reply_port->ip_receiver_name == rcv_name &&
1556 reply_port->ip_pset_count == 0)
1557 {
1558 /* Grab a reference to the reply port. */
1559 rcv_object = (ipc_object_t) reply_port;
1560 io_reference(rcv_object);
1561 rcv_mqueue = &reply_port->ip_messages;
1562 io_unlock(rcv_object);
1563 HOT(c_mmot_getback_FastSR++);
1564 goto fast_send_receive;
1565 }
1566 ip_unlock(reply_port);
1567 }
1568 }
1569 }
1570
1571 ip_unlock(dest_port);
1572 HOT(c_mmot_cold_050++);
1573 goto slow_send;
1574
1575 kernel_send:
1576 /*
1577 * Special case: send message to kernel services.
1578 * The request message has been copied into the
1579 * kmsg. Nothing is locked.
1580 */
1581
1582 {
1583 register ipc_port_t reply_port;
1584 spl_t s;
1585
1586 /*
1587 * Perform the kernel function.
1588 */
1589 c_mmot_kernel_send++;
1590
1591 current_task()->messages_sent++;
1592
1593 kmsg = ipc_kobject_server(kmsg);
1594 if (kmsg == IKM_NULL) {
1595 /*
1596 * No reply. Take the
1597 * slow receive path.
1598 */
1599 HOT(c_mmot_cold_051++);
1600 goto slow_get_rcv_port;
1601 }
1602
1603 /*
1604 * Check that:
1605 * the reply port is alive
1606 * we hold the receive right
1607 * the name has not changed.
1608 * the port is not in a set
1609 * If any of these are not true,
1610 * we cannot directly receive the reply
1611 * message.
1612 */
1613 hdr = kmsg->ikm_header;
1614 send_size = hdr->msgh_size;
1615 trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1616 round_msg(send_size));
1617 reply_port = (ipc_port_t) hdr->msgh_remote_port;
1618 ip_lock(reply_port);
1619
1620 if ((!ip_active(reply_port)) ||
1621 (reply_port->ip_receiver != space) ||
1622 (reply_port->ip_receiver_name != rcv_name) ||
1623 (reply_port->ip_pset_count != 0))
1624 {
1625 ip_unlock(reply_port);
1626 ipc_kmsg_send_always(kmsg);
1627 HOT(c_mmot_cold_052++);
1628 goto slow_get_rcv_port;
1629 }
1630
1631 s = splsched();
1632 rcv_mqueue = &reply_port->ip_messages;
1633 imq_lock(rcv_mqueue);
1634
1635 /* keep port locked, and don`t change ref count yet */
1636
1637 /*
1638 * If there are messages on the port
1639 * or other threads waiting for a message,
1640 * we cannot directly receive the reply.
1641 */
1642 if (!wait_queue_empty(&rcv_mqueue->imq_wait_queue) ||
1643 (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL))
1644 {
1645 imq_unlock(rcv_mqueue);
1646 splx(s);
1647 ip_unlock(reply_port);
1648 ipc_kmsg_send_always(kmsg);
1649 HOT(c_mmot_cold_053++);
1650 goto slow_get_rcv_port;
1651 }
1652
1653 /*
1654 * We can directly receive this reply.
1655 * Since there were no messages queued
1656 * on the reply port, there should be
1657 * no threads blocked waiting to send.
1658 */
1659 dest_port = reply_port;
1660 temp_seqno = rcv_mqueue->imq_seqno++;
1661 imq_unlock(rcv_mqueue);
1662 splx(s);
1663
1664 /*
1665 * inline ipc_object_release.
1666 * Port is still locked.
1667 * Reference count was not incremented.
1668 */
1669 ip_check_unlock(reply_port);
1670
1671 if (option & MACH_RCV_TRAILER_MASK) {
1672 trailer->msgh_seqno = temp_seqno;
1673 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
1674 }
1675 /* copy out the kernel reply */
1676 HOT(c_mmot_fastkernelreply++);
1677 goto fast_copyout;
1678 }
1679
1680 slow_send:
1681 /*
1682 * Nothing is locked. We have acquired kmsg, but
1683 * we still need to send it and receive a reply.
1684 */
1685
1686 mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE,
1687 MACH_MSG_TIMEOUT_NONE);
1688 if (mr != MACH_MSG_SUCCESS) {
1689 mr |= ipc_kmsg_copyout_pseudo(kmsg, space,
1690 current_map(),
1691 MACH_MSG_BODY_NULL);
1692
1693 (void) ipc_kmsg_put(msg_addr, kmsg,
1694 kmsg->ikm_header->msgh_size);
1695 return(mr);
1696 }
1697
1698 slow_get_rcv_port:
1699 /*
1700 * We have sent the message. Copy in the receive port.
1701 */
1702 mr = ipc_mqueue_copyin(space, rcv_name,
1703 &rcv_mqueue, &rcv_object);
1704 if (mr != MACH_MSG_SUCCESS) {
1705 return(mr);
1706 }
1707 /* hold ref for rcv_object */
1708
1709 /*
1710 * slow_receive:
1711 *
1712 * Now we have sent the request and copied in rcv_name,
1713 * and hold ref for rcv_object (to keep mqueue alive).
1714 * Just receive a reply and try to get back to fast path.
1715 */
1716
1717 self->ith_continuation = (void (*)(mach_msg_return_t))0;
1718 ipc_mqueue_receive(rcv_mqueue,
1719 MACH_MSG_OPTION_NONE,
1720 MACH_MSG_SIZE_MAX,
1721 MACH_MSG_TIMEOUT_NONE,
1722 THREAD_ABORTSAFE);
1723
1724 mr = self->ith_state;
1725 temp_seqno = self->ith_seqno;
1726
1727 ipc_object_release(rcv_object);
1728
1729 if (mr != MACH_MSG_SUCCESS) {
1730 return(mr);
1731 }
1732
1733 kmsg = self->ith_kmsg;
1734 hdr = kmsg->ikm_header;
1735 send_size = hdr->msgh_size;
1736 trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr +
1737 round_msg(send_size));
1738 if (option & MACH_RCV_TRAILER_MASK) {
1739 trailer->msgh_seqno = temp_seqno;
1740 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
1741 }
1742 dest_port = (ipc_port_t) hdr->msgh_remote_port;
1743 HOT(c_mmot_cold_055++);
1744 goto fast_copyout;
1745
1746 slow_copyout:
1747 /*
1748 * Nothing locked and no references held, except
1749 * we have kmsg with msgh_seqno filled in. Must
1750 * still check against rcv_size and do
1751 * ipc_kmsg_copyout/ipc_kmsg_put.
1752 */
1753
1754 /* LP64support - have to compute real size as it would be received */
1755 reply_size = ipc_kmsg_copyout_size(kmsg, current_map()) +
1756 REQUESTED_TRAILER_SIZE(option);
1757 temp_seqno = trailer->msgh_seqno;
1758 if (rcv_size < reply_size) {
1759 if (msg_receive_error(kmsg, msg_addr, option, temp_seqno,
1760 space) == MACH_RCV_INVALID_DATA) {
1761 mr = MACH_RCV_INVALID_DATA;
1762 return(mr);
1763 }
1764 else {
1765 mr = MACH_RCV_TOO_LARGE;
1766 return(mr);
1767 }
1768 }
1769
1770 mr = ipc_kmsg_copyout(kmsg, space, current_map(),
1771 MACH_PORT_NULL, MACH_MSG_BODY_NULL);
1772 if (mr != MACH_MSG_SUCCESS) {
1773 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
1774 if (ipc_kmsg_put(msg_addr, kmsg, reply_size) ==
1775 MACH_RCV_INVALID_DATA)
1776 mr = MACH_RCV_INVALID_DATA;
1777 }
1778 else {
1779 if (msg_receive_error(kmsg, msg_addr, option,
1780 temp_seqno, space) == MACH_RCV_INVALID_DATA)
1781 mr = MACH_RCV_INVALID_DATA;
1782 }
1783
1784 return(mr);
1785 }
1786
1787 /* try to get back on optimized path */
1788 HOT(c_mmot_getback_fast_put++);
1789 goto fast_put;
1790
1791 /*NOTREACHED*/
1792 }
1793 } /* END OF HOT PATH */
1794 #endif /* ENABLE_HOTPATH */
1795
1796 if (option & MACH_SEND_MSG) {
1797 ipc_space_t space = current_space();
1798 vm_map_t map = current_map();
1799 ipc_kmsg_t kmsg;
1800
1801 mr = ipc_kmsg_get(msg_addr, send_size, &kmsg);
1802
1803 if (mr != MACH_MSG_SUCCESS)
1804 return mr;
1805
1806 if (option & MACH_SEND_CANCEL) {
1807 if (notify == MACH_PORT_NULL)
1808 mr = MACH_SEND_INVALID_NOTIFY;
1809 else
1810 mr = ipc_kmsg_copyin(kmsg, space, map, notify);
1811 } else
1812 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
1813 if (mr != MACH_MSG_SUCCESS) {
1814 ipc_kmsg_free(kmsg);
1815 return mr;
1816 }
1817
1818 mr = ipc_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, msg_timeout);
1819
1820 if (mr != MACH_MSG_SUCCESS) {
1821 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL);
1822 (void) ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size);
1823 return mr;
1824 }
1825
1826 }
1827
1828 if (option & MACH_RCV_MSG) {
1829 thread_t self = current_thread();
1830 ipc_space_t space = current_space();
1831 ipc_object_t object;
1832 ipc_mqueue_t mqueue;
1833
1834 mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
1835 if (mr != MACH_MSG_SUCCESS) {
1836 return mr;
1837 }
1838 /* hold ref for object */
1839
1840 /*
1841 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
1842 * and receive buffer
1843 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
1844 * alternate receive buffer (separate send and receive buffers).
1845 */
1846 if (option & MACH_RCV_OVERWRITE)
1847 self->ith_msg_addr = rcv_msg_addr;
1848 else if (rcv_msg_addr != (mach_vm_address_t)0)
1849 self->ith_msg_addr = rcv_msg_addr;
1850 else
1851 self->ith_msg_addr = msg_addr;
1852 self->ith_object = object;
1853 self->ith_msize = rcv_size;
1854 self->ith_option = option;
1855 self->ith_scatter_list_size = scatter_list_size;
1856 self->ith_continuation = thread_syscall_return;
1857
1858 ipc_mqueue_receive(mqueue, option, rcv_size, msg_timeout, THREAD_ABORTSAFE);
1859 if ((option & MACH_RCV_TIMEOUT) && msg_timeout == 0)
1860 thread_poll_yield(self);
1861 return mach_msg_receive_results();
1862 }
1863
1864 return MACH_MSG_SUCCESS;
1865 }
1866
1867 /*
1868 * Routine: mach_msg_trap [mach trap]
1869 * Purpose:
1870 * Possibly send a message; possibly receive a message.
1871 * Conditions:
1872 * Nothing locked.
1873 * Returns:
1874 * All of mach_msg_send and mach_msg_receive error codes.
1875 */
1876
1877 mach_msg_return_t
1878 mach_msg_trap(
1879 struct mach_msg_overwrite_trap_args *args)
1880 {
1881 kern_return_t kr;
1882 args->rcv_msg = (mach_vm_address_t)0;
1883
1884 kr = mach_msg_overwrite_trap(args);
1885 return kr;
1886 }
1887
1888
1889 /*
1890 * Routine: msg_receive_error [internal]
1891 * Purpose:
1892 * Builds a minimal header/trailer and copies it to
1893 * the user message buffer. Invoked when in the case of a
1894 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1895 * Conditions:
1896 * Nothing locked.
1897 * Returns:
1898 * MACH_MSG_SUCCESS minimal header/trailer copied
1899 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1900 */
1901
1902 mach_msg_return_t
1903 msg_receive_error(
1904 ipc_kmsg_t kmsg,
1905 mach_vm_address_t msg_addr,
1906 mach_msg_option_t option,
1907 mach_port_seqno_t seqno,
1908 ipc_space_t space)
1909 {
1910 mach_msg_format_0_trailer_t *trailer;
1911
1912 /*
1913 * Copy out the destination port in the message.
1914 * Destroy all other rights and memory in the message.
1915 */
1916 ipc_kmsg_copyout_dest(kmsg, space);
1917
1918 /*
1919 * Build a minimal message with the requested trailer.
1920 */
1921 trailer = (mach_msg_format_0_trailer_t *)
1922 ((vm_offset_t)kmsg->ikm_header +
1923 round_msg(sizeof(mach_msg_header_t)));
1924 kmsg->ikm_header->msgh_size = sizeof(mach_msg_header_t);
1925 bcopy( (char *)&trailer_template,
1926 (char *)trailer,
1927 sizeof(trailer_template));
1928 if (option & MACH_RCV_TRAILER_MASK) {
1929 trailer->msgh_seqno = seqno;
1930 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
1931 }
1932
1933 /*
1934 * Copy the message to user space
1935 */
1936 if (ipc_kmsg_put(msg_addr, kmsg, kmsg->ikm_header->msgh_size +
1937 trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA)
1938 return(MACH_RCV_INVALID_DATA);
1939 else
1940 return(MACH_MSG_SUCCESS);
1941 }