|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 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.
1.1.1.2 root 11: *
1.1 root 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.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: */
28: /*
29: * File: kern/ipc_kobject.c
30: * Author: Rich Draves
31: * Date: 1989
32: *
33: * Functions for letting a port represent a kernel object.
34: */
35:
1.1.1.3 ! root 36: #include <kern/debug.h>
! 37: #include <kern/printf.h>
1.1 root 38: #include <mach/port.h>
39: #include <mach/kern_return.h>
40: #include <mach/message.h>
41: #include <mach/mig_errors.h>
42: #include <mach/notify.h>
43: #include <kern/ipc_kobject.h>
44: #include <ipc/ipc_object.h>
45: #include <ipc/ipc_kmsg.h>
46: #include <ipc/ipc_port.h>
47: #include <ipc/ipc_thread.h>
1.1.1.3 ! root 48: #include <vm/vm_object.h>
! 49: #include <vm/memory_object_proxy.h>
! 50: #include <device/ds_routines.h>
1.1 root 51:
52: #if MACH_MACHINE_ROUTINES
53: #include <machine/machine_routines.h>
54: #endif
55:
56:
57: /*
58: * Routine: ipc_kobject_server
59: * Purpose:
60: * Handle a message sent to the kernel.
61: * Generates a reply message.
62: * Conditions:
63: * Nothing locked.
64: */
65:
66: ipc_kmsg_t
67: ipc_kobject_server(request)
68: ipc_kmsg_t request;
69: {
70: mach_msg_size_t reply_size = ikm_less_overhead(8192);
71: ipc_kmsg_t reply;
72: kern_return_t kr;
73: mig_routine_t routine;
74: ipc_port_t *destp;
75:
76: reply = ikm_alloc(reply_size);
77: if (reply == IKM_NULL) {
78: printf("ipc_kobject_server: dropping request\n");
79: ipc_kmsg_destroy(request);
80: return IKM_NULL;
81: }
82: ikm_init(reply, reply_size);
83:
84: /*
85: * Initialize reply message.
86: */
87: {
88: #define InP ((mach_msg_header_t *) &request->ikm_header)
89: #define OutP ((mig_reply_header_t *) &reply->ikm_header)
90:
91: static mach_msg_type_t RetCodeType = {
92: /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32,
93: /* msgt_size = */ 32,
94: /* msgt_number = */ 1,
95: /* msgt_inline = */ TRUE,
96: /* msgt_longform = */ FALSE,
97: /* msgt_unused = */ 0
98: };
99: OutP->Head.msgh_bits =
100: MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0);
101: OutP->Head.msgh_size = sizeof(mig_reply_header_t);
102: OutP->Head.msgh_remote_port = InP->msgh_local_port;
103: OutP->Head.msgh_local_port = MACH_PORT_NULL;
104: OutP->Head.msgh_seqno = 0;
105: OutP->Head.msgh_id = InP->msgh_id + 100;
106: #if 0
107: if (InP->msgh_id) {
108: static long _calls;
109: static struct { long id, count; } _counts[512];
110: int i, id;
111:
112: id = InP->msgh_id;
113: for (i = 0; i < 511; i++) {
114: if (_counts[i].id == 0) {
115: _counts[i].id = id;
116: _counts[i].count++;
117: break;
118: }
119: if (_counts[i].id == id) {
120: _counts[i].count++;
121: break;
122: }
123: }
124: if (i == 511) {
125: _counts[i].id = id;
126: _counts[i].count++;
127: }
128: if ((++_calls & 0x7fff) == 0)
129: for (i = 0; i < 512; i++) {
130: if (_counts[i].id == 0)
131: break;
132: printf("%d: %d\n",
133: _counts[i].id, _counts[i].count);
134: }
135: }
136: #endif
137:
138: OutP->RetCodeType = RetCodeType;
139:
140: #undef InP
141: #undef OutP
142: }
143:
144: /*
145: * Find the server routine to call, and call it
146: * to perform the kernel function
147: */
148: {
149: extern mig_routine_t mach_server_routine(),
150: mach_port_server_routine(),
151: mach_host_server_routine(),
152: device_server_routine(),
153: device_pager_server_routine(),
1.1.1.3 ! root 154: mach4_server_routine(),
! 155: gnumach_server_routine();
1.1 root 156: #if MACH_DEBUG
157: extern mig_routine_t mach_debug_server_routine();
158: #endif
159:
160: #if MACH_MACHINE_ROUTINES
161: extern mig_routine_t MACHINE_SERVER_ROUTINE();
162: #endif
163:
164: check_simple_locks();
165: if ((routine = mach_server_routine(&request->ikm_header)) != 0
166: || (routine = mach_port_server_routine(&request->ikm_header)) != 0
167: || (routine = mach_host_server_routine(&request->ikm_header)) != 0
168: || (routine = device_server_routine(&request->ikm_header)) != 0
169: || (routine = device_pager_server_routine(&request->ikm_header)) != 0
170: #if MACH_DEBUG
171: || (routine = mach_debug_server_routine(&request->ikm_header)) != 0
1.1.1.2 root 172: #endif /* MACH_DEBUG */
1.1 root 173: || (routine = mach4_server_routine(&request->ikm_header)) != 0
1.1.1.3 ! root 174: || (routine = gnumach_server_routine(&request->ikm_header)) != 0
1.1 root 175: #if MACH_MACHINE_ROUTINES
176: || (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
1.1.1.2 root 177: #endif /* MACH_MACHINE_ROUTINES */
1.1 root 178: ) {
179: (*routine)(&request->ikm_header, &reply->ikm_header);
1.1.1.3 ! root 180: kernel_task->messages_received++;
! 181: } else {
! 182: if (!ipc_kobject_notify(&request->ikm_header,
! 183: &reply->ikm_header)) {
1.1 root 184: ((mig_reply_header_t *) &reply->ikm_header)->RetCode
185: = MIG_BAD_ID;
186: #if MACH_IPC_TEST
187: printf("ipc_kobject_server: bogus kernel message, id=%d\n",
188: request->ikm_header.msgh_id);
1.1.1.2 root 189: #endif /* MACH_IPC_TEST */
1.1.1.3 ! root 190: } else {
! 191: kernel_task->messages_received++;
! 192: }
1.1 root 193: }
1.1.1.3 ! root 194: kernel_task->messages_sent++;
1.1 root 195: }
196: check_simple_locks();
197:
198: /*
199: * Destroy destination. The following code differs from
200: * ipc_object_destroy in that we release the send-once
201: * right instead of generating a send-once notification
202: * (which would bring us here again, creating a loop).
203: * It also differs in that we only expect send or
204: * send-once rights, never receive rights.
205: *
206: * We set msgh_remote_port to IP_NULL so that the kmsg
207: * destroy routines don't try to destroy the port twice.
208: */
209: destp = (ipc_port_t *) &request->ikm_header.msgh_remote_port;
210: switch (MACH_MSGH_BITS_REMOTE(request->ikm_header.msgh_bits)) {
211: case MACH_MSG_TYPE_PORT_SEND:
212: ipc_port_release_send(*destp);
213: break;
1.1.1.2 root 214:
1.1 root 215: case MACH_MSG_TYPE_PORT_SEND_ONCE:
216: ipc_port_release_sonce(*destp);
217: break;
1.1.1.2 root 218:
1.1 root 219: default:
220: #if MACH_ASSERT
221: assert(!"ipc_object_destroy: strange destination rights");
222: #else
223: panic("ipc_object_destroy: strange destination rights");
224: #endif
225: }
226: *destp = IP_NULL;
227:
228: kr = ((mig_reply_header_t *) &reply->ikm_header)->RetCode;
229: if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
230: /*
231: * The server function is responsible for the contents
232: * of the message. The reply port right is moved
233: * to the reply message, and we have deallocated
234: * the destination port right, so we just need
235: * to free the kmsg.
236: */
237:
238: /* like ipc_kmsg_put, but without the copyout */
239:
240: ikm_check_initialized(request, request->ikm_size);
241: if ((request->ikm_size == IKM_SAVED_KMSG_SIZE) &&
242: (ikm_cache() == IKM_NULL))
243: ikm_cache() = request;
244: else
245: ikm_free(request);
246: } else {
247: /*
248: * The message contents of the request are intact.
249: * Destroy everthing except the reply port right,
250: * which is needed in the reply message.
251: */
252:
253: request->ikm_header.msgh_local_port = MACH_PORT_NULL;
254: ipc_kmsg_destroy(request);
255: }
256:
257: if (kr == MIG_NO_REPLY) {
258: /*
259: * The server function will send a reply message
260: * using the reply port right, which it has saved.
261: */
262:
263: ikm_free(reply);
264: return IKM_NULL;
265: } else if (!IP_VALID((ipc_port_t)reply->ikm_header.msgh_remote_port)) {
266: /*
267: * Can't queue the reply message if the destination
268: * (the reply port) isn't valid.
269: */
270:
271: ipc_kmsg_destroy(reply);
272: return IKM_NULL;
273: }
274:
275: return reply;
276: }
277:
278: /*
279: * Routine: ipc_kobject_set
280: * Purpose:
281: * Make a port represent a kernel object of the given type.
282: * The caller is responsible for handling refs for the
283: * kernel object, if necessary.
284: * Conditions:
285: * Nothing locked. The port must be active.
286: */
287:
288: void
289: ipc_kobject_set(port, kobject, type)
290: ipc_port_t port;
291: ipc_kobject_t kobject;
292: ipc_kobject_type_t type;
293: {
294: ip_lock(port);
295: assert(ip_active(port));
296: port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
297: port->ip_kobject = kobject;
298: ip_unlock(port);
299: }
300:
301: /*
302: * Routine: ipc_kobject_destroy
303: * Purpose:
304: * Release any kernel object resources associated
305: * with the port, which is being destroyed.
306: *
307: * This should only be needed when resources are
308: * associated with a user's port. In the normal case,
309: * when the kernel is the receiver, the code calling
310: * ipc_port_dealloc_kernel should clean up the resources.
311: * Conditions:
312: * The port is not locked, but it is dead.
313: */
314:
315: void
316: ipc_kobject_destroy(
317: ipc_port_t port)
318: {
319: switch (ip_kotype(port)) {
320: case IKOT_PAGER:
321: vm_object_destroy(port);
322: break;
323:
324: case IKOT_PAGER_TERMINATING:
325: vm_object_pager_wakeup(port);
326: break;
327:
328: default:
329: #if MACH_ASSERT
1.1.1.3 ! root 330: printf("ipc_kobject_destroy: port 0x%p, kobj 0x%lx, type %d\n",
1.1 root 331: port, port->ip_kobject, ip_kotype(port));
1.1.1.2 root 332: #endif /* MACH_ASSERT */
1.1 root 333: break;
334: }
335: }
336:
337: /*
338: * Routine: ipc_kobject_notify
339: * Purpose:
340: * Deliver notifications to kobjects that care about them.
341: */
342:
343: boolean_t
344: ipc_kobject_notify(request_header, reply_header)
345: mach_msg_header_t *request_header;
346: mach_msg_header_t *reply_header;
347: {
348: ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
349:
350: ((mig_reply_header_t *) reply_header)->RetCode = MIG_NO_REPLY;
351: switch (request_header->msgh_id) {
352: case MACH_NOTIFY_PORT_DELETED:
353: case MACH_NOTIFY_MSG_ACCEPTED:
354: case MACH_NOTIFY_PORT_DESTROYED:
355: case MACH_NOTIFY_NO_SENDERS:
356: case MACH_NOTIFY_SEND_ONCE:
357: case MACH_NOTIFY_DEAD_NAME:
358: break;
359:
360: default:
361: return FALSE;
362: }
363: switch (ip_kotype(port)) {
364: case IKOT_DEVICE:
365: return ds_notify(request_header);
366:
1.1.1.3 ! root 367: case IKOT_PAGER_PROXY:
! 368: return memory_object_proxy_notify(request_header);
! 369:
1.1 root 370: default:
371: return FALSE;
372: }
373: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.