Annotation of XNU/osfmk/kern/ipc_mig.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:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: /*
        !            51:  */
        !            52: 
        !            53: #include <norma_vm.h>
        !            54: #include <mach_rt.h>
        !            55: #include <dipc.h>
        !            56: 
        !            57: #include <mach/boolean.h>
        !            58: #include <mach/port.h>
        !            59: #include <mach/thread_status.h>
        !            60: #include <mach/mig_errors.h>
        !            61: #include <mach/mach_types.h>
        !            62: #include <mach/mach_traps.h>
        !            63: #include <kern/ast.h>
        !            64: #include <kern/ipc_mig.h>
        !            65: #include <kern/task.h>
        !            66: #include <kern/thread.h>
        !            67: #include <kern/ipc_kobject.h>
        !            68: #include <kern/misc_protos.h>
        !            69: #include <vm/vm_map.h>
        !            70: #include <vm/vm_user.h>
        !            71: #include <ipc/port.h>
        !            72: #include <ipc/ipc_kmsg.h>
        !            73: #include <ipc/ipc_entry.h>
        !            74: #include <ipc/ipc_object.h>
        !            75: #include <ipc/ipc_mqueue.h>
        !            76: #include <ipc/ipc_space.h>
        !            77: #include <ipc/ipc_port.h>
        !            78: #include <ipc/ipc_pset.h>
        !            79: 
        !            80: /* Default (zeroed) template for qos */
        !            81: 
        !            82: static mach_port_qos_t qos_template;
        !            83: 
        !            84: /*
        !            85:  *     Routine:        mach_msg_send_from_kernel
        !            86:  *     Purpose:
        !            87:  *             Send a message from the kernel.
        !            88:  *
        !            89:  *             This is used by the client side of KernelUser interfaces
        !            90:  *             to implement SimpleRoutines.  Currently, this includes
        !            91:  *             memory_object messages.
        !            92:  *     Conditions:
        !            93:  *             Nothing locked.
        !            94:  *     Returns:
        !            95:  *             MACH_MSG_SUCCESS        Sent the message.
        !            96:  *             MACH_SEND_INVALID_DATA  Bad destination port.
        !            97:  */
        !            98: 
        !            99: mach_msg_return_t
        !           100: mach_msg_send_from_kernel(
        !           101:        mach_msg_header_t       *msg,
        !           102:        mach_msg_size_t         send_size)
        !           103: {
        !           104:        ipc_kmsg_t kmsg;
        !           105:        mach_msg_return_t mr;
        !           106: 
        !           107:        if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port))
        !           108:                return MACH_SEND_INVALID_DEST;
        !           109: 
        !           110:        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
        !           111:        if (mr != MACH_MSG_SUCCESS)
        !           112:                panic("mach_msg_send_from_kernel");
        !           113: 
        !           114:        ipc_kmsg_copyin_from_kernel(kmsg);
        !           115:        ipc_kmsg_send_always(kmsg);
        !           116: 
        !           117:        return MACH_MSG_SUCCESS;
        !           118: }
        !           119: 
        !           120: /*
        !           121:  *     Routine:        mach_msg_rpc_from_kernel
        !           122:  *     Purpose:
        !           123:  *             Send a message from the kernel and receive a reply.
        !           124:  *             Uses ith_rpc_reply for the reply port.
        !           125:  *
        !           126:  *             This is used by the client side of KernelUser interfaces
        !           127:  *             to implement Routines.
        !           128:  *     Conditions:
        !           129:  *             Nothing locked.
        !           130:  *     Returns:
        !           131:  *             MACH_MSG_SUCCESS        Sent the message.
        !           132:  *             MACH_RCV_PORT_DIED      The reply port was deallocated.
        !           133:  */
        !           134: 
        !           135: mach_msg_return_t
        !           136: mach_msg_rpc_from_kernel(
        !           137:        mach_msg_header_t       *msg,
        !           138:        mach_msg_size_t         send_size,
        !           139:        mach_msg_size_t         rcv_size)
        !           140: {
        !           141:        thread_t self = current_thread();
        !           142:        ipc_port_t reply;
        !           143:        ipc_kmsg_t kmsg;
        !           144:        mach_port_seqno_t seqno;
        !           145:        mach_msg_return_t mr;
        !           146: 
        !           147:        assert(MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port));
        !           148:        assert(msg->msgh_local_port == MACH_PORT_NULL);
        !           149: 
        !           150:        self->ith_scatter_list = MACH_MSG_BODY_NULL;
        !           151: 
        !           152:        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
        !           153:        if (mr != MACH_MSG_SUCCESS)
        !           154:                panic("mach_msg_rpc_from_kernel");
        !           155: 
        !           156:        rpc_lock(self);
        !           157: 
        !           158:        reply = self->ith_rpc_reply;
        !           159:        if (reply == IP_NULL) {
        !           160:                rpc_unlock(self);
        !           161:                reply = ipc_port_alloc_reply();
        !           162:                rpc_lock(self);
        !           163:                if ((reply == IP_NULL) ||
        !           164:                    (self->ith_rpc_reply != IP_NULL))
        !           165:                        panic("mach_msg_rpc_from_kernel");
        !           166:                self->ith_rpc_reply = reply;
        !           167:        }
        !           168: 
        !           169:        /* insert send-once right for the reply port */
        !           170:        kmsg->ikm_header.msgh_local_port = reply;
        !           171:        kmsg->ikm_header.msgh_bits |=
        !           172:                MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE);
        !           173: 
        !           174:        ipc_port_reference(reply);
        !           175:        rpc_unlock(self);
        !           176: 
        !           177:        ipc_kmsg_copyin_from_kernel(kmsg);
        !           178: 
        !           179:        ipc_kmsg_send_always(kmsg);
        !           180: 
        !           181:        for (;;) {
        !           182:                ipc_mqueue_t mqueue;
        !           183: 
        !           184:                ip_lock(reply);
        !           185:                if ( !ip_active(reply)) {
        !           186:                        ip_unlock(reply);
        !           187:                        ipc_port_release(reply);
        !           188:                        return MACH_RCV_PORT_DIED;
        !           189:                }
        !           190:                if (!self->top_act || !self->top_act->active) {
        !           191:                        ip_unlock(reply);
        !           192:                        ipc_port_release(reply);
        !           193:                        return MACH_RCV_INTERRUPTED;
        !           194:                }
        !           195: 
        !           196:                assert(reply->ip_pset_count == 0);
        !           197:                mqueue = &reply->ip_messages;
        !           198:                ip_unlock(reply);
        !           199: 
        !           200:                mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
        !           201:                                        MACH_MSG_SIZE_MAX,
        !           202:                                        MACH_MSG_TIMEOUT_NONE,
        !           203:                                        THREAD_INTERRUPTIBLE,
        !           204:                                        &kmsg, &seqno);
        !           205:                if (mr == MACH_MSG_SUCCESS)
        !           206:                  {
        !           207:                        break;
        !           208:                  }
        !           209: 
        !           210:                assert(mr == MACH_RCV_INTERRUPTED);
        !           211: 
        !           212:                if (self->top_act && self->top_act->handlers) {
        !           213:                        ipc_port_release(reply);
        !           214:                        return(mr);
        !           215:                }
        !           216:        }
        !           217:        ipc_port_release(reply);
        !           218: 
        !           219:        /*
        !           220:         * XXXXX  Set manually for now ...
        !           221:         *      No, why even bother, since the effort is wasted?
        !           222:         *
        !           223:        { mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *)
        !           224:                ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size);
        !           225:        trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
        !           226:        trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
        !           227:        }
        !           228:         *****/
        !           229: 
        !           230:        if (rcv_size < kmsg->ikm_header.msgh_size) {
        !           231:                ipc_kmsg_copyout_dest(kmsg, ipc_space_reply);
        !           232:                ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
        !           233:                return MACH_RCV_TOO_LARGE;
        !           234:        }
        !           235: 
        !           236:        /*
        !           237:         *      We want to preserve rights and memory in reply!
        !           238:         *      We don't have to put them anywhere; just leave them
        !           239:         *      as they are.
        !           240:         */
        !           241: 
        !           242:        ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
        !           243:        ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
        !           244:        return MACH_MSG_SUCCESS;
        !           245: }
        !           246: 
        !           247: 
        !           248: /************** These Calls are set up for kernel-loaded tasks   **************/
        !           249: /************** Apple does not plan on supporting that. These    **************/
        !           250: /************** need to be reworked to deal with the kernel      **************/
        !           251: /************** proper to eliminate the kernel specific code MIG **************/
        !           252: /************** must generate.                                   **************/
        !           253: 
        !           254: 
        !           255: /*
        !           256:  *     Routine:        mach_msg
        !           257:  *     Purpose:
        !           258:  *             Like mach_msg_overwrite_trap except that message buffers
        !           259:  *             live in kernel space.  Doesn't handle any options.
        !           260:  *
        !           261:  *             This is used by in-kernel server threads to make
        !           262:  *             kernel calls, to receive request messages, and
        !           263:  *             to send reply messages.
        !           264:  *     Conditions:
        !           265:  *             Nothing locked.
        !           266:  *     Returns:
        !           267:  */
        !           268: 
        !           269: mach_msg_return_t
        !           270: mach_msg_overwrite(
        !           271:        mach_msg_header_t       *msg,
        !           272:        mach_msg_option_t       option,
        !           273:        mach_msg_size_t         send_size,
        !           274:        mach_msg_size_t         rcv_size,
        !           275:        mach_port_name_t        rcv_name,
        !           276:        mach_msg_timeout_t      timeout,
        !           277:        mach_port_name_t        notify,
        !           278:        mach_msg_header_t       *rcv_msg,
        !           279:         mach_msg_size_t                rcv_msg_size)
        !           280: {
        !           281:        ipc_space_t space = current_space();
        !           282:        vm_map_t map = current_map();
        !           283:        ipc_kmsg_t kmsg;
        !           284:        mach_port_seqno_t seqno;
        !           285:        mach_msg_return_t mr;
        !           286:        mach_msg_format_0_trailer_t *trailer;
        !           287: 
        !           288:        if (option & MACH_SEND_MSG) {
        !           289:                mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
        !           290:                if (mr != MACH_MSG_SUCCESS)
        !           291:                        panic("mach_msg");
        !           292: 
        !           293:                mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
        !           294:                if (mr != MACH_MSG_SUCCESS) {
        !           295:                        ikm_free(kmsg);
        !           296:                        return mr;
        !           297:                }
        !           298: 
        !           299:                do
        !           300:                        mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE,
        !           301:                                             MACH_MSG_TIMEOUT_NONE);
        !           302:                while (mr == MACH_SEND_INTERRUPTED);
        !           303:                assert(mr == MACH_MSG_SUCCESS);
        !           304:        }
        !           305: 
        !           306:        if (option & MACH_RCV_MSG) {
        !           307:                thread_t self = current_thread();
        !           308: 
        !           309:                self->ith_scatter_list = MACH_MSG_BODY_NULL;
        !           310:                do {
        !           311:                        ipc_object_t object;
        !           312:                        ipc_mqueue_t mqueue;
        !           313: 
        !           314:                        mr = ipc_mqueue_copyin(space, rcv_name,
        !           315:                                               &mqueue, &object);
        !           316:                        if (mr != MACH_MSG_SUCCESS)
        !           317:                                return mr;
        !           318:                        /* hold ref for object */
        !           319: 
        !           320:                        mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
        !           321:                                                MACH_MSG_SIZE_MAX,
        !           322:                                                MACH_MSG_TIMEOUT_NONE,
        !           323:                                                THREAD_ABORTSAFE,
        !           324:                                                &kmsg, &seqno);
        !           325:                        ipc_object_release(object);
        !           326: 
        !           327:                } while (mr == MACH_RCV_INTERRUPTED);
        !           328:                if (mr != MACH_MSG_SUCCESS)
        !           329:                        return mr;
        !           330: 
        !           331:                trailer = (mach_msg_format_0_trailer_t *) 
        !           332:                    ((vm_offset_t)&kmsg->ikm_header + kmsg->ikm_header.msgh_size);
        !           333:                if (option & MACH_RCV_TRAILER_MASK) {
        !           334:                        trailer->msgh_seqno = seqno;
        !           335:                        trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
        !           336:                }
        !           337: 
        !           338:                if (rcv_size < (kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size)) {
        !           339:                        ipc_kmsg_copyout_dest(kmsg, space);
        !           340:                        ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
        !           341:                        return MACH_RCV_TOO_LARGE;
        !           342:                }
        !           343: 
        !           344:                mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL,
        !           345:                                      MACH_MSG_BODY_NULL);
        !           346:                if (mr != MACH_MSG_SUCCESS) {
        !           347:                        if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
        !           348:                                ipc_kmsg_put_to_kernel(msg, kmsg,
        !           349:                                                kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size);
        !           350:                        } else {
        !           351:                                ipc_kmsg_copyout_dest(kmsg, space);
        !           352:                                ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
        !           353:                        }
        !           354: 
        !           355:                        return mr;
        !           356:                }
        !           357: 
        !           358:                ipc_kmsg_put_to_kernel(msg, kmsg, 
        !           359:                      kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size);
        !           360:        }
        !           361: 
        !           362:        return MACH_MSG_SUCCESS;
        !           363: }
        !           364: 
        !           365: /*
        !           366:  *     Routine:        mig_get_reply_port
        !           367:  *     Purpose:
        !           368:  *             Called by client side interfaces living in the kernel
        !           369:  *             to get a reply port.  This port is used for
        !           370:  *             mach_msg() calls which are kernel calls.
        !           371:  */
        !           372: mach_port_t
        !           373: mig_get_reply_port(void)
        !           374: {
        !           375:        thread_t self = current_thread();
        !           376: 
        !           377:        assert(self->ith_mig_reply == (mach_port_t)0);
        !           378: 
        !           379:        /* 
        !           380:         * JMM - for now we have no real clients of this under the kernel
        !           381:         * loaded server model because we only have one of those.  In order
        !           382:         * to avoid MIG changes, we just return null here - and return]
        !           383:         * references to ipc_port_t's instead of names.
        !           384:         *
        !           385:         * if (self->ith_mig_reply == MACH_PORT_NULL)
        !           386:         *      self->ith_mig_reply = mach_reply_port();
        !           387:         */
        !           388:        return self->ith_mig_reply;
        !           389: }
        !           390: 
        !           391: /*
        !           392:  *     Routine:        mig_dealloc_reply_port
        !           393:  *     Purpose:
        !           394:  *             Called by client side interfaces to get rid of a reply port.
        !           395:  *             Shouldn't ever be called inside the kernel, because
        !           396:  *             kernel calls shouldn't prompt Mig to call it.
        !           397:  */
        !           398: 
        !           399: void
        !           400: mig_dealloc_reply_port(
        !           401:        mach_port_t reply_port)
        !           402: {
        !           403:        panic("mig_dealloc_reply_port");
        !           404: }
        !           405: 
        !           406: /*
        !           407:  *     Routine:        mig_put_reply_port
        !           408:  *     Purpose:
        !           409:  *             Called by client side interfaces after each RPC to 
        !           410:  *             let the client recycle the reply port if it wishes.
        !           411:  */
        !           412: void
        !           413: mig_put_reply_port(
        !           414:        mach_port_t reply_port)
        !           415: {
        !           416: }
        !           417: 
        !           418: /*
        !           419:  * mig_strncpy.c - by Joshua Block
        !           420:  *
        !           421:  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
        !           422:  * OUGHT to do:  Copies the (null terminated) string in src into dest, a 
        !           423:  * buffer of length len.  Assures that the copy is still null terminated
        !           424:  * and doesn't overflow the buffer, truncating the copy if necessary.
        !           425:  *
        !           426:  * Parameters:
        !           427:  * 
        !           428:  *     dest - Pointer to destination buffer.
        !           429:  * 
        !           430:  *     src - Pointer to source string.
        !           431:  * 
        !           432:  *     len - Length of destination buffer.
        !           433:  */
        !           434: int 
        !           435: mig_strncpy(
        !           436:        char    *dest,
        !           437:        char    *src,
        !           438:        int     len)
        !           439: {
        !           440:     int i;
        !           441: 
        !           442:     if (len <= 0)
        !           443:        return 0;
        !           444: 
        !           445:     for (i=1; i<len; i++)
        !           446:        if (! (*dest++ = *src++))
        !           447:            return i;
        !           448: 
        !           449:     *dest = '\0';
        !           450:     return i;
        !           451: }
        !           452: 
        !           453: char *
        !           454: mig_user_allocate(
        !           455:        vm_size_t       size)
        !           456: {
        !           457:        return (char *)kalloc(size);
        !           458: }
        !           459: 
        !           460: void
        !           461: mig_user_deallocate(
        !           462:        char            *data,
        !           463:        vm_size_t       size)
        !           464: {
        !           465:        kfree((vm_offset_t)data, size);
        !           466: }
        !           467: 
        !           468: thread_act_t
        !           469: port_name_to_act(
        !           470:        mach_port_name_t        name)
        !           471: {
        !           472:        thread_act_t thr_act;
        !           473:        ipc_port_t kern_port;
        !           474:        kern_return_t kr;
        !           475: 
        !           476:        if (MACH_PORT_VALID(name)) {
        !           477:                kr = ipc_object_copyin(current_space(), name,
        !           478:                                       MACH_MSG_TYPE_COPY_SEND,
        !           479:                                       (ipc_object_t *) &kern_port);
        !           480:                if (kr != KERN_SUCCESS)
        !           481:                        return THR_ACT_NULL;
        !           482: 
        !           483:                thr_act = convert_port_to_act(kern_port);
        !           484:                
        !           485:                if (IP_VALID(kern_port))
        !           486:                        ipc_port_release_send(kern_port);
        !           487:        }
        !           488:        return thr_act;
        !           489: }
        !           490: 
        !           491: task_t
        !           492: port_name_to_task(
        !           493:        mach_port_name_t name)
        !           494: {
        !           495:        ipc_port_t kern_port;
        !           496:        kern_return_t kr;
        !           497:        task_t task = TASK_NULL;
        !           498: 
        !           499:        if (MACH_PORT_VALID(name)) {
        !           500:                kr = ipc_object_copyin(current_space(), name,
        !           501:                                       MACH_MSG_TYPE_COPY_SEND,
        !           502:                                       (ipc_object_t *) &kern_port);
        !           503:                if (kr != KERN_SUCCESS)
        !           504:                        return TASK_NULL;
        !           505: 
        !           506:                task = convert_port_to_task(kern_port);
        !           507: 
        !           508:                if (IP_VALID(kern_port))
        !           509:                        ipc_port_release_send(kern_port);
        !           510:        }
        !           511:        return task;
        !           512: }

unix.superglobalmegacorp.com

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