Annotation of XNU/osfmk/kern/subsystem.c, revision 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.