2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
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>
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>
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>
79 /* Default (zeroed) template for qos */
81 static mach_port_qos_t qos_template
;
84 * Routine: mach_msg_send_from_kernel
86 * Send a message from the kernel.
88 * This is used by the client side of KernelUser interfaces
89 * to implement SimpleRoutines. Currently, this includes
90 * memory_object messages.
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.
100 mach_msg_send_from_kernel(
101 mach_msg_header_t
*msg
,
102 mach_msg_size_t send_size
)
105 mach_msg_return_t mr
;
107 if (!MACH_PORT_VALID((mach_port_name_t
)msg
->msgh_remote_port
))
108 return MACH_SEND_INVALID_DEST
;
110 mr
= ipc_kmsg_get_from_kernel(msg
, send_size
, &kmsg
);
111 if (mr
!= MACH_MSG_SUCCESS
)
114 ipc_kmsg_copyin_from_kernel(kmsg
);
115 ipc_kmsg_send_always(kmsg
);
117 return MACH_MSG_SUCCESS
;
121 * Routine: mach_msg_rpc_from_kernel
123 * Send a message from the kernel and receive a reply.
124 * Uses ith_rpc_reply for the reply port.
126 * This is used by the client side of KernelUser interfaces
127 * to implement Routines.
131 * MACH_MSG_SUCCESS Sent the message.
132 * MACH_RCV_PORT_DIED The reply port was deallocated.
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
)
141 thread_t self
= current_thread();
144 mach_port_seqno_t seqno
;
145 mach_msg_return_t mr
;
147 assert(MACH_PORT_VALID((mach_port_name_t
)msg
->msgh_remote_port
));
148 assert(msg
->msgh_local_port
== MACH_PORT_NULL
);
150 mr
= ipc_kmsg_get_from_kernel(msg
, send_size
, &kmsg
);
151 if (mr
!= MACH_MSG_SUCCESS
)
156 reply
= self
->ith_rpc_reply
;
157 if (reply
== IP_NULL
) {
159 reply
= ipc_port_alloc_reply();
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
;
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
);
172 ipc_port_reference(reply
);
175 ipc_kmsg_copyin_from_kernel(kmsg
);
177 ipc_kmsg_send_always(kmsg
);
183 if ( !ip_active(reply
)) {
185 ipc_port_release(reply
);
186 return MACH_RCV_PORT_DIED
;
188 if (!self
->top_act
|| !self
->top_act
->active
) {
190 ipc_port_release(reply
);
191 return MACH_RCV_INTERRUPTED
;
194 assert(reply
->ip_pset_count
== 0);
195 mqueue
= &reply
->ip_messages
;
198 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
200 ipc_mqueue_receive(mqueue
,
201 MACH_MSG_OPTION_NONE
,
203 MACH_MSG_TIMEOUT_NONE
,
204 THREAD_INTERRUPTIBLE
);
206 mr
= self
->ith_state
;
207 kmsg
= self
->ith_kmsg
;
208 seqno
= self
->ith_seqno
;
210 if (mr
== MACH_MSG_SUCCESS
)
215 assert(mr
== MACH_RCV_INTERRUPTED
);
217 if (self
->top_act
&& self
->top_act
->handlers
) {
218 ipc_port_release(reply
);
222 ipc_port_release(reply
);
225 * XXXXX Set manually for now ...
226 * No, why even bother, since the effort is wasted?
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;
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
;
242 * We want to preserve rights and memory in reply!
243 * We don't have to put them anywhere; just leave them
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
;
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. **************/
263 * Like mach_msg_overwrite_trap except that message buffers
264 * live in kernel space. Doesn't handle any options.
266 * This is used by in-kernel server threads to make
267 * kernel calls, to receive request messages, and
268 * to send reply messages.
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
)
286 ipc_space_t space
= current_space();
287 vm_map_t map
= current_map();
289 mach_port_seqno_t seqno
;
290 mach_msg_return_t mr
;
291 mach_msg_format_0_trailer_t
*trailer
;
293 if (option
& MACH_SEND_MSG
) {
294 mr
= ipc_kmsg_get_from_kernel(msg
, send_size
, &kmsg
);
295 if (mr
!= MACH_MSG_SUCCESS
)
298 mr
= ipc_kmsg_copyin(kmsg
, space
, map
, MACH_PORT_NULL
);
299 if (mr
!= MACH_MSG_SUCCESS
) {
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
);
311 if (option
& MACH_RCV_MSG
) {
312 thread_t self
= current_thread();
318 mr
= ipc_mqueue_copyin(space
, rcv_name
,
320 if (mr
!= MACH_MSG_SUCCESS
)
322 /* hold ref for object */
324 self
->ith_continuation
= (void (*)(mach_msg_return_t
))0;
325 ipc_mqueue_receive(mqueue
,
326 MACH_MSG_OPTION_NONE
,
328 MACH_MSG_TIMEOUT_NONE
,
330 mr
= self
->ith_state
;
331 kmsg
= self
->ith_kmsg
;
332 seqno
= self
->ith_seqno
;
334 ipc_object_release(object
);
336 } while (mr
== MACH_RCV_INTERRUPTED
);
337 if (mr
!= MACH_MSG_SUCCESS
)
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
);
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
;
353 mr
= ipc_kmsg_copyout(kmsg
, space
, map
, MACH_PORT_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
);
360 ipc_kmsg_copyout_dest(kmsg
, space
);
361 ipc_kmsg_put_to_kernel(msg
, kmsg
, sizeof *msg
);
367 ipc_kmsg_put_to_kernel(msg
, kmsg
,
368 kmsg
->ikm_header
.msgh_size
+ trailer
->msgh_trailer_size
);
371 return MACH_MSG_SUCCESS
;
375 * Routine: mig_get_reply_port
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.
382 mig_get_reply_port(void)
384 thread_t self
= current_thread();
386 assert(self
->ith_mig_reply
== (mach_port_t
)0);
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.
394 * if (self->ith_mig_reply == MACH_PORT_NULL)
395 * self->ith_mig_reply = mach_reply_port();
397 return self
->ith_mig_reply
;
401 * Routine: mig_dealloc_reply_port
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.
409 mig_dealloc_reply_port(
410 mach_port_t reply_port
)
412 panic("mig_dealloc_reply_port");
416 * Routine: mig_put_reply_port
418 * Called by client side interfaces after each RPC to
419 * let the client recycle the reply port if it wishes.
423 mach_port_t reply_port
)
428 * mig_strncpy.c - by Joshua Block
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.
437 * dest - Pointer to destination buffer.
439 * src - Pointer to source string.
441 * len - Length of destination buffer.
454 for (i
=1; i
<len
; i
++)
455 if (! (*dest
++ = *src
++))
466 return (char *)kalloc(size
);
474 kfree((vm_offset_t
)data
, size
);