1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_kobject.c,v $
29 * Revision 2.16 93/11/17 17:10:30 dbg
30 * Added kern_reply_kmsg_zone, for quick allocation of kernel reply
31 * messages.
32 * [93/03/30 dbg]
33 *
34 * Added ANSI function prototypes.
35 * [93/02/04 dbg]
36 *
37 * Revision 2.15 93/01/24 13:19:00 danner
38 * Introduce Mach4 interface. Initially for pc sampling.
39 * [93/01/11 rvb]
40 *
41 * Revision 2.14 92/08/03 17:37:23 jfriedl
42 * removed silly prototypes
43 * [92/08/02 jfriedl]
44 *
45 * Revision 2.13 92/05/21 17:13:47 jfriedl
46 * Made correct for when assert is off.
47 * [92/05/16 jfriedl]
48 *
49 * Revision 2.12 92/03/10 16:26:28 jsb
50 * Add IKOT_PAGER_TERMINATING case to ipc_kobject_destroy.
51 * [92/02/25 dlb]
52 * Added ipc_kobject_notify for kernel-requested notifications.
53 * Added code to correctly release send-once kobject destinations.
54 * [92/01/21 18:20:19 jsb]
55 *
56 * Revision 2.11 92/01/03 20:14:32 dbg
57 * Call <subsystem>_routine_name to find IPC stub to execute.
58 * Build reply message header by hand. (XXX)
59 * Simplify cleanup of request message when reply is success.
60 * [91/12/18 dbg]
61 *
62 * Revision 2.10 91/12/13 13:42:24 jsb
63 * Added support for norma/norma_internal.defs.
64 *
65 * Revision 2.9 91/08/01 14:36:18 dbg
66 * Call machine-dependent interface routine, under
67 * MACH_MACHINE_ROUTINES.
68 * [91/08/01 dbg]
69 *
70 * Revision 2.8 91/06/17 15:47:02 jsb
71 * Renamed NORMA conditionals. Added NORMA_VM support.
72 * [91/06/17 13:46:55 jsb]
73 *
74 * Revision 2.7 91/06/06 17:07:05 jsb
75 * Added NORMA_TASK support.
76 * [91/05/14 09:05:48 jsb]
77 *
78 * Revision 2.6 91/05/18 14:31:42 rpd
79 * Added check_simple_locks.
80 * [91/04/01 rpd]
81 *
82 * Revision 2.5 91/05/14 16:42:00 mrt
83 * Correcting copyright
84 *
85 * Revision 2.4 91/03/16 14:50:02 rpd
86 * Replaced ith_saved with ikm_cache.
87 * [91/02/16 rpd]
88 *
89 * Revision 2.3 91/02/05 17:26:37 mrt
90 * Changed to new Mach copyright
91 * [91/02/01 16:12:51 mrt]
92 *
93 * Revision 2.2 90/06/02 14:54:08 rpd
94 * Created for new IPC.
95 * [90/03/26 23:46:53 rpd]
96 *
97 */
98 /*
99 * File: kern/ipc_kobject.c
100 * Author: Rich Draves
101 * Date: 1989
102 *
103 * Functions for letting a port represent a kernel object.
104 */
105
106 #include <mach_debug.h>
107 #include <mach_ipc_test.h>
108 #include <mach_machine_routines.h>
109 #include <mach_rt.h>
110 #include <norma_task.h>
111 #include <norma_vm.h>
112
113 #include <mach/port.h>
114 #include <mach/kern_return.h>
115 #include <mach/message.h>
116 #include <mach/mig_errors.h>
117 #include <mach/notify.h>
118 #include <kern/ipc_kobject.h>
119 #include <ipc/ipc_object.h>
120 #include <ipc/ipc_kmsg.h>
121 #include <ipc/ipc_port.h>
122 #include <ipc/ipc_thread.h>
123 #include <kern/kern_kmsg.h>
124 #include <kern/kern_io.h>
125 #include <kern/mach_timer.h>
126 #include <device/ds_routines.h>
127
128 #if MACH_MACHINE_ROUTINES
129 #include <machine/machine_routines.h>
130 #endif
131
132 /*
133 * Size of kernel reply messages.
134 * Value is historical.
135 */
136 #define KERNEL_REPLY_KMSG_SIZE (8192)
137
138 int kern_reply_kmsg_size = KERNEL_REPLY_KMSG_SIZE;
139 int kern_reply_kmsg_max = 4096;
140 /*
141 * Zone for kernel reply messages.
142 */
143 zone_t kernel_reply_kmsg_zone;
144
145 boolean_t
146 ipc_kobject_notify(
147 mach_msg_header_t *request_header,
148 mach_msg_header_t *reply_header); /* forward */
149
150 /*
151 * Initialize zone.
152 */
153 void kernel_reply_kmsg_init(void)
154 {
155 kernel_reply_kmsg_zone = zinit(
156 kern_reply_kmsg_size,
157 kern_reply_kmsg_size * kern_reply_kmsg_max,
158 kern_reply_kmsg_size,
159 FALSE,
160 "kernel reply messages");
161 }
162
163 /*
164 * Routine: ipc_kobject_server
165 * Purpose:
166 * Handle a message sent to the kernel.
167 * Generates a reply message.
168 * Conditions:
169 * Nothing locked.
170 */
171
172 ipc_kmsg_t
173 ipc_kobject_server(
174 ipc_kmsg_t request)
175 {
176 ipc_kmsg_t reply;
177 kern_return_t kr;
178 mig_routine_t routine;
179 ipc_port_t dest;
180
181 kernel_reply_kmsg_get(reply);
182 if (reply == IKM_NULL) {
183 printf("ipc_kobject_server: dropping request\n");
184 ipc_kmsg_destroy(request);
185 return IKM_NULL;
186 }
187
188 /*
189 * Initialize reply message.
190 */
191 {
192 #define InP ((mach_msg_header_t *) &request->ikm_header)
193 #define OutP ((mig_reply_header_t *) &reply->ikm_header)
194
195 static mach_msg_type_t RetCodeType = {
196 /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32,
197 /* msgt_size = */ 32,
198 /* msgt_number = */ 1,
199 /* msgt_inline = */ TRUE,
200 /* msgt_longform = */ FALSE,
201 /* msgt_unused = */ 0
202 };
203 OutP->Head.msgh_bits =
204 MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0);
205 OutP->Head.msgh_size = sizeof(mig_reply_header_t);
206 OutP->Head.msgh_remote_port = InP->msgh_local_port;
207 OutP->Head.msgh_local_port = MACH_PORT_NULL;
208 OutP->Head.msgh_seqno = 0;
209 OutP->Head.msgh_id = InP->msgh_id + 100;
210
211 OutP->RetCodeType = RetCodeType;
212
213 #undef InP
214 #undef OutP
215 }
216
217 /*
218 * Find the server routine to call, and call it
219 * to perform the kernel function
220 */
221 {
222 extern mig_routine_t
223 mach_server_routine(mach_msg_header_t *),
224 mach_port_server_routine(mach_msg_header_t *),
225 mach_host_server_routine(mach_msg_header_t *),
226 device_server_routine(mach_msg_header_t *),
227 device_pager_server_routine(mach_msg_header_t *),
228 mach4_server_routine(mach_msg_header_t *);
229 #if MACH_DEBUG
230 extern mig_routine_t
231 mach_debug_server_routine(mach_msg_header_t *);
232 #endif
233 #if NORMA_TASK
234 extern mig_routine_t
235 mach_norma_server_routine(mach_msg_header_t *),
236 norma_internal_server_routine(mach_msg_header_t *);
237 #endif
238 #if NORMA_VM
239 extern mig_routine_t
240 proxy_server_routine(mach_msg_header_t *);
241 #endif
242
243 #if MACH_MACHINE_ROUTINES
244 extern mig_routine_t
245 MACHINE_SERVER_ROUTINE(mach_msg_header_t *);
246 #endif
247
248 check_simple_locks();
249 if ((routine = mach_server_routine(&request->ikm_header)) != 0
250 || (routine = mach_port_server_routine(&request->ikm_header)) != 0
251 || (routine = mach_host_server_routine(&request->ikm_header)) != 0
252 || (routine = device_server_routine(&request->ikm_header)) != 0
253 || (routine = device_pager_server_routine(&request->ikm_header)) != 0
254 #if MACH_DEBUG
255 || (routine = mach_debug_server_routine(&request->ikm_header)) != 0
256 #endif
257 #if NORMA_TASK
258 || (routine = mach_norma_server_routine(&request->ikm_header)) != 0
259 || (routine = norma_internal_server_routine(&request->ikm_header)) != 0
260 #endif
261 #if NORMA_VM
262 || (routine = proxy_server_routine(&request->ikm_header)) != 0
263 #endif
264 || (routine = mach4_server_routine(&request->ikm_header)) != 0
265 #if MACH_MACHINE_ROUTINES
266 || (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
267 #endif
268 ) {
269 (*routine)(&request->ikm_header, &reply->ikm_header);
270 }
271 else if (!ipc_kobject_notify(&request->ikm_header,&reply->ikm_header)){
272 ((mig_reply_header_t *) &reply->ikm_header)->RetCode
273 = MIG_BAD_ID;
274 #if MACH_IPC_TEST
275 printf("ipc_kobject_server: bogus kernel message, id=%d\n",
276 request->ikm_header.msgh_id);
277 #endif /* MACH_IPC_TEST */
278 }
279 }
280 check_simple_locks();
281
282 /*
283 * Destroy destination. The following code differs from
284 * ipc_object_destroy in that we release the send-once
285 * right instead of generating a send-once notification
286 * (which would bring us here again, creating a loop).
287 * It also differs in that we only expect send or
288 * send-once rights, never receive rights.
289 *
290 * We set msgh_remote_port to IP_NULL so that the kmsg
291 * destroy routines don't try to destroy the port twice.
292 */
293 dest = (ipc_port_t) request->ikm_header.msgh_remote_port;
294 switch (MACH_MSGH_BITS_REMOTE(request->ikm_header.msgh_bits)) {
295 case MACH_MSG_TYPE_PORT_SEND:
296 ipc_port_release_send(dest);
297 break;
298
299 case MACH_MSG_TYPE_PORT_SEND_ONCE:
300 ipc_port_release_sonce(dest);
301 break;
302
303 default:
304 #if MACH_ASSERT
305 assert(!"ipc_object_destroy: strange destination rights");
306 #else
307 panic("ipc_object_destroy: strange destination rights");
308 #endif
309 }
310
311 kr = ((mig_reply_header_t *) &reply->ikm_header)->RetCode;
312 if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
313 /*
314 * The server function is responsible for the contents
315 * of the message. The reply port right is moved
316 * to the reply message, and we have deallocated
317 * the destination port right, so we just need
318 * to free the kmsg.
319 */
320
321 /* like ipc_kmsg_put, but without the copyout */
322
323 ikm_check_initialized(request, request->ikm_size);
324 if ((request->ikm_size == IKM_SAVED_KMSG_SIZE) &&
325 (ikm_cache() == IKM_NULL))
326 ikm_cache() = request;
327 else
328 ikm_free(request);
329 } else {
330 /*
331 * The message contents of the request are intact.
332 * Destroy everything except the reply port right,
333 * which is needed in the reply message. The
334 * destination port right has already been destroyed.
335 */
336
337 request->ikm_header.msgh_remote_port = MACH_PORT_NULL;
338 request->ikm_header.msgh_local_port = MACH_PORT_NULL;
339 ipc_kmsg_destroy(request);
340 }
341
342 if (kr == MIG_NO_REPLY) {
343 /*
344 * The server function will send a reply message
345 * using the reply port right, which it has saved.
346 */
347
348 ikm_free(reply);
349 return IKM_NULL;
350 } else if (!IP_VALID((ipc_port_t)reply->ikm_header.msgh_remote_port)) {
351 /*
352 * Can't queue the reply message if the destination
353 * (the reply port) isn't valid.
354 */
355
356 ipc_kmsg_destroy(reply);
357 return IKM_NULL;
358 }
359
360 return reply;
361 }
362
363 /*
364 * Routine: ipc_kobject_set
365 * Purpose:
366 * Make a port represent a kernel object of the given type.
367 * The caller is responsible for handling refs for the
368 * kernel object, if necessary.
369 * Conditions:
370 * Nothing locked. The port must be active.
371 */
372
373 void
374 ipc_kobject_set(
375 ipc_port_t port,
376 ipc_kobject_t kobject,
377 ipc_kobject_type_t type)
378 {
379 ip_lock(port);
380 assert(ip_active(port));
381 port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
382 port->ip_kobject = kobject;
383 ip_unlock(port);
384 }
385
386 /*
387 * Routine: ipc_kobject_destroy
388 * Purpose:
389 * Release any kernel object resources associated
390 * with the port, which is being destroyed.
391 *
392 * This should only be needed when resources are
393 * associated with a user's port. In the normal case,
394 * when the kernel is the receiver, the code calling
395 * ipc_port_dealloc_kernel should clean up the resources.
396 * Conditions:
397 * The port is not locked, but it is dead.
398 */
399
400 void
401 ipc_kobject_destroy(
402 ipc_port_t port)
403 {
404 switch (ip_kotype(port)) {
405 case IKOT_PAGER:
406 vm_object_destroy(port);
407 break;
408
409 case IKOT_PAGER_TERMINATING:
410 vm_object_pager_wakeup(port);
411 break;
412
413 default:
414 #if MACH_ASSERT
415 printf("ipc_kobject_destroy: port 0x%x, kobj 0x%x, type %d\n",
416 port, port->ip_kobject, ip_kotype(port));
417 #endif /* MACH_ASSERT */
418 break;
419 }
420 }
421
422 /*
423 * Routine: ipc_kobject_notify
424 * Purpose:
425 * Deliver notifications to kobjects that care about them.
426 */
427
428 boolean_t
429 ipc_kobject_notify(
430 mach_msg_header_t *request_header,
431 mach_msg_header_t *reply_header)
432 {
433 ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
434
435 ((mig_reply_header_t *) reply_header)->RetCode = MIG_NO_REPLY;
436 switch (request_header->msgh_id) {
437 case MACH_NOTIFY_PORT_DELETED:
438 case MACH_NOTIFY_MSG_ACCEPTED:
439 case MACH_NOTIFY_PORT_DESTROYED:
440 case MACH_NOTIFY_NO_SENDERS:
441 case MACH_NOTIFY_SEND_ONCE:
442 case MACH_NOTIFY_DEAD_NAME:
443 break;
444
445 default:
446 return FALSE;
447 }
448 switch (ip_kotype(port)) {
449 #if NORMA_VM
450 case IKOT_XMM_OBJECT:
451 return xmm_object_notify(request_header);
452
453 case IKOT_XMM_PAGER:
454 return xmm_pager_notify(request_header);
455
456 case IKOT_XMM_KERNEL:
457 return xmm_kernel_notify(request_header);
458
459 case IKOT_XMM_REPLY:
460 return xmm_reply_notify(request_header);
461 #endif /* NORMA_VM */
462
463 case IKOT_DEVICE:
464 return ds_notify(request_header);
465
466 case IKOT_TIMER:
467 return timer_notify(request_header);
468
469 default:
470 return FALSE;
471 }
472 }
Cache object: d308f98e135a7af963e83832f6b0a615
|