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