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