]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ipc_mig.c
928832f10aa94000b2384a3ed1a3c8859237dae7
[apple/xnu.git] / osfmk / kern / ipc_mig.c
1 /*
2 * Copyright (c) 2000 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 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 #include <norma_vm.h>
54 #include <mach_rt.h>
55
56 #include <mach/boolean.h>
57 #include <mach/port.h>
58 #include <mach/thread_status.h>
59 #include <mach/mig_errors.h>
60 #include <mach/mach_types.h>
61 #include <mach/mach_traps.h>
62 #include <kern/ast.h>
63 #include <kern/ipc_tt.h>
64 #include <kern/ipc_mig.h>
65 #include <kern/task.h>
66 #include <kern/thread.h>
67 #include <kern/ipc_kobject.h>
68 #include <kern/misc_protos.h>
69 #include <vm/vm_map.h>
70 #include <ipc/port.h>
71 #include <ipc/ipc_kmsg.h>
72 #include <ipc/ipc_entry.h>
73 #include <ipc/ipc_object.h>
74 #include <ipc/ipc_mqueue.h>
75 #include <ipc/ipc_space.h>
76 #include <ipc/ipc_port.h>
77 #include <ipc/ipc_pset.h>
78
79 /* Default (zeroed) template for qos */
80
81 static mach_port_qos_t qos_template;
82
83 /*
84 * Routine: mach_msg_send_from_kernel
85 * Purpose:
86 * Send a message from the kernel.
87 *
88 * This is used by the client side of KernelUser interfaces
89 * to implement SimpleRoutines. Currently, this includes
90 * memory_object messages.
91 * Conditions:
92 * Nothing locked.
93 * Returns:
94 * MACH_MSG_SUCCESS Sent the message.
95 * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer
96 * MACH_SEND_INVALID_DEST Bad destination port.
97 */
98
99 mach_msg_return_t
100 mach_msg_send_from_kernel(
101 mach_msg_header_t *msg,
102 mach_msg_size_t send_size)
103 {
104 ipc_kmsg_t kmsg;
105 mach_msg_return_t mr;
106
107 if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port))
108 return MACH_SEND_INVALID_DEST;
109
110 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
111 if (mr != MACH_MSG_SUCCESS)
112 return mr;
113
114 ipc_kmsg_copyin_from_kernel(kmsg);
115 ipc_kmsg_send_always(kmsg);
116
117 return MACH_MSG_SUCCESS;
118 }
119
120 /*
121 * Routine: mach_msg_rpc_from_kernel
122 * Purpose:
123 * Send a message from the kernel and receive a reply.
124 * Uses ith_rpc_reply for the reply port.
125 *
126 * This is used by the client side of KernelUser interfaces
127 * to implement Routines.
128 * Conditions:
129 * Nothing locked.
130 * Returns:
131 * MACH_MSG_SUCCESS Sent the message.
132 * MACH_RCV_PORT_DIED The reply port was deallocated.
133 */
134
135 mach_msg_return_t
136 mach_msg_rpc_from_kernel(
137 mach_msg_header_t *msg,
138 mach_msg_size_t send_size,
139 mach_msg_size_t rcv_size)
140 {
141 thread_t self = current_thread();
142 ipc_port_t reply;
143 ipc_kmsg_t kmsg;
144 mach_port_seqno_t seqno;
145 mach_msg_return_t mr;
146
147 assert(MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port));
148 assert(msg->msgh_local_port == MACH_PORT_NULL);
149
150 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
151 if (mr != MACH_MSG_SUCCESS)
152 return mr;
153
154 rpc_lock(self);
155
156 reply = self->ith_rpc_reply;
157 if (reply == IP_NULL) {
158 rpc_unlock(self);
159 reply = ipc_port_alloc_reply();
160 rpc_lock(self);
161 if ((reply == IP_NULL) ||
162 (self->ith_rpc_reply != IP_NULL))
163 panic("mach_msg_rpc_from_kernel");
164 self->ith_rpc_reply = reply;
165 }
166
167 /* insert send-once right for the reply port */
168 kmsg->ikm_header.msgh_local_port = reply;
169 kmsg->ikm_header.msgh_bits |=
170 MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE);
171
172 ipc_port_reference(reply);
173 rpc_unlock(self);
174
175 ipc_kmsg_copyin_from_kernel(kmsg);
176
177 ipc_kmsg_send_always(kmsg);
178
179 for (;;) {
180 ipc_mqueue_t mqueue;
181
182 ip_lock(reply);
183 if ( !ip_active(reply)) {
184 ip_unlock(reply);
185 ipc_port_release(reply);
186 return MACH_RCV_PORT_DIED;
187 }
188 if (!self->top_act || !self->top_act->active) {
189 ip_unlock(reply);
190 ipc_port_release(reply);
191 return MACH_RCV_INTERRUPTED;
192 }
193
194 assert(reply->ip_pset_count == 0);
195 mqueue = &reply->ip_messages;
196 ip_unlock(reply);
197
198 self->ith_continuation = (void (*)(mach_msg_return_t))0;
199
200 ipc_mqueue_receive(mqueue,
201 MACH_MSG_OPTION_NONE,
202 MACH_MSG_SIZE_MAX,
203 MACH_MSG_TIMEOUT_NONE,
204 THREAD_INTERRUPTIBLE);
205
206 mr = self->ith_state;
207 kmsg = self->ith_kmsg;
208 seqno = self->ith_seqno;
209
210 if (mr == MACH_MSG_SUCCESS)
211 {
212 break;
213 }
214
215 assert(mr == MACH_RCV_INTERRUPTED);
216
217 if (self->top_act && self->top_act->handlers) {
218 ipc_port_release(reply);
219 return(mr);
220 }
221 }
222 ipc_port_release(reply);
223
224 /*
225 * XXXXX Set manually for now ...
226 * No, why even bother, since the effort is wasted?
227 *
228 { mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *)
229 ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size);
230 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
231 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
232 }
233 *****/
234
235 if (rcv_size < kmsg->ikm_header.msgh_size) {
236 ipc_kmsg_copyout_dest(kmsg, ipc_space_reply);
237 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
238 return MACH_RCV_TOO_LARGE;
239 }
240
241 /*
242 * We want to preserve rights and memory in reply!
243 * We don't have to put them anywhere; just leave them
244 * as they are.
245 */
246
247 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
248 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
249 return MACH_MSG_SUCCESS;
250 }
251
252
253 /************** These Calls are set up for kernel-loaded tasks **************/
254 /************** Apple does not plan on supporting that. These **************/
255 /************** need to be reworked to deal with the kernel **************/
256 /************** proper to eliminate the kernel specific code MIG **************/
257 /************** must generate. **************/
258
259
260 /*
261 * Routine: mach_msg
262 * Purpose:
263 * Like mach_msg_overwrite_trap except that message buffers
264 * live in kernel space. Doesn't handle any options.
265 *
266 * This is used by in-kernel server threads to make
267 * kernel calls, to receive request messages, and
268 * to send reply messages.
269 * Conditions:
270 * Nothing locked.
271 * Returns:
272 */
273
274 mach_msg_return_t
275 mach_msg_overwrite(
276 mach_msg_header_t *msg,
277 mach_msg_option_t option,
278 mach_msg_size_t send_size,
279 mach_msg_size_t rcv_size,
280 mach_port_name_t rcv_name,
281 mach_msg_timeout_t timeout,
282 mach_port_name_t notify,
283 mach_msg_header_t *rcv_msg,
284 mach_msg_size_t rcv_msg_size)
285 {
286 ipc_space_t space = current_space();
287 vm_map_t map = current_map();
288 ipc_kmsg_t kmsg;
289 mach_port_seqno_t seqno;
290 mach_msg_return_t mr;
291 mach_msg_format_0_trailer_t *trailer;
292
293 if (option & MACH_SEND_MSG) {
294 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
295 if (mr != MACH_MSG_SUCCESS)
296 panic("mach_msg");
297
298 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
299 if (mr != MACH_MSG_SUCCESS) {
300 ipc_kmsg_free(kmsg);
301 return mr;
302 }
303
304 do
305 mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE,
306 MACH_MSG_TIMEOUT_NONE);
307 while (mr == MACH_SEND_INTERRUPTED);
308 assert(mr == MACH_MSG_SUCCESS);
309 }
310
311 if (option & MACH_RCV_MSG) {
312 thread_t self = current_thread();
313
314 do {
315 ipc_object_t object;
316 ipc_mqueue_t mqueue;
317
318 mr = ipc_mqueue_copyin(space, rcv_name,
319 &mqueue, &object);
320 if (mr != MACH_MSG_SUCCESS)
321 return mr;
322 /* hold ref for object */
323
324 self->ith_continuation = (void (*)(mach_msg_return_t))0;
325 ipc_mqueue_receive(mqueue,
326 MACH_MSG_OPTION_NONE,
327 MACH_MSG_SIZE_MAX,
328 MACH_MSG_TIMEOUT_NONE,
329 THREAD_ABORTSAFE);
330 mr = self->ith_state;
331 kmsg = self->ith_kmsg;
332 seqno = self->ith_seqno;
333
334 ipc_object_release(object);
335
336 } while (mr == MACH_RCV_INTERRUPTED);
337 if (mr != MACH_MSG_SUCCESS)
338 return mr;
339
340 trailer = (mach_msg_format_0_trailer_t *)
341 ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size);
342 if (option & MACH_RCV_TRAILER_MASK) {
343 trailer->msgh_seqno = seqno;
344 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
345 }
346
347 if (rcv_size < (kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size)) {
348 ipc_kmsg_copyout_dest(kmsg, space);
349 ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
350 return MACH_RCV_TOO_LARGE;
351 }
352
353 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL,
354 MACH_MSG_BODY_NULL);
355 if (mr != MACH_MSG_SUCCESS) {
356 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
357 ipc_kmsg_put_to_kernel(msg, kmsg,
358 kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size);
359 } else {
360 ipc_kmsg_copyout_dest(kmsg, space);
361 ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
362 }
363
364 return mr;
365 }
366
367 ipc_kmsg_put_to_kernel(msg, kmsg,
368 kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size);
369 }
370
371 return MACH_MSG_SUCCESS;
372 }
373
374 /*
375 * Routine: mig_get_reply_port
376 * Purpose:
377 * Called by client side interfaces living in the kernel
378 * to get a reply port. This port is used for
379 * mach_msg() calls which are kernel calls.
380 */
381 mach_port_t
382 mig_get_reply_port(void)
383 {
384 thread_t self = current_thread();
385
386 assert(self->ith_mig_reply == (mach_port_t)0);
387
388 /*
389 * JMM - for now we have no real clients of this under the kernel
390 * loaded server model because we only have one of those. In order
391 * to avoid MIG changes, we just return null here - and return]
392 * references to ipc_port_t's instead of names.
393 *
394 * if (self->ith_mig_reply == MACH_PORT_NULL)
395 * self->ith_mig_reply = mach_reply_port();
396 */
397 return self->ith_mig_reply;
398 }
399
400 /*
401 * Routine: mig_dealloc_reply_port
402 * Purpose:
403 * Called by client side interfaces to get rid of a reply port.
404 * Shouldn't ever be called inside the kernel, because
405 * kernel calls shouldn't prompt Mig to call it.
406 */
407
408 void
409 mig_dealloc_reply_port(
410 mach_port_t reply_port)
411 {
412 panic("mig_dealloc_reply_port");
413 }
414
415 /*
416 * Routine: mig_put_reply_port
417 * Purpose:
418 * Called by client side interfaces after each RPC to
419 * let the client recycle the reply port if it wishes.
420 */
421 void
422 mig_put_reply_port(
423 mach_port_t reply_port)
424 {
425 }
426
427 /*
428 * mig_strncpy.c - by Joshua Block
429 *
430 * mig_strncp -- Bounded string copy. Does what the library routine strncpy
431 * OUGHT to do: Copies the (null terminated) string in src into dest, a
432 * buffer of length len. Assures that the copy is still null terminated
433 * and doesn't overflow the buffer, truncating the copy if necessary.
434 *
435 * Parameters:
436 *
437 * dest - Pointer to destination buffer.
438 *
439 * src - Pointer to source string.
440 *
441 * len - Length of destination buffer.
442 */
443 int
444 mig_strncpy(
445 char *dest,
446 char *src,
447 int len)
448 {
449 int i = 0;
450
451 if (len > 0)
452 if (dest != NULL) {
453 if (src != NULL)
454 for (i=1; i<len; i++)
455 if (! (*dest++ = *src++))
456 return i;
457 *dest = '\0';
458 }
459 return i;
460 }
461
462 char *
463 mig_user_allocate(
464 vm_size_t size)
465 {
466 return (char *)kalloc(size);
467 }
468
469 void
470 mig_user_deallocate(
471 char *data,
472 vm_size_t size)
473 {
474 kfree((vm_offset_t)data, size);
475 }
476