|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.