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