Annotation of Gnu-Mach/kern/exception.c, revision 1.1.1.5

1.1.1.4   root        1: /*
1.1       root        2:  * Mach Operating System
                      3:  * Copyright (c) 1993,1992,1991,1990,1989,1988,1987 Carnegie Mellon University.
                      4:  * All Rights Reserved.
1.1.1.4   root        5:  *
1.1       root        6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
1.1.1.4   root       11:  *
1.1       root       12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.4   root       15:  *
1.1       root       16:  * Carnegie Mellon requests users of this software to return to
1.1.1.4   root       17:  *
1.1       root       18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
1.1.1.4   root       22:  *
1.1       root       23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: 
                     27: #include <mach/boolean.h>
                     28: #include <mach/kern_return.h>
                     29: #include <mach/message.h>
                     30: #include <mach/port.h>
                     31: #include <mach/mig_errors.h>
1.1.1.5 ! root       32: #include <machine/locore.h>
1.1       root       33: #include <ipc/port.h>
                     34: #include <ipc/ipc_entry.h>
1.1.1.5 ! root       35: #include <ipc/ipc_notify.h>
1.1       root       36: #include <ipc/ipc_object.h>
                     37: #include <ipc/ipc_space.h>
                     38: #include <ipc/ipc_port.h>
                     39: #include <ipc/ipc_pset.h>
                     40: #include <ipc/mach_msg.h>
                     41: #include <ipc/ipc_machdep.h>
                     42: #include <kern/counters.h>
1.1.1.5 ! root       43: #include <kern/debug.h>
1.1       root       44: #include <kern/ipc_tt.h>
                     45: #include <kern/task.h>
                     46: #include <kern/thread.h>
                     47: #include <kern/processor.h>
                     48: #include <kern/sched.h>
                     49: #include <kern/sched_prim.h>
                     50: #include <mach/machine/vm_types.h>
                     51: 
                     52: 
                     53: 
1.1.1.5 ! root       54: extern void exception() __attribute__ ((noreturn));
        !            55: extern void exception_try_task() __attribute__ ((noreturn));
        !            56: extern void exception_no_server() __attribute__ ((noreturn));
1.1       root       57: 
1.1.1.5 ! root       58: extern void exception_raise() __attribute__ ((noreturn));
1.1       root       59: extern kern_return_t exception_parse_reply();
1.1.1.5 ! root       60: extern void exception_raise_continue() __attribute__ ((noreturn));
        !            61: extern void exception_raise_continue_slow() __attribute__ ((noreturn));
        !            62: extern void exception_raise_continue_fast() __attribute__ ((noreturn));
1.1       root       63: 
                     64: #if    MACH_KDB
                     65: extern void thread_kdb_return();
                     66: extern void db_printf();
                     67: 
                     68: boolean_t debug_user_with_kdb = FALSE;
                     69: #endif /* MACH_KDB */
                     70: 
                     71: #ifdef KEEP_STACKS
                     72: /*
                     73:  *     Some obsolete architectures don't support kernel stack discarding
                     74:  *     or the thread_exception_return, thread_syscall_return continuations.
                     75:  *     For these architectures, the NOTREACHED comments below are incorrect.
                     76:  *     The exception function is expected to return.
                     77:  *     So the return statements along the slow paths are important.
                     78:  */
1.1.1.4   root       79: #endif /* KEEP_STACKS */
1.1       root       80: 
                     81: /*
                     82:  *     Routine:        exception
                     83:  *     Purpose:
                     84:  *             The current thread caught an exception.
                     85:  *             We make an up-call to the thread's exception server.
                     86:  *     Conditions:
                     87:  *             Nothing locked and no resources held.
                     88:  *             Called from an exception context, so
                     89:  *             thread_exception_return and thread_kdb_return
                     90:  *             are possible.
                     91:  *     Returns:
                     92:  *             Doesn't return.
                     93:  */
                     94: 
                     95: void
                     96: exception(_exception, code, subcode)
                     97:        integer_t _exception, code, subcode;
                     98: {
                     99:        register ipc_thread_t self = current_thread();
                    100:        register ipc_port_t exc_port;
                    101: 
                    102:        if (_exception == KERN_SUCCESS)
                    103:                panic("exception");
                    104: 
                    105:        /*
                    106:         *      Optimized version of retrieve_thread_exception.
                    107:         */
                    108: 
                    109:        ith_lock(self);
                    110:        assert(self->ith_self != IP_NULL);
                    111:        exc_port = self->ith_exception;
                    112:        if (!IP_VALID(exc_port)) {
                    113:                ith_unlock(self);
                    114:                exception_try_task(_exception, code, subcode);
                    115:                /*NOTREACHED*/
                    116:        }
                    117: 
                    118:        ip_lock(exc_port);
                    119:        ith_unlock(self);
                    120:        if (!ip_active(exc_port)) {
                    121:                ip_unlock(exc_port);
                    122:                exception_try_task(_exception, code, subcode);
                    123:                /*NOTREACHED*/
                    124:        }
                    125: 
                    126:        /*
                    127:         *      Make a naked send right for the exception port.
                    128:         */
                    129: 
                    130:        ip_reference(exc_port);
                    131:        exc_port->ip_srights++;
                    132:        ip_unlock(exc_port);
                    133: 
                    134:        /*
                    135:         *      If this exception port doesn't work,
                    136:         *      we will want to try the task's exception port.
                    137:         *      Indicate this by saving the exception state.
                    138:         */
                    139: 
                    140:        self->ith_exc = _exception;
                    141:        self->ith_exc_code = code;
                    142:        self->ith_exc_subcode = subcode;
                    143: 
                    144:        exception_raise(exc_port,
                    145:                        retrieve_thread_self_fast(self),
                    146:                        retrieve_task_self_fast(self->task),
                    147:                        _exception, code, subcode);
                    148:        /*NOTREACHED*/
                    149: }
                    150: 
                    151: /*
                    152:  *     Routine:        exception_try_task
                    153:  *     Purpose:
                    154:  *             The current thread caught an exception.
                    155:  *             We make an up-call to the task's exception server.
                    156:  *     Conditions:
                    157:  *             Nothing locked and no resources held.
                    158:  *             Called from an exception context, so
                    159:  *             thread_exception_return and thread_kdb_return
                    160:  *             are possible.
                    161:  *     Returns:
                    162:  *             Doesn't return.
                    163:  */
                    164: 
                    165: void
                    166: exception_try_task(_exception, code, subcode)
                    167:        integer_t _exception, code, subcode;
                    168: {
                    169:        ipc_thread_t self = current_thread();
                    170:        register task_t task = self->task;
                    171:        register ipc_port_t exc_port;
                    172: 
                    173:        /*
                    174:         *      Optimized version of retrieve_task_exception.
                    175:         */
                    176: 
                    177:        itk_lock(task);
                    178:        assert(task->itk_self != IP_NULL);
                    179:        exc_port = task->itk_exception;
                    180:        if (!IP_VALID(exc_port)) {
                    181:                itk_unlock(task);
                    182:                exception_no_server();
                    183:                /*NOTREACHED*/
                    184:        }
                    185: 
                    186:        ip_lock(exc_port);
                    187:        itk_unlock(task);
                    188:        if (!ip_active(exc_port)) {
                    189:                ip_unlock(exc_port);
                    190:                exception_no_server();
                    191:                /*NOTREACHED*/
                    192:        }
                    193: 
                    194:        /*
                    195:         *      Make a naked send right for the exception port.
                    196:         */
                    197: 
                    198:        ip_reference(exc_port);
                    199:        exc_port->ip_srights++;
                    200:        ip_unlock(exc_port);
                    201: 
                    202:        /*
                    203:         *      This is the thread's last chance.
                    204:         *      Clear the saved exception state.
                    205:         */
                    206: 
                    207:        self->ith_exc = KERN_SUCCESS;
                    208: 
                    209:        exception_raise(exc_port,
                    210:                        retrieve_thread_self_fast(self),
                    211:                        retrieve_task_self_fast(task),
                    212:                        _exception, code, subcode);
                    213:        /*NOTREACHED*/
                    214: }
                    215: 
                    216: /*
                    217:  *     Routine:        exception_no_server
                    218:  *     Purpose:
                    219:  *             The current thread took an exception,
                    220:  *             and no exception server took responsibility
                    221:  *             for the exception.  So good bye, charlie.
                    222:  *     Conditions:
                    223:  *             Nothing locked and no resources held.
                    224:  *             Called from an exception context, so
                    225:  *             thread_kdb_return is possible.
                    226:  *     Returns:
                    227:  *             Doesn't return.
                    228:  */
                    229: 
                    230: void
                    231: exception_no_server()
                    232: {
                    233:        register ipc_thread_t self = current_thread();
                    234: 
                    235:        /*
                    236:         *      If this thread is being terminated, cooperate.
                    237:         */
                    238: 
                    239:        while (thread_should_halt(self))
                    240:                thread_halt_self();
                    241: 
                    242: 
1.1.1.3   root      243: #if 0
1.1       root      244:        if (thread_suspend (self) == KERN_SUCCESS)
                    245:          thread_exception_return ();
1.1.1.2   root      246: #endif
1.1       root      247: 
                    248: #if    MACH_KDB
                    249:        if (debug_user_with_kdb) {
                    250:                /*
                    251:                 *      Debug the exception with kdb.
                    252:                 *      If kdb handles the exception,
                    253:                 *      then thread_kdb_return won't return.
                    254:                 */
                    255: 
                    256:                db_printf("No exception server, calling kdb...\n");
                    257:                thread_kdb_return();
                    258:        }
1.1.1.4   root      259: #endif /* MACH_KDB */
1.1       root      260: 
                    261:        /*
                    262:         *      All else failed; terminate task.
                    263:         */
                    264: 
                    265:        (void) task_terminate(self->task);
                    266:        thread_halt_self();
1.1.1.5 ! root      267:        panic("terminating the task didn't kill us");
1.1       root      268:        /*NOTREACHED*/
                    269: }
                    270: 
                    271: #define MACH_EXCEPTION_ID              2400    /* from mach/exc.defs */
                    272: #define MACH_EXCEPTION_REPLY_ID                (MACH_EXCEPTION_ID + 100)
                    273: 
                    274: struct mach_exception {
                    275:        mach_msg_header_t       Head;
                    276:        mach_msg_type_t         threadType;
                    277:        mach_port_t             thread;
                    278:        mach_msg_type_t         taskType;
                    279:        mach_port_t             task;
                    280:        mach_msg_type_t         exceptionType;
                    281:        integer_t               exception;
                    282:        mach_msg_type_t         codeType;
                    283:        integer_t               code;
                    284:        mach_msg_type_t         subcodeType;
                    285:        integer_t               subcode;
                    286: };
                    287: 
                    288: #define        INTEGER_T_SIZE_IN_BITS  (8 * sizeof(integer_t))
                    289: #define        INTEGER_T_TYPE          MACH_MSG_TYPE_INTEGER_T
                    290:                                        /* in mach/machine/vm_types.h */
                    291: 
                    292: mach_msg_type_t exc_port_proto = {
                    293:        /* msgt_name = */               MACH_MSG_TYPE_PORT_SEND,
                    294:        /* msgt_size = */               PORT_T_SIZE_IN_BITS,
                    295:        /* msgt_number = */             1,
                    296:        /* msgt_inline = */             TRUE,
                    297:        /* msgt_longform = */           FALSE,
                    298:        /* msgt_deallocate = */         FALSE,
                    299:        /* msgt_unused = */             0
                    300: };
                    301: 
                    302: mach_msg_type_t exc_code_proto = {
                    303:        /* msgt_name = */               INTEGER_T_TYPE,
                    304:        /* msgt_size = */               INTEGER_T_SIZE_IN_BITS,
                    305:        /* msgt_number = */             1,
                    306:        /* msgt_inline = */             TRUE,
                    307:        /* msgt_longform = */           FALSE,
                    308:        /* msgt_deallocate = */         FALSE,
                    309:        /* msgt_unused = */             0
                    310: };
                    311: 
                    312: /*
                    313:  *     Routine:        exception_raise
                    314:  *     Purpose:
                    315:  *             Make an exception_raise up-call to an exception server.
                    316:  *
                    317:  *             dest_port must be a valid naked send right.
                    318:  *             thread_port and task_port are naked send rights.
                    319:  *             All three are always consumed.
                    320:  *
                    321:  *             self->ith_exc, self->ith_exc_code, self->ith_exc_subcode
                    322:  *             must be appropriately initialized.
                    323:  *     Conditions:
                    324:  *             Nothing locked.  We are being called in an exception context,
                    325:  *             so thread_exception_return may be called.
                    326:  *     Returns:
                    327:  *             Doesn't return.
                    328:  */
                    329: 
                    330: int exception_raise_misses = 0;
                    331: 
                    332: void
                    333: exception_raise(dest_port, thread_port, task_port,
                    334:                _exception, code, subcode)
                    335:        ipc_port_t dest_port;
                    336:        ipc_port_t thread_port;
                    337:        ipc_port_t task_port;
                    338:        integer_t _exception, code, subcode;
                    339: {
                    340:        ipc_thread_t self = current_thread();
                    341:        ipc_thread_t receiver;
                    342:        ipc_port_t reply_port;
                    343:        ipc_mqueue_t dest_mqueue;
                    344:        ipc_mqueue_t reply_mqueue;
                    345:        ipc_kmsg_t kmsg;
                    346:        mach_msg_return_t mr;
                    347: 
                    348:        assert(IP_VALID(dest_port));
                    349: 
                    350:        /*
                    351:         *      We will eventually need a message buffer.
                    352:         *      Grab the buffer now, while nothing is locked.
                    353:         *      This buffer will get handed to the exception server,
                    354:         *      and it will give the buffer back with its reply.
                    355:         */
                    356: 
                    357:        kmsg = ikm_cache();
                    358:        if (kmsg != IKM_NULL) {
                    359:                ikm_cache() = IKM_NULL;
                    360:                ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
                    361:        } else {
                    362:                kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
                    363:                if (kmsg == IKM_NULL)
                    364:                        panic("exception_raise");
                    365:                ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
                    366:        }
                    367: 
                    368:        /*
                    369:         *      We need a reply port for the RPC.
                    370:         *      Check first for a cached port.
                    371:         */
                    372: 
                    373:        ith_lock(self);
                    374:        assert(self->ith_self != IP_NULL);
                    375: 
                    376:        reply_port = self->ith_rpc_reply;
                    377:        if (reply_port == IP_NULL) {
                    378:                ith_unlock(self);
                    379:                reply_port = ipc_port_alloc_reply();
                    380:                ith_lock(self);
                    381:                if ((reply_port == IP_NULL) ||
                    382:                    (self->ith_rpc_reply != IP_NULL))
                    383:                        panic("exception_raise");
                    384:                self->ith_rpc_reply = reply_port;
                    385:        }
                    386: 
                    387:        ip_lock(reply_port);
                    388:        assert(ip_active(reply_port));
                    389:        ith_unlock(self);
                    390: 
                    391:        /*
                    392:         *      Make a naked send-once right for the reply port,
                    393:         *      to hand to the exception server.
                    394:         *      Make an extra reference for the reply port,
                    395:         *      to receive on.  This protects us against
                    396:         *      mach_msg_abort_rpc.
                    397:         */
                    398: 
                    399:        reply_port->ip_sorights++;
                    400:        ip_reference(reply_port);
                    401: 
                    402:        ip_reference(reply_port);
                    403:        self->ith_port = reply_port;
                    404: 
                    405:        reply_mqueue = &reply_port->ip_messages;
                    406:        imq_lock(reply_mqueue);
                    407:        assert(ipc_kmsg_queue_empty(&reply_mqueue->imq_messages));
                    408:        ip_unlock(reply_port);
                    409: 
                    410:        /*
                    411:         *      Make sure we can queue to the destination port.
                    412:         */
                    413: 
                    414:        if (!ip_lock_try(dest_port)) {
                    415:                imq_unlock(reply_mqueue);
                    416:                goto slow_exception_raise;
                    417:        }
                    418: 
                    419:        if (!ip_active(dest_port) ||
                    420:            (dest_port->ip_receiver == ipc_space_kernel)) {
                    421:                imq_unlock(reply_mqueue);
                    422:                ip_unlock(dest_port);
                    423:                goto slow_exception_raise;
                    424:        }
                    425: 
                    426:        /*
                    427:         *      Find the destination message queue.
                    428:         */
                    429: 
                    430:     {
                    431:        register ipc_pset_t dest_pset;
                    432: 
                    433:        dest_pset = dest_port->ip_pset;
                    434:        if (dest_pset == IPS_NULL)
                    435:                dest_mqueue = &dest_port->ip_messages;
                    436:        else
                    437:                dest_mqueue = &dest_pset->ips_messages;
                    438:     }
                    439: 
                    440:        if (!imq_lock_try(dest_mqueue)) {
                    441:                imq_unlock(reply_mqueue);
                    442:                ip_unlock(dest_port);
                    443:                goto slow_exception_raise;
                    444:        }
                    445: 
                    446:        /*
                    447:         *      Safe to unlock dest_port, because we hold
                    448:         *      dest_mqueue locked.  We never bother changing
                    449:         *      dest_port->ip_msgcount.
                    450:         */
                    451: 
                    452:        ip_unlock(dest_port);
                    453: 
                    454:        receiver = ipc_thread_queue_first(&dest_mqueue->imq_threads);
                    455:        if ((receiver == ITH_NULL) ||
                    456:            !((receiver->swap_func == (void (*)()) mach_msg_continue) ||
                    457:              ((receiver->swap_func ==
                    458:                                (void (*)()) mach_msg_receive_continue) &&
                    459:               (sizeof(struct mach_exception) <= receiver->ith_msize) &&
                    460:               ((receiver->ith_option & MACH_RCV_NOTIFY) == 0))) ||
                    461:            !thread_handoff(self, exception_raise_continue, receiver)) {
                    462:                imq_unlock(reply_mqueue);
                    463:                imq_unlock(dest_mqueue);
                    464:                goto slow_exception_raise;
                    465:        }
                    466:        counter(c_exception_raise_block++);
                    467: 
                    468:        assert(current_thread() == receiver);
                    469: 
                    470:        /*
                    471:         *      We need to finish preparing self for its
                    472:         *      time asleep in reply_mqueue.  self is left
                    473:         *      holding the extra ref for reply_port.
                    474:         */
                    475: 
                    476:        ipc_thread_enqueue_macro(&reply_mqueue->imq_threads, self);
                    477:        self->ith_state = MACH_RCV_IN_PROGRESS;
                    478:        self->ith_msize = MACH_MSG_SIZE_MAX;
                    479:        imq_unlock(reply_mqueue);
                    480: 
                    481:        /*
                    482:         *      Finish extracting receiver from dest_mqueue.
                    483:         */
                    484: 
                    485:        ipc_thread_rmqueue_first_macro(
                    486:                &dest_mqueue->imq_threads, receiver);
                    487:        imq_unlock(dest_mqueue);
                    488: 
                    489:        /*
                    490:         *      Release the receiver's reference for his object.
                    491:         */
                    492:     {
                    493:        register ipc_object_t object = receiver->ith_object;
                    494: 
                    495:        io_lock(object);
                    496:        io_release(object);
                    497:        io_check_unlock(object);
                    498:     }
                    499: 
                    500:     {
                    501:        register struct mach_exception *exc =
                    502:                        (struct mach_exception *) &kmsg->ikm_header;
                    503:        ipc_space_t space = receiver->task->itk_space;
                    504: 
                    505:        /*
                    506:         *      We are running as the receiver now.  We hold
                    507:         *      the following resources, which must be consumed:
                    508:         *              kmsg, send-once right for reply_port
                    509:         *              send rights for dest_port, thread_port, task_port
                    510:         *      Synthesize a kmsg for copyout to the receiver.
                    511:         */
                    512: 
                    513:        exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
                    514:                                              MACH_MSG_TYPE_PORT_SEND) |
                    515:                               MACH_MSGH_BITS_COMPLEX);
                    516:        exc->Head.msgh_size = sizeof *exc;
                    517:      /* exc->Head.msgh_remote_port later */
                    518:      /* exc->Head.msgh_local_port later */
                    519:        exc->Head.msgh_seqno = 0;
                    520:        exc->Head.msgh_id = MACH_EXCEPTION_ID;
                    521:        exc->threadType = exc_port_proto;
                    522:      /* exc->thread later */
                    523:        exc->taskType = exc_port_proto;
                    524:      /* exc->task later */
                    525:        exc->exceptionType = exc_code_proto;
                    526:        exc->exception = _exception;
                    527:        exc->codeType = exc_code_proto;
                    528:        exc->code = code;
                    529:        exc->subcodeType = exc_code_proto;
                    530:        exc->subcode = subcode;
                    531: 
                    532:        /*
                    533:         *      Check that the receiver can handle the message.
                    534:         */
                    535: 
                    536:        if (receiver->ith_rcv_size < sizeof(struct mach_exception)) {
                    537:                /*
                    538:                 *      ipc_kmsg_destroy is a handy way to consume
                    539:                 *      the resources we hold, but it requires setup.
                    540:                 */
                    541: 
                    542:                exc->Head.msgh_bits =
                    543:                        (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    544:                                        MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    545:                         MACH_MSGH_BITS_COMPLEX);
                    546:                exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    547:                exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    548:                exc->thread = (mach_port_t) thread_port;
                    549:                exc->task = (mach_port_t) task_port;
                    550: 
                    551:                ipc_kmsg_destroy(kmsg);
                    552:                thread_syscall_return(MACH_RCV_TOO_LARGE);
                    553:                /*NOTREACHED*/
                    554:        }
                    555: 
                    556:        is_write_lock(space);
                    557:        assert(space->is_active);
                    558: 
                    559:        /*
                    560:         *      To do an atomic copyout, need simultaneous
                    561:         *      locks on both ports and the space.
                    562:         */
                    563: 
                    564:        ip_lock(dest_port);
                    565:        if (!ip_active(dest_port) ||
                    566:            !ip_lock_try(reply_port)) {
                    567:            abort_copyout:
                    568:                ip_unlock(dest_port);
                    569:                is_write_unlock(space);
                    570: 
                    571:                /*
                    572:                 *      Oh well, we have to do the header the slow way.
                    573:                 *      First make it look like it's in-transit.
                    574:                 */
                    575: 
                    576:                exc->Head.msgh_bits =
                    577:                        (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    578:                                        MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    579:                         MACH_MSGH_BITS_COMPLEX);
                    580:                exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    581:                exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    582: 
                    583:                mr = ipc_kmsg_copyout_header(&exc->Head, space,
                    584:                                             MACH_PORT_NULL);
                    585:                if (mr == MACH_MSG_SUCCESS)
                    586:                        goto copyout_body;
                    587: 
                    588:                /*
                    589:                 *      Ack!  Prepare for ipc_kmsg_copyout_dest.
                    590:                 *      It will consume thread_port and task_port.
                    591:                 */
                    592: 
                    593:                exc->thread = (mach_port_t) thread_port;
                    594:                exc->task = (mach_port_t) task_port;
                    595: 
                    596:                ipc_kmsg_copyout_dest(kmsg, space);
                    597:                (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
                    598:                                    sizeof(mach_msg_header_t));
                    599:                thread_syscall_return(mr);
                    600:                /*NOTREACHED*/
                    601:        }
                    602: 
                    603:        if (!ip_active(reply_port)) {
                    604:                ip_unlock(reply_port);
                    605:                goto abort_copyout;
                    606:        }
                    607: 
                    608:        assert(reply_port->ip_sorights > 0);
                    609:        ip_unlock(reply_port);
                    610: 
                    611:     {
                    612:        register ipc_entry_t table;
                    613:        register ipc_entry_t entry;
                    614:        register mach_port_index_t index;
                    615: 
                    616:        /* optimized ipc_entry_get */
                    617: 
                    618:        table = space->is_table;
                    619:        index = table->ie_next;
                    620: 
                    621:        if (index == 0)
                    622:                goto abort_copyout;
                    623: 
                    624:        entry = &table[index];
                    625:        table->ie_next = entry->ie_next;
                    626:        entry->ie_request = 0;
                    627: 
                    628:     {
                    629:        register mach_port_gen_t gen;
                    630: 
                    631:        assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
                    632:        gen = entry->ie_bits + IE_BITS_GEN_ONE;
                    633: 
                    634:        exc->Head.msgh_remote_port = MACH_PORT_MAKE(index, gen);
                    635: 
                    636:        /* optimized ipc_right_copyout */
                    637: 
                    638:        entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
                    639:     }
                    640: 
                    641:        entry->ie_object = (ipc_object_t) reply_port;
                    642:        is_write_unlock(space);
                    643:     }
                    644: 
                    645:        /* optimized ipc_object_copyout_dest */
                    646: 
                    647:        assert(dest_port->ip_srights > 0);
                    648:        ip_release(dest_port);
                    649: 
                    650:        exc->Head.msgh_local_port =
                    651:                ((dest_port->ip_receiver == space) ?
                    652:                 dest_port->ip_receiver_name : MACH_PORT_NULL);
                    653: 
                    654:        if ((--dest_port->ip_srights == 0) &&
                    655:            (dest_port->ip_nsrequest != IP_NULL)) {
                    656:                ipc_port_t nsrequest;
                    657:                mach_port_mscount_t mscount;
                    658: 
                    659:                /* a rather rare case */
                    660: 
                    661:                nsrequest = dest_port->ip_nsrequest;
                    662:                mscount = dest_port->ip_mscount;
                    663:                dest_port->ip_nsrequest = IP_NULL;
                    664:                ip_unlock(dest_port);
                    665: 
                    666:                ipc_notify_no_senders(nsrequest, mscount);
                    667:        } else
                    668:                ip_unlock(dest_port);
                    669: 
                    670:     copyout_body:
                    671:        /*
                    672:         *      Optimized version of ipc_kmsg_copyout_body,
                    673:         *      to handle the two ports in the body.
                    674:         */
                    675: 
                    676:        mr = (ipc_kmsg_copyout_object(space, (ipc_object_t) thread_port,
                    677:                                      MACH_MSG_TYPE_PORT_SEND, &exc->thread) |
                    678:              ipc_kmsg_copyout_object(space, (ipc_object_t) task_port,
                    679:                                      MACH_MSG_TYPE_PORT_SEND, &exc->task));
                    680:        if (mr != MACH_MSG_SUCCESS) {
                    681:                (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
                    682:                                    kmsg->ikm_header.msgh_size);
                    683:                thread_syscall_return(mr | MACH_RCV_BODY_ERROR);
                    684:                /*NOTREACHED*/
                    685:        }
                    686:     }
                    687: 
                    688:        /*
                    689:         *      Optimized version of ipc_kmsg_put.
                    690:         *      We must check ikm_cache after copyoutmsg.
                    691:         */
                    692: 
                    693:        ikm_check_initialized(kmsg, kmsg->ikm_size);
                    694:        assert(kmsg->ikm_size == IKM_SAVED_KMSG_SIZE);
                    695: 
1.1.1.5 ! root      696:        if (copyoutmsg(&kmsg->ikm_header, receiver->ith_msg,
1.1       root      697:                       sizeof(struct mach_exception)) ||
                    698:            (ikm_cache() != IKM_NULL)) {
                    699:                mr = ipc_kmsg_put(receiver->ith_msg, kmsg,
                    700:                                  kmsg->ikm_header.msgh_size);
                    701:                thread_syscall_return(mr);
                    702:                /*NOTREACHED*/
                    703:        }
                    704: 
                    705:        ikm_cache() = kmsg;
                    706:        thread_syscall_return(MACH_MSG_SUCCESS);
                    707:        /*NOTREACHED*/
                    708: #ifndef        __GNUC__
                    709:        return; /* help for the compiler */
                    710: #endif
                    711: 
                    712:     slow_exception_raise: {
                    713:        register struct mach_exception *exc =
                    714:                        (struct mach_exception *) &kmsg->ikm_header;
                    715:        ipc_kmsg_t reply_kmsg;
                    716:        mach_port_seqno_t reply_seqno;
                    717: 
                    718:        exception_raise_misses++;
                    719: 
                    720:        /*
                    721:         *      We hold the following resources, which must be consumed:
                    722:         *              kmsg, send-once right and ref for reply_port
                    723:         *              send rights for dest_port, thread_port, task_port
                    724:         *      Synthesize a kmsg to send.
                    725:         */
                    726: 
                    727:        exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    728:                                              MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    729:                               MACH_MSGH_BITS_COMPLEX);
                    730:        exc->Head.msgh_size = sizeof *exc;
                    731:        exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    732:        exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    733:        exc->Head.msgh_seqno = 0;
                    734:        exc->Head.msgh_id = MACH_EXCEPTION_ID;
                    735:        exc->threadType = exc_port_proto;
                    736:        exc->thread = (mach_port_t) thread_port;
                    737:        exc->taskType = exc_port_proto;
                    738:        exc->task = (mach_port_t) task_port;
                    739:        exc->exceptionType = exc_code_proto;
                    740:        exc->exception = _exception;
                    741:        exc->codeType = exc_code_proto;
                    742:        exc->code = code;
                    743:        exc->subcodeType = exc_code_proto;
                    744:        exc->subcode = subcode;
                    745: 
                    746:        ipc_mqueue_send_always(kmsg);
                    747: 
                    748:        /*
                    749:         *      We are left with a ref for reply_port,
                    750:         *      which we use to receive the reply message.
                    751:         */
                    752: 
                    753:        ip_lock(reply_port);
                    754:        if (!ip_active(reply_port)) {
                    755:                ip_unlock(reply_port);
                    756:                exception_raise_continue_slow(MACH_RCV_PORT_DIED, IKM_NULL, /*dummy*/0);
                    757:                /*NOTREACHED*/
                    758:        }
                    759: 
                    760:        imq_lock(reply_mqueue);
                    761:        ip_unlock(reply_port);
                    762: 
                    763:        mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    764:                                MACH_MSG_SIZE_MAX,
                    765:                                MACH_MSG_TIMEOUT_NONE,
                    766:                                FALSE, exception_raise_continue,
                    767:                                &reply_kmsg, &reply_seqno);
                    768:        /* reply_mqueue is unlocked */
                    769: 
                    770:        exception_raise_continue_slow(mr, reply_kmsg, reply_seqno);
                    771:        /*NOTREACHED*/
                    772:     }
                    773: }
                    774: 
                    775: mach_msg_type_t exc_RetCode_proto = {
                    776:        /* msgt_name = */               MACH_MSG_TYPE_INTEGER_32,
                    777:        /* msgt_size = */               32,
                    778:        /* msgt_number = */             1,
                    779:        /* msgt_inline = */             TRUE,
                    780:        /* msgt_longform = */           FALSE,
                    781:        /* msgt_deallocate = */         FALSE,
                    782:        /* msgt_unused = */             0
                    783: };
                    784: 
                    785: /*
                    786:  *     Routine:        exception_parse_reply
                    787:  *     Purpose:
                    788:  *             Parse and consume an exception reply message.
                    789:  *     Conditions:
                    790:  *             The destination port right has already been consumed.
                    791:  *             The message buffer and anything else in it is consumed.
                    792:  *     Returns:
                    793:  *             The reply return code.
                    794:  */
                    795: 
                    796: kern_return_t
                    797: exception_parse_reply(kmsg)
                    798:        ipc_kmsg_t kmsg;
                    799: {
                    800:        register mig_reply_header_t *msg =
                    801:                        (mig_reply_header_t *) &kmsg->ikm_header;
                    802:        kern_return_t kr;
                    803: 
                    804:        if ((msg->Head.msgh_bits !=
                    805:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0)) ||
                    806:            (msg->Head.msgh_size != sizeof *msg) ||
                    807:            (msg->Head.msgh_id != MACH_EXCEPTION_REPLY_ID) ||
                    808:            (* (int *) &msg->RetCodeType != * (int *) &exc_RetCode_proto)) {
                    809:                /*
                    810:                 *      Bozo user sent us a misformatted reply.
                    811:                 */
                    812: 
                    813:                kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    814:                ipc_kmsg_destroy(kmsg);
                    815:                return MIG_REPLY_MISMATCH;
                    816:        }
                    817: 
                    818:        kr = msg->RetCode;
                    819: 
                    820:        if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
                    821:            (ikm_cache() == IKM_NULL))
                    822:                ikm_cache() = kmsg;
                    823:        else
                    824:                ikm_free(kmsg);
                    825: 
                    826:        return kr;
                    827: }
                    828: 
                    829: /*
                    830:  *     Routine:        exception_raise_continue
                    831:  *     Purpose:
                    832:  *             Continue after blocking for an exception.
                    833:  *     Conditions:
                    834:  *             Nothing locked.  We are running on a new kernel stack,
                    835:  *             with the exception state saved in the thread.  From here
                    836:  *             control goes back to user space.
                    837:  *     Returns:
                    838:  *             Doesn't return.
                    839:  */
                    840: 
                    841: void
                    842: exception_raise_continue()
                    843: {
                    844:        ipc_thread_t self = current_thread();
                    845:        ipc_port_t reply_port = self->ith_port;
                    846:        ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
                    847:        ipc_kmsg_t kmsg;
                    848:        mach_port_seqno_t seqno;
                    849:        mach_msg_return_t mr;
                    850: 
                    851:        mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    852:                                MACH_MSG_SIZE_MAX,
                    853:                                MACH_MSG_TIMEOUT_NONE,
                    854:                                TRUE, exception_raise_continue,
                    855:                                &kmsg, &seqno);
                    856:        /* reply_mqueue is unlocked */
                    857: 
                    858:        exception_raise_continue_slow(mr, kmsg, seqno);
                    859:        /*NOTREACHED*/
                    860: }
                    861: 
                    862: /*
                    863:  *     Routine:        exception_raise_continue_slow
                    864:  *     Purpose:
                    865:  *             Continue after finishing an ipc_mqueue_receive
                    866:  *             for an exception reply message.
                    867:  *     Conditions:
                    868:  *             Nothing locked.  We hold a ref for reply_port.
                    869:  *     Returns:
                    870:  *             Doesn't return.
                    871:  */
                    872: 
                    873: void
                    874: exception_raise_continue_slow(mr, kmsg, seqno)
                    875:        mach_msg_return_t mr;
                    876:        ipc_kmsg_t kmsg;
                    877:        mach_port_seqno_t seqno;
                    878: {
                    879:        ipc_thread_t self = current_thread();
                    880:        ipc_port_t reply_port = self->ith_port;
                    881:        ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
                    882: 
                    883:        while (mr == MACH_RCV_INTERRUPTED) {
                    884:                /*
                    885:                 *      Somebody is trying to force this thread
                    886:                 *      to a clean point.  We must cooperate
                    887:                 *      and then resume the receive.
                    888:                 */
                    889: 
                    890:                while (thread_should_halt(self)) {
                    891:                        /* don't terminate while holding a reference */
                    892:                        if (self->ast & AST_TERMINATE)
                    893:                                ipc_port_release(reply_port);
                    894:                        thread_halt_self();
                    895:                }
                    896: 
                    897:                ip_lock(reply_port);
                    898:                if (!ip_active(reply_port)) {
                    899:                        ip_unlock(reply_port);
                    900:                        mr = MACH_RCV_PORT_DIED;
                    901:                        break;
                    902:                }
                    903: 
                    904:                imq_lock(reply_mqueue);
                    905:                ip_unlock(reply_port);
                    906: 
                    907:                mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    908:                                        MACH_MSG_SIZE_MAX,
                    909:                                        MACH_MSG_TIMEOUT_NONE,
                    910:                                        FALSE, exception_raise_continue,
                    911:                                        &kmsg, &seqno);
                    912:                /* reply_mqueue is unlocked */
                    913:        }
                    914:        ipc_port_release(reply_port);
                    915: 
                    916:        assert((mr == MACH_MSG_SUCCESS) ||
                    917:               (mr == MACH_RCV_PORT_DIED));
                    918: 
                    919:        if (mr == MACH_MSG_SUCCESS) {
                    920:                /*
                    921:                 *      Consume the reply message.
                    922:                 */
                    923: 
                    924:                ipc_port_release_sonce(reply_port);
                    925:                mr = exception_parse_reply(kmsg);
                    926:        }
                    927: 
                    928:        if ((mr == KERN_SUCCESS) ||
                    929:            (mr == MACH_RCV_PORT_DIED)) {
                    930:                thread_exception_return();
                    931:                /*NOTREACHED*/
                    932:        }
                    933: 
                    934:        if (self->ith_exc != KERN_SUCCESS) {
                    935:                exception_try_task(self->ith_exc,
                    936:                                   self->ith_exc_code,
                    937:                                   self->ith_exc_subcode);
                    938:                /*NOTREACHED*/
                    939:        }
                    940: 
                    941:        exception_no_server();
                    942:        /*NOTREACHED*/
                    943: }
                    944: 
                    945: /*
                    946:  *     Routine:        exception_raise_continue_fast
                    947:  *     Purpose:
                    948:  *             Special-purpose fast continuation for exceptions.
                    949:  *     Conditions:
                    950:  *             reply_port is locked and alive.
                    951:  *             kmsg is our reply message.
                    952:  *     Returns:
                    953:  *             Doesn't return.
                    954:  */
                    955: 
                    956: void
                    957: exception_raise_continue_fast(reply_port, kmsg)
                    958:        ipc_port_t reply_port;
                    959:        ipc_kmsg_t kmsg;
                    960: {
                    961:        ipc_thread_t self = current_thread();
                    962:        kern_return_t kr;
                    963: 
                    964:        assert(ip_active(reply_port));
                    965:        assert(reply_port == self->ith_port);
                    966:        assert(reply_port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
                    967:        assert(MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
                    968:                                                MACH_MSG_TYPE_PORT_SEND_ONCE);
                    969: 
                    970:        /*
                    971:         *      Release the send-once right (from the message header)
                    972:         *      and the saved reference (from self->ith_port).
                    973:         */
                    974: 
                    975:        reply_port->ip_sorights--;
                    976:        ip_release(reply_port);
                    977:        ip_release(reply_port);
                    978:        ip_unlock(reply_port);
                    979: 
                    980:        /*
                    981:         *      Consume the reply message.
                    982:         */
                    983: 
                    984:        kr = exception_parse_reply(kmsg);
                    985:        if (kr == KERN_SUCCESS) {
                    986:                thread_exception_return();
                    987:                /*NOTREACHED*/
                    988:        }
                    989: 
                    990:        if (self->ith_exc != KERN_SUCCESS) {
                    991:                exception_try_task(self->ith_exc,
                    992:                                   self->ith_exc_code,
                    993:                                   self->ith_exc_subcode);
                    994:                /*NOTREACHED*/
                    995:        }
                    996: 
                    997:        exception_no_server();
                    998:        /*NOTREACHED*/
                    999: }

unix.superglobalmegacorp.com

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