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