|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * HISTORY
27: *
28: * Revision 1.1.1.1 1998/09/22 21:05:32 wsanchez
29: * Import of Mac OS X kernel (~semeria)
30: *
31: * Revision 1.2 1998/04/29 17:36:19 mburg
32: * MK7.3 merger
33: *
34: * Revision 1.1.18.1 1998/02/03 09:30:24 gdt
35: * Merge up to MK7.3
36: * [1998/02/03 09:15:10 gdt]
37: *
38: * Revision 1.1.16.1 1997/06/17 02:59:23 devrcs
39: * Added call to `ipc_subsystem_terminate()' to `subsystem_deallocate()'
40: * to close port leak.
41: * [1997/03/18 18:25:55 rkc]
42: *
43: * Revision 1.1.7.4 1995/01/10 05:14:19 devrcs
44: * mk6 CR801 - merge up from nmk18b4 to nmk18b7
45: * * Rev 1.1.7.3 1994/10/19 16:24:57 watkins
46: * Define subsystem_print if mach_debug.
47: * [1994/12/09 21:01:02 dwm]
48: *
49: * mk6 CR668 - 1.3b26 merge
50: * splx is void.
51: * [1994/11/04 09:32:40 dwm]
52: *
53: * Revision 1.1.7.2 1994/09/23 02:27:05 ezf
54: * change marker to not FREE
55: * [1994/09/22 21:36:22 ezf]
56: *
57: * Revision 1.1.7.1 1994/09/16 15:30:10 emcmanus
58: * Implement "show subsystem" command.
59: * [1994/09/16 15:29:11 emcmanus]
60: *
61: * Revision 1.1.3.4 1994/06/02 01:53:14 bolinger
62: * mk6 CR125: Initialize subsystem_lock().
63: * [1994/06/01 22:30:18 bolinger]
64: *
65: * Revision 1.1.3.3 1994/01/21 01:22:58 condict
66: * Fix too stringent error checking. Change subsys from ool to in-line.
67: * [1994/01/21 01:19:32 condict]
68: *
69: * Revision 1.1.3.2 1994/01/20 16:25:29 condict
70: * Testing bsubmit.
71: * [1994/01/20 16:24:32 condict]
72: *
73: * Revision 1.1.3.1 1994/01/20 11:09:26 emcmanus
74: * Copied for submission.
75: * [1994/01/20 11:08:20 emcmanus]
76: *
77: * Revision 1.1.1.4 1994/01/20 02:45:10 condict
78: * Make user subsystem point at containing system subsytem struct.
79: *
80: * Revision 1.1.1.3 1994/01/15 22:01:19 condict
81: * Validate user subsystem data, convert user ptrs to kernel ptrs.
82: *
83: * Revision 1.1.1.2 1994/01/13 02:39:58 condict
84: * Implementation of RPC subsystem object, for server co-location.
85: *
86: * $EndLog$
87: */
88: /*
89: * Functions to manipulate RPC subsystem descriptions.
90: */
91:
92: #include <mach/port.h>
93: #include <mach/kern_return.h>
94: #include <kern/task.h>
95: #include <kern/lock.h>
96: #include <kern/spl.h>
97: #include <kern/zalloc.h>
98: #include <kern/ipc_subsystem.h>
99: #include <kern/subsystem.h>
100: #include <kern/misc_protos.h>
101:
102: #define SUBSYSTEM_MIN_SIZE 12
103: #define SUBSYSTEM_MAX_SIZE (2*1024*1024) /* What value is correct? */
104:
105: void
106: subsystem_init(
107: void)
108: {
109: /* Nothing to do on bootstrap, at the moment. */
110: }
111:
112: /*
113: * Routine: mach_subsystem_create
114: * Purpose:
115: * Create a new RPC subsystem.
116: * Conditions:
117: * Nothing locked. If successful, the subsystem is returned
118: * unlocked. (The caller has a reference.)
119: * Returns:
120: * KERN_SUCCESS The subsystem is allocated.
121: * KERN_INVALID_TASK The task is dead.
122: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
123: */
124:
125: kern_return_t
126: mach_subsystem_create(
127: register task_t parent_task,
128: user_subsystem_t user_subsys,
129: mach_msg_type_number_t user_subsysCount,
130: subsystem_t *subsystem_p)
131: {
132: int i;
133: subsystem_t new_subsystem;
134: kern_return_t kr;
135: boolean_t deallocate = FALSE;
136: vm_size_t size;
137: vm_offset_t offset;
138: int num_routines;
139: boolean_t bad_arg = FALSE;
140:
141: if (parent_task == TASK_NULL)
142: return(KERN_INVALID_ARGUMENT);
143:
144: if (user_subsysCount < SUBSYSTEM_MIN_SIZE ||
145: user_subsysCount > SUBSYSTEM_MAX_SIZE)
146: return(KERN_INVALID_ARGUMENT);
147:
148: /*
149: * Allocate a subsystem and initialize:
150: */
151:
152: size = (vm_size_t)user_subsysCount + sizeof(struct subsystem) -
153: sizeof(struct rpc_subsystem);
154: new_subsystem = (subsystem_t) kalloc(size);
155:
156: if (new_subsystem == 0)
157: return(KERN_RESOURCE_SHORTAGE);
158:
159: new_subsystem->task = parent_task;
160: new_subsystem->ref_count = 1; /* A reference for our caller */
161: new_subsystem->size = size;
162: subsystem_lock_init(new_subsystem);
163:
164: /* Copy the user subsystem data to a permanent place: */
165: bcopy((char *)user_subsys, (char *)&(new_subsystem->user),
166: (int)user_subsysCount);
167:
168: /* Validate the user-specified fields of the subsystem: */
169:
170: num_routines = new_subsystem->user.end - new_subsystem->user.start;
171: if (num_routines < 0 ||
172: (char *)&new_subsystem->user.routine[num_routines] >
173: (char *)&new_subsystem->user + (int)user_subsysCount
174: ) {
175: kfree((vm_offset_t)new_subsystem, size);
176: return(KERN_INVALID_ADDRESS);
177: }
178:
179: /* The following is for converting the user pointers in the
180: * subsystem struct to kernel pointers:
181: */
182: offset = (char *)&new_subsystem->user -
183: (char *)new_subsystem->user.base_addr; /* The user addr */
184:
185: for (i = 0; i < num_routines; i++) {
186: routine_descriptor_t routine = &new_subsystem->user.routine[i];
187:
188: /* If this is a "skip" routine, ignore it: */
189: if (!routine->impl_routine)
190: continue;
191:
192: /* Convert the user arg_descr pointer to a kernel pointer: */
193: routine->arg_descr = (routine_arg_descriptor_t)
194: ((char *)routine->arg_descr + offset);
195:
196: if (routine->argc > 1000000 ||
197: routine->argc < routine->descr_count) {
198: bad_arg = TRUE;
199: break;
200: }
201: /* Validate that the arg_descr field is within the part of
202: * the struct that follows the routine array: */
203: if ((char *)&routine->arg_descr[0] <
204: (char *)&new_subsystem->user.routine[num_routines]
205: ||
206: (char *)&routine->arg_descr[routine->descr_count] >
207: (char *)&new_subsystem->user + (int)user_subsysCount
208: ) {
209: printf("Arg descr out of bounds: arg_descr=%x, &routine.num_routines=%x\n",
210: &routine->arg_descr[0], &new_subsystem->user.routine[num_routines]);
211: printf(" new_subsys->user + subsysCount = %x\n",
212: (char *)&new_subsystem->user + (int)user_subsysCount);
213: #if MACH_DEBUG && MACH_KDB
214: subsystem_print(new_subsystem);
215: /* Not all of the arg_descr pointers have necessarily
216: been corrected, but this just means that we print
217: the arg_descr from the user's input subsystem
218: instead of the copy we are building. */
219: #endif /* MACH_DEBUG && MACH_KDB */
220: bad_arg = TRUE;
221: break;
222: }
223: }
224: if (bad_arg) {
225: kfree((vm_offset_t)new_subsystem, size);
226: return(KERN_INVALID_ADDRESS);
227: }
228:
229: /* Convert the user base address to a kernel address: */
230: new_subsystem->user.base_addr = (vm_address_t)&new_subsystem->user;
231:
232: /* Make the user subsystem point at the containing system data
233: * structure, so we can get from a port (which points to the user
234: * subsystem data) to the system subsystem struct:
235: */
236: new_subsystem->user.subsystem = new_subsystem;
237:
238: ipc_subsystem_init(new_subsystem);
239:
240: task_lock(parent_task);
241: if (parent_task->active) {
242: parent_task->subsystem_count++;
243: queue_enter(&parent_task->subsystem_list, new_subsystem,
244: subsystem_t, subsystem_list);
245: } else
246: deallocate = TRUE;
247: task_unlock(parent_task);
248:
249: if (deallocate) {
250: /* release ref we would have given our caller */
251: subsystem_deallocate(new_subsystem);
252: return(KERN_INVALID_TASK);
253: }
254:
255: ipc_subsystem_enable(new_subsystem);
256:
257: *subsystem_p = new_subsystem;
258: return(KERN_SUCCESS);
259: }
260:
261: /*
262: * Routine: subsystem_reference
263: * Purpose:
264: * Increments the reference count on a subsystem.
265: * Conditions:
266: * Nothing is locked.
267: */
268: void
269: subsystem_reference(
270: register subsystem_t subsystem)
271: {
272: spl_t s;
273:
274: if (subsystem == SUBSYSTEM_NULL)
275: return;
276:
277: s = splsched();
278: subsystem_lock(subsystem);
279: subsystem->ref_count++;
280: subsystem_unlock(subsystem);
281: splx(s);
282: }
283:
284:
285:
286: /*
287: * Routine: subsystem_deallocate
288: * Purpose:
289: * Decrements the reference count on a subsystem. If 0,
290: * destroys the subsystem. Must have no ports registered on it
291: * when it is destroyed.
292: * Conditions:
293: * The subsystem is locked, and
294: * the caller has a reference, which is consumed.
295: */
296:
297: void
298: subsystem_deallocate(
299: subsystem_t subsystem)
300: {
301: task_t task;
302: spl_t s;
303:
304: if (subsystem == SUBSYSTEM_NULL)
305: return;
306:
307: s = splsched();
308: subsystem_lock(subsystem);
309: if (--subsystem->ref_count > 0) {
310: subsystem_unlock(subsystem);
311: splx(s);
312: return;
313: }
314:
315: /*
316: * Count is 0, so destroy the subsystem. Need to restore the
317: * reference temporarily, and lock the task first:
318: */
319: ipc_subsystem_disable(subsystem);
320:
321: subsystem->ref_count = 1;
322: subsystem_unlock(subsystem);
323: splx(s);
324:
325: task = subsystem->task;
326: task_lock(task);
327: s = splsched();
328: subsystem_lock(subsystem);
329:
330: /* Check again, since we temporarily unlocked the subsystem: */
331: if (--subsystem->ref_count == 0) {
332:
333: task->subsystem_count--;
334: queue_remove(&task->subsystem_list, subsystem, subsystem_t,
335: subsystem_list);
336: ipc_subsystem_terminate(subsystem);
337: subsystem_unlock(subsystem);
338: splx(s);
339: kfree((vm_offset_t) subsystem, subsystem->size);
340: task_unlock(task);
341: return;
342: }
343:
344: ipc_subsystem_enable(subsystem);
345:
346: subsystem_unlock(subsystem);
347: splx(s);
348: task_unlock(task);
349: }
350:
351:
352: #include <mach_kdb.h>
353: #if MACH_KDB
354:
355: #include <ddb/db_output.h>
356: #include <ddb/db_sym.h>
357: #include <ddb/db_print.h>
358: #include <ddb/db_command.h>
359:
360: #define printf kdbprintf
361:
362: /*
363: * Routine: subsystem_print
364: * Purpose:
365: * Pretty-print a subsystem for kdb.
366: */
367:
368: void rpc_subsystem_print(rpc_subsystem_t subsys);
369:
370: void
371: subsystem_print(
372: subsystem_t subsystem)
373: {
374: extern int db_indent;
375:
376: iprintf("subsystem 0x%x\n", subsystem);
377:
378: db_indent += 2;
379:
380: iprintf("ref %d size %x task %x port %x\n", subsystem->ref_count,
381: subsystem->size, subsystem->task, subsystem->ipc_self);
382: rpc_subsystem_print(&subsystem->user);
383:
384: /* ipc_object_print(&port->ip_object);
385: * iprintf("receiver=0x%x", port->ip_receiver);
386: * printf(", receiver_name=0x%x\n", port->ip_receiver_name);
387: */
388: db_indent -=2;
389: }
390:
391: struct flagnames {
392: char *name;
393: int bit;
394: } arg_type_names[] = {
395: "port", MACH_RPC_PORT, "array", MACH_RPC_ARRAY,
396: "variable", MACH_RPC_VARIABLE, "in", MACH_RPC_IN, "out", MACH_RPC_OUT,
397: "pointer", MACH_RPC_POINTER, "phys_copy", MACH_RPC_PHYSICAL_COPY,
398: "virt_copy", MACH_RPC_VIRTUAL_COPY, "deallocate", MACH_RPC_DEALLOCATE,
399: "onstack", MACH_RPC_ONSTACK, "bounded", MACH_RPC_BOUND,
400: };
401:
402: void
403: rpc_subsystem_print(
404: rpc_subsystem_t subsys)
405: {
406: int i, num_routines;
407:
408: iprintf("rpc_subsystem 0x%x\n", subsys);
409:
410: db_indent += 2;
411:
412: num_routines = subsys->end - subsys->start;
413: iprintf("start %d end %d (%d routines) maxsize %x base %x\n",
414: subsys->start, subsys->end, num_routines, subsys->maxsize,
415: subsys->base_addr);
416: for (i = 0; i < num_routines; i++) {
417: routine_descriptor_t routine = subsys->routine + i;
418: routine_arg_descriptor_t args = routine->arg_descr;
419: int j, type, disposition;
420: struct flagnames *n;
421: char *sep;
422:
423: iprintf("%x #%d:", routine, subsys->start + i);
424: if (routine->impl_routine == 0) {
425: printf(" skip\n");
426: continue;
427: }
428: printf("\n");
429: db_indent += 2;
430: iprintf("impl ");
431: db_printsym((db_expr_t) routine->impl_routine, DB_STGY_PROC);
432: printf("\n");
433: iprintf("stub ");
434: db_printsym((db_expr_t) routine->stub_routine, DB_STGY_PROC);
435: printf("\n");
436: iprintf("argc %d descr_count %d max_reply %x\n",
437: routine->argc, routine->descr_count, routine->max_reply_msg);
438: for (j = 0; j < routine->descr_count; j++) {
439: iprintf("%x desc %d: size %d count %d offset %x type", &args[j], j,
440: args[j].size, args[j].count, args[j].offset);
441: sep = " ";
442: type = args[j].type;
443: for (n = arg_type_names; n->name != 0; n++) {
444: if (type & n->bit) {
445: printf("%s%s", sep, n->name);
446: sep = "|";
447: type &= ~n->bit; /* Might have an alias */
448: }
449: }
450: #define NAME_MASK (3 << NAME_SHIFT) /* XXX magic numbers */
451: #define ACTION_MASK (3 << ACTION_SHIFT)
452: #define DISPOSITION_MASK (NAME_MASK | ACTION_MASK)
453: disposition = type & DISPOSITION_MASK;
454: type &= ~DISPOSITION_MASK;
455: if (sep[0] != '|' || type != 0)
456: printf("%s%x", sep, type);
457: switch (disposition & ACTION_MASK) {
458: case MACH_RPC_MOVE: printf(" move"); break;
459: case MACH_RPC_COPY: printf(" copy"); break;
460: case MACH_RPC_MAKE: printf(" make"); break;
461: }
462: switch (disposition & NAME_MASK) {
463: case MACH_RPC_RECEIVE: printf(" receive"); break;
464: case MACH_RPC_SEND: printf(" send"); break;
465: case MACH_RPC_SEND_ONCE: printf(" send-once"); break;
466: }
467: printf("\n");
468: }
469: db_indent -= 2;
470: }
471:
472: db_indent -= 2;
473: }
474:
475: void
476: db_show_subsystem(
477: db_expr_t addr,
478: boolean_t have_addr,
479: db_expr_t count,
480: char *modif)
481: {
482: if (!have_addr || addr == 0) {
483: db_printf("No subsystem\n");
484: return;
485: }
486: if (db_option(modif, 'r'))
487: rpc_subsystem_print((rpc_subsystem_t) addr);
488: else
489: subsystem_print((subsystem_t) addr);
490: }
491:
492: #endif /* MACH_KDB || MACH_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.