2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
28 * Revision 1.1.1.1 1998/09/22 21:05:32 wsanchez
29 * Import of Mac OS X kernel (~semeria)
31 * Revision 1.2 1998/04/29 17:36:19 mburg
34 * Revision 1.1.18.1 1998/02/03 09:30:24 gdt
36 * [1998/02/03 09:15:10 gdt]
38 * Revision 1.1.16.1 1997/06/17 02:59:23 devrcs
39 * Added call to `ipc_subsystem_terminate()' to `subsystem_deallocate()'
41 * [1997/03/18 18:25:55 rkc]
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]
49 * mk6 CR668 - 1.3b26 merge
51 * [1994/11/04 09:32:40 dwm]
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]
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]
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]
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]
69 * Revision 1.1.3.2 1994/01/20 16:25:29 condict
71 * [1994/01/20 16:24:32 condict]
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]
77 * Revision 1.1.1.4 1994/01/20 02:45:10 condict
78 * Make user subsystem point at containing system subsytem struct.
80 * Revision 1.1.1.3 1994/01/15 22:01:19 condict
81 * Validate user subsystem data, convert user ptrs to kernel ptrs.
83 * Revision 1.1.1.2 1994/01/13 02:39:58 condict
84 * Implementation of RPC subsystem object, for server co-location.
89 * Functions to manipulate RPC subsystem descriptions.
92 #include <mach/port.h>
93 #include <mach/kern_return.h>
94 #include <kern/task.h>
95 #include <kern/lock.h>
97 #include <kern/zalloc.h>
98 #include <kern/ipc_subsystem.h>
99 #include <kern/subsystem.h>
100 #include <kern/misc_protos.h>
102 #define SUBSYSTEM_MIN_SIZE 12
103 #define SUBSYSTEM_MAX_SIZE (2*1024*1024) /* What value is correct? */
109 /* Nothing to do on bootstrap, at the moment. */
113 * Routine: mach_subsystem_create
115 * Create a new RPC subsystem.
117 * Nothing locked. If successful, the subsystem is returned
118 * unlocked. (The caller has a reference.)
120 * KERN_SUCCESS The subsystem is allocated.
121 * KERN_INVALID_TASK The task is dead.
122 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
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
)
133 subsystem_t new_subsystem
;
135 boolean_t deallocate
= FALSE
;
139 boolean_t bad_arg
= FALSE
;
141 if (parent_task
== TASK_NULL
)
142 return(KERN_INVALID_ARGUMENT
);
144 if (user_subsysCount
< SUBSYSTEM_MIN_SIZE
||
145 user_subsysCount
> SUBSYSTEM_MAX_SIZE
)
146 return(KERN_INVALID_ARGUMENT
);
149 * Allocate a subsystem and initialize:
152 size
= (vm_size_t
)user_subsysCount
+ sizeof(struct subsystem
) -
153 sizeof(struct rpc_subsystem
);
154 new_subsystem
= (subsystem_t
) kalloc(size
);
156 if (new_subsystem
== 0)
157 return(KERN_RESOURCE_SHORTAGE
);
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
);
164 /* Copy the user subsystem data to a permanent place: */
165 bcopy((char *)user_subsys
, (char *)&(new_subsystem
->user
),
166 (int)user_subsysCount
);
168 /* Validate the user-specified fields of the subsystem: */
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
175 kfree((vm_offset_t
)new_subsystem
, size
);
176 return(KERN_INVALID_ADDRESS
);
179 /* The following is for converting the user pointers in the
180 * subsystem struct to kernel pointers:
182 offset
= (char *)&new_subsystem
->user
-
183 (char *)new_subsystem
->user
.base_addr
; /* The user addr */
185 for (i
= 0; i
< num_routines
; i
++) {
186 routine_descriptor_t routine
= &new_subsystem
->user
.routine
[i
];
188 /* If this is a "skip" routine, ignore it: */
189 if (!routine
->impl_routine
)
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
);
196 if (routine
->argc
> 1000000 ||
197 routine
->argc
< routine
->descr_count
) {
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
]
206 (char *)&routine
->arg_descr
[routine
->descr_count
] >
207 (char *)&new_subsystem
->user
+ (int)user_subsysCount
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 */
225 kfree((vm_offset_t
)new_subsystem
, size
);
226 return(KERN_INVALID_ADDRESS
);
229 /* Convert the user base address to a kernel address: */
230 new_subsystem
->user
.base_addr
= (vm_address_t
)&new_subsystem
->user
;
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:
236 new_subsystem
->user
.subsystem
= new_subsystem
;
238 ipc_subsystem_init(new_subsystem
);
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
);
247 task_unlock(parent_task
);
250 /* release ref we would have given our caller */
251 subsystem_deallocate(new_subsystem
);
252 return(KERN_INVALID_TASK
);
255 ipc_subsystem_enable(new_subsystem
);
257 *subsystem_p
= new_subsystem
;
258 return(KERN_SUCCESS
);
262 * Routine: subsystem_reference
264 * Increments the reference count on a subsystem.
270 register subsystem_t subsystem
)
274 if (subsystem
== SUBSYSTEM_NULL
)
278 subsystem_lock(subsystem
);
279 subsystem
->ref_count
++;
280 subsystem_unlock(subsystem
);
287 * Routine: subsystem_deallocate
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.
293 * The subsystem is locked, and
294 * the caller has a reference, which is consumed.
298 subsystem_deallocate(
299 subsystem_t subsystem
)
304 if (subsystem
== SUBSYSTEM_NULL
)
308 subsystem_lock(subsystem
);
309 if (--subsystem
->ref_count
> 0) {
310 subsystem_unlock(subsystem
);
316 * Count is 0, so destroy the subsystem. Need to restore the
317 * reference temporarily, and lock the task first:
319 ipc_subsystem_disable(subsystem
);
321 subsystem
->ref_count
= 1;
322 subsystem_unlock(subsystem
);
325 task
= subsystem
->task
;
328 subsystem_lock(subsystem
);
330 /* Check again, since we temporarily unlocked the subsystem: */
331 if (--subsystem
->ref_count
== 0) {
333 task
->subsystem_count
--;
334 queue_remove(&task
->subsystem_list
, subsystem
, subsystem_t
,
336 ipc_subsystem_terminate(subsystem
);
337 subsystem_unlock(subsystem
);
339 kfree((vm_offset_t
) subsystem
, subsystem
->size
);
344 ipc_subsystem_enable(subsystem
);
346 subsystem_unlock(subsystem
);
352 #include <mach_kdb.h>
355 #include <ddb/db_output.h>
356 #include <ddb/db_sym.h>
357 #include <ddb/db_print.h>
358 #include <ddb/db_command.h>
360 #define printf kdbprintf
363 * Routine: subsystem_print
365 * Pretty-print a subsystem for kdb.
368 void rpc_subsystem_print(rpc_subsystem_t subsys
);
372 subsystem_t subsystem
)
374 extern int db_indent
;
376 iprintf("subsystem 0x%x\n", subsystem
);
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
);
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);
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
,
404 rpc_subsystem_t subsys
)
408 iprintf("rpc_subsystem 0x%x\n", subsys
);
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
,
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
;
423 iprintf("%x #%d:", routine
, subsys
->start
+ i
);
424 if (routine
->impl_routine
== 0) {
431 db_printsym((db_expr_t
) routine
->impl_routine
, DB_STGY_PROC
);
434 db_printsym((db_expr_t
) routine
->stub_routine
, DB_STGY_PROC
);
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
);
443 for (n
= arg_type_names
; n
->name
!= 0; n
++) {
445 printf("%s%s", sep
, n
->name
);
447 type
&= ~n
->bit
; /* Might have an alias */
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;
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;
482 if (!have_addr
|| addr
== 0) {
483 db_printf("No subsystem\n");
486 if (db_option(modif
, 'r'))
487 rpc_subsystem_print((rpc_subsystem_t
) addr
);
489 subsystem_print((subsystem_t
) addr
);
492 #endif /* MACH_KDB || MACH_DEBUG */