Annotation of XNU/osfmk/kern/subsystem.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.