Annotation of kernel/kern/ipc_mig.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     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: #include <mach/boolean.h>
                     52: #include <mach/port.h>
                     53: #include <mach/message.h>
                     54: #include <mach/thread_status.h>
                     55: #include <kern/ast.h>
                     56: #include <kern/ipc_tt.h>
                     57: #include <kern/thread.h>
                     58: #include <kern/task.h>
                     59: #include <kern/ipc_kobject.h>
                     60: #include <vm/vm_map.h>
                     61: #include <vm/vm_user.h>
                     62: #include <ipc/port.h>
                     63: #include <ipc/ipc_kmsg.h>
                     64: #include <ipc/ipc_entry.h>
                     65: #include <ipc/ipc_object.h>
                     66: #include <ipc/ipc_mqueue.h>
                     67: #include <ipc/ipc_space.h>
                     68: #include <ipc/ipc_port.h>
                     69: #include <ipc/ipc_pset.h>
                     70: #include <ipc/ipc_thread.h>
                     71: 
                     72: 
                     73: /*
                     74:  *     Routine:        mach_msg_send_from_kernel
                     75:  *     Purpose:
                     76:  *             Send a message from the kernel.
                     77:  *
                     78:  *             This is used by the client side of KernelUser interfaces
                     79:  *             to implement SimpleRoutines.  Currently, this includes
                     80:  *             device_reply and memory_object messages.
                     81:  *     Conditions:
                     82:  *             Nothing locked.
                     83:  *     Returns:
                     84:  *             MACH_MSG_SUCCESS        Sent the message.
                     85:  *             MACH_SEND_INVALID_DATA  Bad destination port.
                     86:  */
                     87: 
                     88: mach_msg_return_t
                     89: mach_msg_send_from_kernel(msg, send_size)
                     90:        mach_msg_header_t *msg;
                     91:        mach_msg_size_t send_size;
                     92: {
                     93:        ipc_kmsg_t kmsg;
                     94:        mach_msg_return_t mr;
                     95: 
                     96:        if (!MACH_PORT_VALID(msg->msgh_remote_port))
                     97:                return MACH_SEND_INVALID_DEST;
                     98: 
                     99:        mr = ipc_kmsg_get_from_kernel(msg, MACH_MSG_OPTION_NONE,
                    100:                                      send_size, MAX_TRAILER_SIZE,
                    101:                                      &kmsg);
                    102:        if (mr != MACH_MSG_SUCCESS)
                    103:                panic("mach_msg_send_from_kernel");
                    104: 
                    105:        ipc_kmsg_copyin_from_kernel(kmsg);
                    106:        ipc_mqueue_send_always(kmsg);
                    107: 
                    108:        return MACH_MSG_SUCCESS;
                    109: }
                    110: 
                    111: /*
                    112:  *     Routine:        mach_msg_abort_rpc
                    113:  *     Purpose:
                    114:  *             Destroy the thread's ith_rpc_reply port.
                    115:  *             This will interrupt a mach_msg_rpc_from_kernel
                    116:  *             with a MACH_RCV_PORT_DIED return code.
                    117:  *     Conditions:
                    118:  *             Nothing locked.
                    119:  */
                    120: 
                    121: void
                    122: mach_msg_abort_rpc(thread)
                    123:        ipc_thread_t thread;
                    124: {
                    125:        ipc_port_t reply = IP_NULL;
                    126: 
                    127:        ith_lock(thread);
                    128:        if (thread->ith_self != IP_NULL) {
                    129:                reply = thread->ith_rpc_reply;
                    130:                thread->ith_rpc_reply = IP_NULL;
                    131:        }
                    132:        ith_unlock(thread);
                    133: 
                    134:        if (reply != IP_NULL)
                    135:                ipc_port_dealloc_reply(reply);
                    136: }
                    137: 
                    138: msg_return_t
                    139: msg_send_from_kernel(msg, option, time_out)
                    140:        msg_header_t *msg;
                    141:        msg_option_t option;
                    142:        msg_timeout_t time_out;
                    143: {
                    144:        msg_size_t send_size = msg->msg_size;
                    145:        ipc_kmsg_t kmsg;
                    146:        integer_t send_delta = send_size;
                    147:        mach_msg_return_t mr;
                    148: 
                    149:        send_size = (send_size + 3) & ~3; /* round up */
                    150:        send_delta -= send_size;
                    151: 
                    152:        mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
                    153:                                        MACH_MSG_OPTION_NONE,
                    154:                                        (mach_msg_size_t) send_size,
                    155:                                        send_delta,
                    156:                                        &kmsg);
                    157:        if (mr != MACH_MSG_SUCCESS)
                    158:                return msg_return_translate(mr);
                    159: 
                    160:        ipc_kmsg_copyin_compat_from_kernel(kmsg);
                    161:        if (option & SEND_NOTIFY) {
                    162:                panic("msg_send_from_kernel");
                    163:        } else
                    164:                mr = ipc_mqueue_send(kmsg,
                    165:                                     ((option & SEND_TIMEOUT) ?
                    166:                                      MACH_SEND_TIMEOUT :
                    167:                                      MACH_MSG_OPTION_NONE) |
                    168:                                      MACH_SEND_ALWAYS | MACH_SEND_SWITCH,
                    169:                                     (mach_msg_timeout_t) time_out,
                    170:                                     IMQ_NULL_CONTINUE);
                    171: 
                    172:        if (mr != MACH_MSG_SUCCESS)
                    173:                ipc_kmsg_destroy(kmsg);
                    174: 
                    175:        return msg_return_translate(mr);
                    176: }
                    177: 
                    178: msg_return_t
                    179: msg_send(msg, option, time_out)
                    180:        msg_header_t *msg;
                    181:        msg_option_t option;
                    182:        msg_timeout_t time_out;
                    183: {
                    184:        ipc_space_t space = current_space();
                    185:        vm_map_t map = current_map();
                    186:        msg_size_t send_size = msg->msg_size;
                    187:        ipc_kmsg_t kmsg;
                    188:        integer_t send_delta = send_size;
                    189:        mach_msg_return_t mr;
                    190: 
                    191:        send_size = (send_size + 3) & ~3; /* round up */
                    192:        send_delta -= send_size;
                    193: 
                    194:        if (send_size > MSG_SIZE_MAX)
                    195:                return SEND_MSG_TOO_LARGE;
                    196: 
                    197:        mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
                    198:                                        MACH_MSG_OPTION_NONE,
                    199:                                        (mach_msg_size_t) send_size,
                    200:                                        send_delta,
                    201:                                        &kmsg);
                    202:        if (mr != MACH_MSG_SUCCESS)
                    203:                return msg_return_translate(mr);
                    204: 
                    205:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
                    206:        if (mr != MACH_MSG_SUCCESS) {
                    207:                ikm_free(kmsg);
                    208:                return msg_return_translate(mr);
                    209:        }
                    210:        if (option & SEND_NOTIFY) {
                    211:                panic("msg_send notify");
                    212:        } else
                    213:                do {
                    214:                        if (option & SEND_SWITCH)
                    215:                                mr = ipc_mqueue_send(kmsg,
                    216:                                                ((option & SEND_TIMEOUT) ?
                    217:                                                MACH_SEND_TIMEOUT :
                    218:                                                MACH_MSG_OPTION_NONE) |
                    219:                                                MACH_SEND_SWITCH,
                    220:                                                (mach_msg_timeout_t) time_out,
                    221:                                                IMQ_NULL_CONTINUE);
                    222:                        else
                    223:                                mr = ipc_mqueue_send(kmsg,
                    224:                                                ((option & SEND_TIMEOUT) ?
                    225:                                                MACH_SEND_TIMEOUT :
                    226:                                                MACH_MSG_OPTION_NONE),
                    227:                                                (mach_msg_timeout_t) time_out,
                    228:                                                IMQ_NULL_CONTINUE);
                    229:                        if (mr == MACH_SEND_INTERRUPTED) {
                    230:                                while (thread_should_halt(current_thread()))
                    231:                                        thread_halt_self_with_continuation(
                    232:                                                        (void (*)(void)) 0);
                    233: 
                    234:                                if (option & SEND_INTERRUPT)
                    235:                                        break;
                    236:                        }
                    237:                } while (mr == MACH_SEND_INTERRUPTED);
                    238: 
                    239:        if (mr != MACH_MSG_SUCCESS)
                    240:                ipc_kmsg_destroy(kmsg);
                    241: 
                    242:        return msg_return_translate(mr);
                    243: }
                    244: 
                    245: msg_return_t
                    246: msg_receive(msg, option, time_out)
                    247:        msg_header_t *msg;
                    248:        msg_option_t option;
                    249:        msg_timeout_t time_out;
                    250: {
                    251:        ipc_space_t space = current_space();
                    252:        vm_map_t map = current_map();
                    253:        port_name_t rcv_name = msg->msg_local_port;
                    254:        msg_size_t rcv_size = msg->msg_size;
                    255:        ipc_object_t object;
                    256:        ipc_mqueue_t mqueue;
                    257:        ipc_kmsg_t kmsg;
                    258:        mach_port_seqno_t seqno;
                    259:        mach_msg_return_t mr;
                    260: 
                    261:        do {
                    262:                mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
                    263:                                        &mqueue, &object);
                    264:                if (mr != MACH_MSG_SUCCESS)
                    265:                        return msg_return_translate(mr);
                    266:                /* hold ref for object; mqueue is locked */
                    267: 
                    268:                mr = ipc_mqueue_receive(mqueue,
                    269:                                        ((option & RCV_TIMEOUT) ?
                    270:                                        MACH_RCV_TIMEOUT :
                    271:                                        MACH_MSG_OPTION_NONE) |
                    272:                                        MACH_RCV_OLD_FORMAT,
                    273:                                        (option & RCV_LARGE) ?
                    274:                                        (mach_msg_size_t) rcv_size :
                    275:                                        MACH_MSG_SIZE_MAX,
                    276:                                        (mach_msg_timeout_t) time_out,
                    277:                                        FALSE, IMQ_NULL_CONTINUE,
                    278:                                        &kmsg, &seqno, 0);
                    279:                /* mqueue is unlocked */
                    280:                ipc_object_release(object);
                    281:                if (mr == MACH_RCV_INTERRUPTED) {
                    282:                        while (thread_should_halt(current_thread()))
                    283:                                thread_halt_self_with_continuation(
                    284:                                                (void (*)(void)) 0);
                    285:                        
                    286:                        if (option & RCV_INTERRUPT)
                    287:                                break;
                    288:                }
                    289:        } while (mr == MACH_RCV_INTERRUPTED);
                    290:        if (mr != MACH_MSG_SUCCESS) {
                    291:                if (mr == MACH_RCV_TOO_LARGE) {
                    292:                        msg_size_t real_size =
                    293:                                (msg_size_t) (mach_msg_size_t) kmsg;
                    294: 
                    295:                        assert(real_size > rcv_size);
                    296:                        
                    297:                        msg->msg_size = real_size;
                    298:                }
                    299: 
                    300:                return msg_return_translate(mr);
                    301:        }
                    302:        
                    303:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
                    304:                assert(!(option & RCV_LARGE));
                    305:                
                    306:                ipc_kmsg_destroy(kmsg);
                    307:                return msg_return_translate(MACH_RCV_TOO_LARGE);
                    308:        }
                    309: 
                    310:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
                    311: 
                    312:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
                    313:        assert(mr == MACH_MSG_SUCCESS);
                    314: 
                    315:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
                    316:        ipc_kmsg_put_to_kernel((mach_msg_header_t *) msg, kmsg,
                    317:                                kmsg->ikm_header.msgh_size);
                    318:        return msg_return_translate(mr);
                    319: }
                    320: 
                    321: msg_return_t
                    322: msg_rpc(msg, option, rcv_size, send_timeout, rcv_timeout)
                    323:        msg_header_t *msg;      /* in/out */
                    324:        msg_option_t option;
                    325:        msg_size_t rcv_size;
                    326:        msg_timeout_t send_timeout;
                    327:        msg_timeout_t rcv_timeout;
                    328: {
                    329:        ipc_space_t space = current_space();
                    330:        vm_map_t map = current_map();
                    331:        msg_size_t send_size = msg->msg_size;
                    332:        ipc_port_t reply;
                    333:        ipc_pset_t pset;
                    334:        ipc_mqueue_t mqueue;
                    335:        ipc_kmsg_t kmsg;
                    336:        integer_t send_delta = send_size;
                    337:        mach_port_seqno_t seqno;
                    338:        mach_msg_return_t mr;
                    339: 
                    340:        /*
                    341:         *      Instead of using msg_send and msg_receive,
                    342:         *      we implement msg_rpc directly.  The difference
                    343:         *      is how the reply port is handled.  Instead of using
                    344:         *      ipc_mqueue_copyin, we save a reference for the reply
                    345:         *      port carried in the sent message.  For example,
                    346:         *      consider a rename kernel call which changes the name
                    347:         *      of the call's own reply port.  This is the behaviour
                    348:         *      of the Mach 2.5 msg_rpc_trap.
                    349:         */
                    350: 
                    351:        send_size = (send_size + 3) & ~3; /* round up */
                    352:        send_delta -= send_size;
                    353: 
                    354:        if (send_size > MSG_SIZE_MAX)
                    355:                return SEND_MSG_TOO_LARGE;
                    356: 
                    357:        mr = ipc_kmsg_get_from_kernel((mach_msg_header_t *) msg,
                    358:                                        MACH_MSG_OPTION_NONE,
                    359:                                        (mach_msg_size_t) send_size,
                    360:                                        send_delta,
                    361:                                        &kmsg);
                    362:        if (mr != MACH_MSG_SUCCESS)
                    363:                return msg_return_translate(mr);
                    364: 
                    365:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
                    366:        if (mr != MACH_MSG_SUCCESS) {
                    367:                ikm_free(kmsg);
                    368:                return msg_return_translate(mr);
                    369:        }
                    370:        
                    371:        reply = (ipc_port_t)kmsg->ikm_header.msgh_local_port;
                    372:        if (IP_VALID(reply)) {
                    373:                ipc_port_t      dest = (ipc_port_t)
                    374:                                        kmsg->ikm_header.msgh_remote_port;
                    375:                
                    376:                ipc_port_reference(reply);
                    377:                assert(IP_VALID(dest));
                    378:                
                    379:                ip_lock(dest);
                    380:                
                    381:                if (dest->ip_receiver == ipc_space_kernel) {
                    382:                        ipc_mqueue_t    mqueue;
                    383: 
                    384:                        assert(ip_active(dest));
                    385:                        ip_unlock(dest);
                    386:                        
                    387:                        kmsg = ipc_kobject_server(kmsg);
                    388:                        if (kmsg == IKM_NULL)
                    389:                                goto receive_reply;
                    390:                        
                    391:                        ip_lock(reply);
                    392:                        
                    393:                        if ((!ip_active(reply)) ||
                    394:                            (reply->ip_receiver != space) ||
                    395:                            (reply->ip_pset != IPS_NULL) ||
                    396:                            (rcv_size < (kmsg->ikm_header.msgh_size + 
                    397:                                                        kmsg->ikm_delta)))
                    398:                        {
                    399:                                ip_unlock(reply);
                    400:                                ipc_mqueue_send_always(kmsg);
                    401:                                goto receive_reply;
                    402:                        }
                    403: 
                    404:                        mqueue = &reply->ip_messages;
                    405:                        imq_lock(mqueue);
                    406:                        
                    407:                        if ((ipc_thread_queue_first(&mqueue->imq_threads)
                    408:                                != ITH_NULL) ||
                    409:                            (ipc_kmsg_queue_first(&mqueue->imq_messages)
                    410:                                != IKM_NULL))
                    411:                        {
                    412:                                imq_unlock(mqueue);
                    413:                                ip_unlock(reply);
                    414:                                ipc_mqueue_send_always(kmsg);
                    415:                                goto receive_reply;
                    416:                        }
                    417: 
                    418:                        assert(kmsg->ikm_marequest == IMAR_NULL);
                    419:                        assert(ipc_thread_queue_first(&reply->ip_blocked)
                    420:                                == ITH_NULL);
                    421: 
                    422:                        reply->ip_seqno++;
                    423:                        imq_unlock(mqueue);
                    424: 
                    425:                        ip_release(reply);
                    426:                        ip_unlock(reply);
                    427:                        
                    428:                        goto copyout_reply;
                    429:                }
                    430:                
                    431:                ip_unlock(dest);
                    432:        }
                    433: 
                    434:        if (option & SEND_NOTIFY) {
                    435:                panic("msg_rpc notify");
                    436:        } else
                    437:                do {
                    438:                        if (option & SEND_SWITCH)
                    439:                                mr = ipc_mqueue_send(kmsg,
                    440:                                                    ((option & SEND_TIMEOUT) ?
                    441:                                                    MACH_SEND_TIMEOUT :
                    442:                                                    MACH_MSG_OPTION_NONE) |
                    443:                                                    MACH_SEND_SWITCH,
                    444:                                                    (mach_msg_timeout_t)
                    445:                                                            send_timeout,
                    446:                                                    IMQ_NULL_CONTINUE);
                    447:                        else
                    448:                                mr = ipc_mqueue_send(kmsg,
                    449:                                                    ((option & SEND_TIMEOUT) ?
                    450:                                                    MACH_SEND_TIMEOUT :
                    451:                                                    MACH_MSG_OPTION_NONE),
                    452:                                                    (mach_msg_timeout_t)
                    453:                                                            send_timeout,
                    454:                                                    IMQ_NULL_CONTINUE);
                    455:                        if (mr == MACH_SEND_INTERRUPTED) {
                    456:                                while (thread_should_halt(current_thread()))
                    457:                                        thread_halt_self_with_continuation(
                    458:                                                        (void (*)(void)) 0);
                    459: 
                    460:                                if (option & SEND_INTERRUPT)
                    461:                                        break;
                    462:                        }
                    463:                } while (mr == MACH_SEND_INTERRUPTED);
                    464: 
                    465:        if (mr != MACH_MSG_SUCCESS) {
                    466:                ipc_kmsg_destroy(kmsg);
                    467:                if (IP_VALID(reply))
                    468:                        ipc_port_release(reply);
                    469:                return msg_return_translate(mr);
                    470:        }
                    471: 
                    472: receive_reply:
                    473:        if (!IP_VALID(reply))
                    474:                return RCV_INVALID_PORT;
                    475:        
                    476:        ip_lock(reply);
                    477:        if (reply->ip_receiver != space) {
                    478:                ip_release(reply);
                    479:                ip_check_unlock(reply);
                    480:                return RCV_INVALID_PORT;
                    481:        }
                    482: 
                    483:        assert(ip_active(reply));
                    484:        pset = reply->ip_pset;
                    485: 
                    486:        if (pset != IPS_NULL) {
                    487:                ips_lock(pset);
                    488:                if (ips_active(pset)) {
                    489:                        ips_unlock(pset);
                    490:                        ip_release(reply);
                    491:                        ip_unlock(reply);
                    492:                        return RCV_INVALID_PORT;
                    493:                }
                    494: 
                    495:                ipc_pset_remove(pset, reply);
                    496:                ips_check_unlock(pset);
                    497:                assert(reply->ip_pset == IPS_NULL);
                    498:        }
                    499: 
                    500:        mqueue = &reply->ip_messages;
                    501:        imq_lock(mqueue);
                    502:        ip_unlock(reply);
                    503: 
                    504:        mr = ipc_mqueue_receive(mqueue,
                    505:                                ((option & RCV_TIMEOUT) ?
                    506:                                MACH_RCV_TIMEOUT :
                    507:                                MACH_MSG_OPTION_NONE) |
                    508:                                MACH_RCV_OLD_FORMAT,
                    509:                                (option & RCV_LARGE) ?
                    510:                                (mach_msg_size_t) rcv_size :
                    511:                                MACH_MSG_SIZE_MAX,
                    512:                                (mach_msg_timeout_t) rcv_timeout,
                    513:                                FALSE, IMQ_NULL_CONTINUE,
                    514:                                &kmsg, &seqno, 0);
                    515:        /* mqueue is unlocked */
                    516:        ipc_port_release(reply);
                    517:        if (mr != MACH_MSG_SUCCESS) {
                    518:                if (mr == MACH_RCV_INTERRUPTED) {
                    519:                        while (thread_should_halt(current_thread()))
                    520:                                thread_halt_self_with_continuation(
                    521:                                                (void (*)(void)) 0);
                    522:                                
                    523:                        msg->msg_size = rcv_size;       /* XXX */
                    524:                        
                    525:                        if (!(option & RCV_INTERRUPT))
                    526:                                return msg_receive(msg, option, rcv_timeout);
                    527:                } else if (mr == MACH_RCV_TOO_LARGE) {
                    528:                        msg_size_t real_size =
                    529:                                (msg_size_t) (mach_msg_size_t) kmsg;
                    530: 
                    531:                        assert(real_size > rcv_size);
                    532:                        
                    533:                        msg->msg_size = real_size;
                    534:                }
                    535: 
                    536:                return msg_return_translate(mr);
                    537:        }
                    538:        
                    539:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
                    540:                assert(!(option & RCV_LARGE));
                    541:                
                    542:                ipc_kmsg_destroy(kmsg);
                    543:                return msg_return_translate(MACH_RCV_TOO_LARGE);
                    544:        }
                    545: 
                    546: copyout_reply:
                    547:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
                    548: 
                    549:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
                    550:        assert(mr == MACH_MSG_SUCCESS);
                    551: 
                    552:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
                    553:        ipc_kmsg_put_to_kernel((mach_msg_header_t *) msg, kmsg,
                    554:                                kmsg->ikm_header.msgh_size);
                    555:        return msg_return_translate(mr);
                    556: 
                    557: }
                    558: 
                    559: /*
                    560:  *     Routine:        mig_get_reply_port
                    561:  *     Purpose:
                    562:  *             Called by client side interfaces living in the kernel
                    563:  *             to get a reply port.  This port is used for
                    564:  *             mach_msg() calls which are kernel calls.
                    565:  */
                    566: 
                    567: mach_port_t
                    568: mig_get_reply_port()
                    569: {
                    570:        ipc_thread_t self = current_thread();
                    571: 
                    572:        if (self->ith_mig_reply == MACH_PORT_NULL)
                    573:                self->ith_mig_reply = mach_reply_port();
                    574: 
                    575:        return self->ith_mig_reply;
                    576: }
                    577: 
                    578: /*
                    579:  *     Routine:        mig_dealloc_reply_port
                    580:  *     Purpose:
                    581:  *             Called by client side interfaces to get rid of a reply port.
                    582:  *             Shouldn't ever be called inside the kernel, because
                    583:  *             kernel calls shouldn't prompt Mig to call it.
                    584:  */
                    585: 
                    586: void
                    587: mig_dealloc_reply_port()
                    588: {
                    589:        panic("mig_dealloc_reply_port");
                    590: }
                    591: 
                    592: /*
                    593:  * mig_strncpy.c - by Joshua Block
                    594:  *
                    595:  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
                    596:  * OUGHT to do:  Copies the (null terminated) string in src into dest, a 
                    597:  * buffer of length len.  Assures that the copy is still null terminated
                    598:  * and doesn't overflow the buffer, truncating the copy if necessary.
                    599:  *
                    600:  * Parameters:
                    601:  * 
                    602:  *     dest - Pointer to destination buffer.
                    603:  * 
                    604:  *     src - Pointer to source string.
                    605:  * 
                    606:  *     len - Length of destination buffer.
                    607:  */
                    608: vm_size_t mig_strncpy(
                    609:        char            *dest,
                    610:        const char      *src,
                    611:        vm_size_t       len)
                    612: {
                    613:     vm_size_t i;
                    614: 
                    615:     if (len <= 0)
                    616:        return 0;
                    617: 
                    618:     for (i=1; i<len; i++)
                    619:        if (! (*dest++ = *src++))
                    620:            return i;
                    621: 
                    622:     *dest = '\0';
                    623:     return i;
                    624: }
                    625: 
                    626: #if    0
                    627: 
                    628: #define        fast_send_right_lookup(name, port, abort)                       \
                    629: MACRO_BEGIN                                                            \
                    630:        register ipc_space_t space = current_space();                   \
                    631:        register ipc_entry_t entry;                                     \
                    632:        register mach_port_index_t index = MACH_PORT_INDEX(name);       \
                    633:                                                                        \
                    634:        is_read_lock(space);                                            \
                    635:        assert(space->is_active);                                       \
                    636:                                                                        \
                    637:        if ((index >= space->is_table_size) ||                          \
                    638:            (((entry = &space->is_table[index])->ie_bits &              \
                    639:              (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=                \
                    640:             (MACH_PORT_GEN(name) | MACH_PORT_TYPE_SEND))) {            \
                    641:                is_read_unlock(space);                                  \
                    642:                abort;                                                  \
                    643:        }                                                               \
                    644:                                                                        \
                    645:        port = (ipc_port_t) entry->ie_object;                           \
                    646:        assert(port != IP_NULL);                                        \
                    647:                                                                        \
                    648:        ip_lock(port);                                                  \
                    649:        /* can safely unlock space now that port is locked */           \
                    650:        is_read_unlock(space);                                          \
                    651: MACRO_END
                    652: 
                    653: thread_t
                    654: port_name_to_thread(name)
                    655:        mach_port_t name;
                    656: {
                    657:        register ipc_port_t port;
                    658: 
                    659:        fast_send_right_lookup(name, port, goto abort);
                    660:        /* port is locked */
                    661: 
                    662:        if (ip_active(port) &&
                    663:            (ip_kotype(port) == IKOT_THREAD)) {
                    664:                register thread_t thread;
                    665: 
                    666:                thread = (thread_t) port->ip_kobject;
                    667:                assert(thread != THREAD_NULL);
                    668: 
                    669:                /* thread referencing is a bit complicated,
                    670:                   so don't bother to expand inline */
                    671:                thread_reference(thread);
                    672:                ip_unlock(port);
                    673: 
                    674:                return thread;
                    675:        }
                    676: 
                    677:        ip_unlock(port);
                    678:        return THREAD_NULL;
                    679: 
                    680:     abort: {
                    681:        thread_t thread;
                    682:        ipc_port_t kern_port;
                    683:        kern_return_t kr;
                    684: 
                    685:        kr = ipc_object_copyin(current_space(), name,
                    686:                               MACH_MSG_TYPE_COPY_SEND,
                    687:                               (ipc_object_t *) &kern_port);
                    688:        if (kr != KERN_SUCCESS)
                    689:                return THREAD_NULL;
                    690: 
                    691:        thread = convert_port_to_thread(kern_port);
                    692:        if (IP_VALID(kern_port))
                    693:                ipc_port_release_send(kern_port);
                    694: 
                    695:        return thread;
                    696:     }
                    697: }
                    698: 
                    699: task_t
                    700: port_name_to_task(name)
                    701:        mach_port_t name;
                    702: {
                    703:        register ipc_port_t port;
                    704: 
                    705:        fast_send_right_lookup(name, port, goto abort);
                    706:        /* port is locked */
                    707: 
                    708:        if (ip_active(port) &&
                    709:            (ip_kotype(port) == IKOT_TASK)) {
                    710:                register task_t task;
                    711: 
                    712:                task = (task_t) port->ip_kobject;
                    713:                assert(task != TASK_NULL);
                    714: 
                    715:                task_lock(task);
                    716:                /* can safely unlock port now that task is locked */
                    717:                ip_unlock(port);
                    718: 
                    719:                task->ref_count++;
                    720:                task_unlock(task);
                    721: 
                    722:                return task;
                    723:        }
                    724: 
                    725:        ip_unlock(port);
                    726:        return TASK_NULL;
                    727: 
                    728:     abort: {
                    729:        task_t task;
                    730:        ipc_port_t kern_port;
                    731:        kern_return_t kr;
                    732: 
                    733:        kr = ipc_object_copyin(current_space(), name,
                    734:                               MACH_MSG_TYPE_COPY_SEND,
                    735:                               (ipc_object_t *) &kern_port);
                    736:        if (kr != KERN_SUCCESS)
                    737:                return TASK_NULL;
                    738: 
                    739:        task = convert_port_to_task(kern_port);
                    740:        if (IP_VALID(kern_port))
                    741:                ipc_port_release_send(kern_port);
                    742: 
                    743:        return task;
                    744:     }
                    745: }
                    746: 
                    747: vm_map_t
                    748: port_name_to_map(name)
                    749:        mach_port_t name;
                    750: {
                    751:        register ipc_port_t port;
                    752: 
                    753:        fast_send_right_lookup(name, port, goto abort);
                    754:        /* port is locked */
                    755: 
                    756:        if (ip_active(port) &&
                    757:            (ip_kotype(port) == IKOT_TASK)) {
                    758:                register vm_map_t map;
                    759: 
                    760:                map = ((task_t) port->ip_kobject)->map;
                    761:                assert(map != VM_MAP_NULL);
                    762: 
                    763:                simple_lock(&map->ref_lock);
                    764:                /* can safely unlock port now that map is locked */
                    765:                ip_unlock(port);
                    766: 
                    767:                map->ref_count++;
                    768:                simple_unlock(&map->ref_lock);
                    769: 
                    770:                return map;
                    771:        }
                    772: 
                    773:        ip_unlock(port);
                    774:        return VM_MAP_NULL;
                    775: 
                    776:     abort: {
                    777:        vm_map_t map;
                    778:        ipc_port_t kern_port;
                    779:        kern_return_t kr;
                    780: 
                    781:        kr = ipc_object_copyin(current_space(), name,
                    782:                               MACH_MSG_TYPE_COPY_SEND,
                    783:                               (ipc_object_t *) &kern_port);
                    784:        if (kr != KERN_SUCCESS)
                    785:                return VM_MAP_NULL;
                    786: 
                    787:        map = convert_port_to_map(kern_port);
                    788:        if (IP_VALID(kern_port))
                    789:                ipc_port_release_send(kern_port);
                    790: 
                    791:        return map;
                    792:     }
                    793: }
                    794: 
                    795: ipc_space_t
                    796: port_name_to_space(name)
                    797:        mach_port_t name;
                    798: {
                    799:        register ipc_port_t port;
                    800: 
                    801:        fast_send_right_lookup(name, port, goto abort);
                    802:        /* port is locked */
                    803: 
                    804:        if (ip_active(port) &&
                    805:            (ip_kotype(port) == IKOT_TASK)) {
                    806:                register ipc_space_t space;
                    807: 
                    808:                space = ((task_t) port->ip_kobject)->itk_space;
                    809:                assert(space != IS_NULL);
                    810: 
                    811:                simple_lock(&space->is_ref_lock_data);
                    812:                /* can safely unlock port now that space is locked */
                    813:                ip_unlock(port);
                    814: 
                    815:                space->is_references++;
                    816:                simple_unlock(&space->is_ref_lock_data);
                    817: 
                    818:                return space;
                    819:        }
                    820: 
                    821:        ip_unlock(port);
                    822:        return IS_NULL;
                    823: 
                    824:     abort: {
                    825:        ipc_space_t space;
                    826:        ipc_port_t kern_port;
                    827:        kern_return_t kr;
                    828: 
                    829:        kr = ipc_object_copyin(current_space(), name,
                    830:                               MACH_MSG_TYPE_COPY_SEND,
                    831:                               (ipc_object_t *) &kern_port);
                    832:        if (kr != KERN_SUCCESS)
                    833:                return IS_NULL;
                    834: 
                    835:        space = convert_port_to_space(kern_port);
                    836:        if (IP_VALID(kern_port))
                    837:                ipc_port_release_send(kern_port);
                    838: 
                    839:        return space;
                    840:     }
                    841: }
                    842: 
                    843: /*
                    844:  * Hack to translate a thread port to a thread pointer for calling
                    845:  * thread_get_state and thread_set_state.  This is only necessary
                    846:  * because the IPC message for these two operations overflows the
                    847:  * kernel stack.
                    848:  *
                    849:  * AARGH!
                    850:  */
                    851: 
                    852: kern_return_t thread_get_state_KERNEL(thread_port, flavor,
                    853:                        old_state, old_state_count)
                    854:        mach_port_t     thread_port;    /* port right for thread */
                    855:        int             flavor;
                    856:        thread_state_t  old_state;      /* pointer to OUT array */
                    857:        natural_t       *old_state_count;       /* IN/OUT */
                    858: {
                    859:        thread_t        thread;
                    860:        kern_return_t   result;
                    861: 
                    862:        thread = port_name_to_thread(thread_port);
                    863:        result = thread_get_state(thread, flavor, old_state, old_state_count);
                    864:        thread_deallocate(thread);
                    865: 
                    866:        return result;
                    867: }
                    868: 
                    869: kern_return_t thread_set_state_KERNEL(thread_port, flavor,
                    870:                        new_state, new_state_count)
                    871:        mach_port_t     thread_port;    /* port right for thread */
                    872:        int             flavor;
                    873:        thread_state_t  new_state;
                    874:        natural_t       new_state_count;
                    875: {
                    876:        thread_t        thread;
                    877:        kern_return_t   result;
                    878: 
                    879:        thread = port_name_to_thread(thread_port);
                    880:        result = thread_set_state(thread, flavor, new_state, new_state_count);
                    881:        thread_deallocate(thread);
                    882: 
                    883:        return result;
                    884: }
                    885: 
                    886: /*
                    887:  *     Things to keep in mind:
                    888:  *
                    889:  *     The idea here is to duplicate the semantics of the true kernel RPC.
                    890:  *     The destination port/object should be checked first, before anything
                    891:  *     that the user might notice (like ipc_object_copyin).  Return
                    892:  *     MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
                    893:  *     knows to fall back on an RPC.  For other return values, it won't
                    894:  *     retry with an RPC.  The retry might get a different (incorrect) rc.
                    895:  *     Return values are only set (and should only be set, with copyout)
                    896:  *     on successfull calls.
                    897:  */
                    898: 
                    899: kern_return_t syscall_vm_map(
                    900:                target_map,
                    901:                address, size, mask, anywhere,
                    902:                memory_object, offset,
                    903:                copy,
                    904:                cur_protection, max_protection, inheritance)
                    905:        mach_port_t     target_map;
                    906:        vm_offset_t     *address;
                    907:        vm_size_t       size;
                    908:        vm_offset_t     mask;
                    909:        boolean_t       anywhere;
                    910:        mach_port_t     memory_object;
                    911:        vm_offset_t     offset;
                    912:        boolean_t       copy;
                    913:        vm_prot_t       cur_protection;
                    914:        vm_prot_t       max_protection;
                    915:        vm_inherit_t    inheritance;
                    916: {
                    917:        vm_map_t                map;
                    918:        ipc_port_t              port;
                    919:        vm_offset_t             addr;
                    920:        kern_return_t           result;
                    921: 
                    922:        map = port_name_to_map(target_map);
                    923:        if (map == VM_MAP_NULL)
                    924:                return MACH_SEND_INTERRUPTED;
                    925: 
                    926:        if (MACH_PORT_VALID(memory_object)) {
                    927:                result = ipc_object_copyin(current_space(), memory_object,
                    928:                                           MACH_MSG_TYPE_COPY_SEND,
                    929:                                           (ipc_object_t *) &port);
                    930:                if (result != KERN_SUCCESS) {
                    931:                        vm_map_deallocate(map);
                    932:                        return result;
                    933:                }
                    934:        } else
                    935:                port = (ipc_port_t) memory_object;
                    936: 
                    937:        copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
                    938:        result = vm_map(map, &addr, size, mask, anywhere,
                    939:                        port, offset, copy,
                    940:                        cur_protection, max_protection, inheritance);
                    941:        if (result == KERN_SUCCESS)
                    942:                copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
                    943:        if (IP_VALID(port))
                    944:                ipc_port_release_send(port);
                    945:        vm_map_deallocate(map);
                    946: 
                    947:        return result;
                    948: }
                    949: 
                    950: kern_return_t syscall_vm_allocate(target_map, address, size, anywhere)
                    951:        mach_port_t             target_map;
                    952:        vm_offset_t             *address;
                    953:        vm_size_t               size;
                    954:        boolean_t               anywhere;
                    955: {
                    956:        vm_map_t                map;
                    957:        vm_offset_t             addr;
                    958:        kern_return_t           result;
                    959: 
                    960:        map = port_name_to_map(target_map);
                    961:        if (map == VM_MAP_NULL)
                    962:                return MACH_SEND_INTERRUPTED;
                    963: 
                    964:        copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
                    965:        result = vm_allocate(map, &addr, size, anywhere);
                    966:        if (result == KERN_SUCCESS)
                    967:                copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
                    968:        vm_map_deallocate(map);
                    969: 
                    970:        return result;
                    971: }
                    972: 
                    973: kern_return_t syscall_vm_deallocate(target_map, start, size)
                    974:        mach_port_t             target_map;
                    975:        vm_offset_t             start;
                    976:        vm_size_t               size;
                    977: {
                    978:        vm_map_t                map;
                    979:        kern_return_t           result;
                    980: 
                    981:        map = port_name_to_map(target_map);
                    982:        if (map == VM_MAP_NULL)
                    983:                return MACH_SEND_INTERRUPTED;
                    984: 
                    985:        result = vm_deallocate(map, start, size);
                    986:        vm_map_deallocate(map);
                    987: 
                    988:        return result;
                    989: }
                    990: 
                    991: kern_return_t syscall_task_create(parent_task, inherit_memory, child_task)
                    992:        mach_port_t     parent_task;
                    993:        boolean_t       inherit_memory;
                    994:        mach_port_t     *child_task;            /* OUT */
                    995: {
                    996:        task_t          t, c;
                    997:        ipc_port_t      port;
                    998:        mach_port_t     name;
                    999:        kern_return_t   result;
                   1000: 
                   1001:        t = port_name_to_task(parent_task);
                   1002:        if (t == TASK_NULL)
                   1003:                return MACH_SEND_INTERRUPTED;
                   1004: 
                   1005:        result = task_create(t, inherit_memory, &c);
                   1006:        if (result == KERN_SUCCESS) {
                   1007:                port = (ipc_port_t) convert_task_to_port(c);
                   1008:                /* always returns a name, even for non-success return codes */
                   1009:                (void) ipc_kmsg_copyout_object(current_space(),
                   1010:                                               (ipc_object_t) port,
                   1011:                                               MACH_MSG_TYPE_PORT_SEND, &name);
                   1012:                copyout((char *)&name, (char *)child_task,
                   1013:                        sizeof(mach_port_t));
                   1014:        }
                   1015:        task_deallocate(t);
                   1016: 
                   1017:        return result;
                   1018: }
                   1019: 
                   1020: kern_return_t syscall_task_terminate(task)
                   1021:        mach_port_t     task;
                   1022: {
                   1023:        task_t          t;
                   1024:        kern_return_t   result;
                   1025: 
                   1026:        t = port_name_to_task(task);
                   1027:        if (t == TASK_NULL)
                   1028:                return MACH_SEND_INTERRUPTED;
                   1029: 
                   1030:        result = task_terminate(t);
                   1031:        task_deallocate(t);
                   1032: 
                   1033:        return result;
                   1034: }
                   1035: 
                   1036: kern_return_t syscall_task_suspend(task)
                   1037:        mach_port_t     task;
                   1038: {
                   1039:        task_t          t;
                   1040:        kern_return_t   result;
                   1041: 
                   1042:        t = port_name_to_task(task);
                   1043:        if (t == TASK_NULL)
                   1044:                return MACH_SEND_INTERRUPTED;
                   1045: 
                   1046:        result = task_suspend(t);
                   1047:        task_deallocate(t);
                   1048: 
                   1049:        return result;
                   1050: }
                   1051: 
                   1052: kern_return_t syscall_task_set_special_port(task, which_port, port_name)
                   1053:        mach_port_t     task;
                   1054:        int             which_port;
                   1055:        mach_port_t     port_name;
                   1056: {
                   1057:        task_t          t;
                   1058:        ipc_port_t      port;
                   1059:        kern_return_t   result;
                   1060: 
                   1061:        t = port_name_to_task(task);
                   1062:        if (t == TASK_NULL)
                   1063:                return MACH_SEND_INTERRUPTED;
                   1064: 
                   1065:        if (MACH_PORT_VALID(port_name)) {
                   1066:                result = ipc_object_copyin(current_space(), port_name,
                   1067:                                           MACH_MSG_TYPE_COPY_SEND,
                   1068:                                           (ipc_object_t *) &port);
                   1069:                if (result != KERN_SUCCESS) {
                   1070:                        task_deallocate(t);
                   1071:                        return result;
                   1072:                }
                   1073:        } else
                   1074:                port = (ipc_port_t) port_name;
                   1075: 
                   1076:        result = task_set_special_port(t, which_port, port);
                   1077:        if ((result != KERN_SUCCESS) && IP_VALID(port))
                   1078:                ipc_port_release_send(port);
                   1079:        task_deallocate(t);
                   1080: 
                   1081:        return result;
                   1082: }
                   1083: 
                   1084: kern_return_t
                   1085: syscall_mach_port_allocate(task, right, namep)
                   1086:        mach_port_t task;
                   1087:        mach_port_right_t right;
                   1088:        mach_port_t *namep;
                   1089: {
                   1090:        ipc_space_t space;
                   1091:        mach_port_t name;
                   1092:        kern_return_t kr;
                   1093: 
                   1094:        space = port_name_to_space(task);
                   1095:        if (space == IS_NULL)
                   1096:                return MACH_SEND_INTERRUPTED;
                   1097: 
                   1098:        kr = mach_port_allocate(space, right, &name);
                   1099:        if (kr == KERN_SUCCESS)
                   1100:                copyout((char *)&name, (char *)namep, sizeof(mach_port_t));
                   1101:        is_release(space);
                   1102: 
                   1103:        return kr;
                   1104: }
                   1105: 
                   1106: kern_return_t
                   1107: syscall_mach_port_allocate_name(task, right, name)
                   1108:        mach_port_t task;
                   1109:        mach_port_right_t right;
                   1110:        mach_port_t name;
                   1111: {
                   1112:        ipc_space_t space;
                   1113:        kern_return_t kr;
                   1114: 
                   1115:        space = port_name_to_space(task);
                   1116:        if (space == IS_NULL)
                   1117:                return MACH_SEND_INTERRUPTED;
                   1118: 
                   1119:        kr = mach_port_allocate_name(space, right, name);
                   1120:        is_release(space);
                   1121: 
                   1122:        return kr;
                   1123: }
                   1124: 
                   1125: kern_return_t
                   1126: syscall_mach_port_deallocate(task, name)
                   1127:        mach_port_t task;
                   1128:        mach_port_t name;
                   1129: {
                   1130:        ipc_space_t space;
                   1131:        kern_return_t kr;
                   1132: 
                   1133:        space = port_name_to_space(task);
                   1134:        if (space == IS_NULL)
                   1135:                return MACH_SEND_INTERRUPTED;
                   1136: 
                   1137:        kr = mach_port_deallocate(space, name);
                   1138:        is_release(space);
                   1139: 
                   1140:        return kr;
                   1141: }
                   1142: 
                   1143: kern_return_t
                   1144: syscall_mach_port_insert_right(task, name, right, rightType)
                   1145:        mach_port_t task;
                   1146:        mach_port_t name;
                   1147:        mach_port_t right;
                   1148:        mach_msg_type_name_t rightType;
                   1149: {
                   1150:        ipc_space_t space;
                   1151:        ipc_object_t object;
                   1152:        mach_msg_type_name_t newtype;
                   1153:        kern_return_t kr;
                   1154: 
                   1155:        space = port_name_to_space(task);
                   1156:        if (space == IS_NULL)
                   1157:                return MACH_SEND_INTERRUPTED;
                   1158: 
                   1159:        if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
                   1160:                is_release(space);
                   1161:                return KERN_INVALID_VALUE;
                   1162:        }
                   1163: 
                   1164:        if (MACH_PORT_VALID(right)) {
                   1165:                kr = ipc_object_copyin(current_space(), right, rightType,
                   1166:                                       &object);
                   1167:                if (kr != KERN_SUCCESS) {
                   1168:                        is_release(space);
                   1169:                        return kr;
                   1170:                }
                   1171:        } else
                   1172:                object = (ipc_object_t) right;
                   1173:        newtype = ipc_object_copyin_type(rightType);
                   1174: 
                   1175:        kr = mach_port_insert_right(space, name, object, newtype);
                   1176:        if ((kr != KERN_SUCCESS) && IO_VALID(object))
                   1177:                ipc_object_destroy(object, newtype);
                   1178:        is_release(space);
                   1179: 
                   1180:        return kr;
                   1181: }
                   1182: 
                   1183: kern_return_t syscall_thread_depress_abort(thread)
                   1184:        mach_port_t     thread;
                   1185: {
                   1186:        thread_t        t;
                   1187:        kern_return_t   result;
                   1188: 
                   1189:        t = port_name_to_thread(thread);
                   1190:        if (t == THREAD_NULL)
                   1191:                return MACH_SEND_INTERRUPTED;
                   1192: 
                   1193:        result = thread_depress_abort(t);
                   1194:        thread_deallocate(t);
                   1195: 
                   1196:        return result;
                   1197: }
                   1198: 
                   1199: #endif

unix.superglobalmegacorp.com

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