2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 * Mach Operating System
28 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
29 * All Rights Reserved.
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
41 * Carnegie Mellon requests users of this software to return to
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
56 #include <mach/mach_types.h>
57 #include <mach/boolean.h>
58 #include <mach/kern_return.h>
59 #include <mach/message.h>
60 #include <mach/port.h>
61 #include <mach/mig_errors.h>
62 #include <mach/task.h>
63 #include <mach/thread_status.h>
64 #include <mach/exception_types.h>
66 #include <ipc/ipc_entry.h>
67 #include <ipc/ipc_object.h>
68 #include <ipc/ipc_notify.h>
69 #include <ipc/ipc_space.h>
70 #include <ipc/ipc_pset.h>
71 #include <ipc/ipc_machdep.h>
72 #include <kern/counters.h>
73 #include <kern/ipc_tt.h>
74 #include <kern/task.h>
75 #include <kern/thread.h>
76 #include <kern/processor.h>
77 #include <kern/sched.h>
78 #include <kern/sched_prim.h>
79 #include <kern/host.h>
80 #include <kern/misc_protos.h>
85 #include <ddb/db_trap.h>
90 #include <ddb/db_output.h>
92 #if iPSC386 || iPSC860
93 boolean_t debug_user_with_kdb
= TRUE
;
95 boolean_t debug_user_with_kdb
= FALSE
;
100 unsigned long c_thr_exc_raise
= 0;
101 unsigned long c_thr_exc_raise_state
= 0;
102 unsigned long c_thr_exc_raise_state_id
= 0;
103 unsigned long c_tsk_exc_raise
= 0;
104 unsigned long c_tsk_exc_raise_state
= 0;
105 unsigned long c_tsk_exc_raise_state_id
= 0;
107 /* forward declarations */
108 void exception_deliver(
109 exception_type_t exception
,
110 exception_data_t code
,
111 mach_msg_type_number_t codeCnt
,
112 struct exception_action
*excp
,
116 kern_return_t
bsd_exception(
117 exception_type_t exception
,
118 exception_data_t code
,
119 mach_msg_type_number_t codeCnt
);
120 #endif /* MACH_BSD */
123 * Routine: exception_deliver
125 * Make an upcall to the exception server provided.
127 * Nothing locked and no resources held.
128 * Called from an exception context, so
129 * thread_exception_return and thread_kdb_return
132 * If the exception was not handled by this handler
136 exception_type_t exception
,
137 exception_data_t code
,
138 mach_msg_type_number_t codeCnt
,
139 struct exception_action
*excp
,
142 thread_t self
= current_thread();
149 * Save work if we are terminating.
150 * Just go back to our AST handler.
153 thread_exception_return();
156 * Snapshot the exception action data under lock for consistency.
157 * Hold a reference to the port over the exception_raise_* calls
158 * so it can't be destroyed. This seems like overkill, but keeps
159 * the port from disappearing between now and when
160 * ipc_object_copyin_from_kernel is finally called.
163 exc_port
= excp
->port
;
164 if (!IP_VALID(exc_port
)) {
169 if (!ip_active(exc_port
)) {
174 ip_reference(exc_port
);
175 exc_port
->ip_srights
++;
178 flavor
= excp
->flavor
;
179 behavior
= excp
->behavior
;
183 case EXCEPTION_STATE
: {
184 mach_msg_type_number_t state_cnt
;
185 thread_state_data_t state
;
187 c_thr_exc_raise_state
++;
188 state_cnt
= _MachineStateCount
[flavor
];
189 kr
= thread_getstatus(self
, flavor
,
190 (thread_state_t
)state
,
192 if (kr
== KERN_SUCCESS
) {
193 kr
= exception_raise_state(exc_port
, exception
,
198 if (kr
== MACH_MSG_SUCCESS
)
199 kr
= thread_setstatus(self
, flavor
,
200 (thread_state_t
)state
,
204 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
205 thread_exception_return();
210 case EXCEPTION_DEFAULT
:
212 kr
= exception_raise(exc_port
,
213 retrieve_thread_self_fast(self
),
214 retrieve_task_self_fast(self
->task
),
218 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
219 thread_exception_return();
223 case EXCEPTION_STATE_IDENTITY
: {
224 mach_msg_type_number_t state_cnt
;
225 thread_state_data_t state
;
227 c_thr_exc_raise_state_id
++;
228 state_cnt
= _MachineStateCount
[flavor
];
229 kr
= thread_getstatus(self
, flavor
,
230 (thread_state_t
)state
,
232 if (kr
== KERN_SUCCESS
) {
233 kr
= exception_raise_state_identity(exc_port
,
234 retrieve_thread_self_fast(self
),
235 retrieve_task_self_fast(self
->task
),
241 if (kr
== MACH_MSG_SUCCESS
)
242 kr
= thread_setstatus(self
, flavor
,
243 (thread_state_t
)state
,
247 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
248 thread_exception_return();
254 panic ("bad exception behavior!");
261 * The current thread caught an exception.
262 * We make an up-call to the thread's exception server.
264 * Nothing locked and no resources held.
265 * Called from an exception context, so
266 * thread_exception_return and thread_kdb_return
273 exception_type_t exception
,
274 exception_data_t code
,
275 mach_msg_type_number_t codeCnt
)
279 host_priv_t host_priv
;
280 struct exception_action
*excp
;
283 assert(exception
!= EXC_RPC_ALERT
);
285 if (exception
== KERN_SUCCESS
)
289 * Try to raise the exception at the activation level.
291 thread
= current_thread();
292 mutex
= mutex_addr(thread
->mutex
);
293 excp
= &thread
->exc_actions
[exception
];
294 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
297 * Maybe the task level will handle it.
299 task
= current_task();
300 mutex
= mutex_addr(task
->lock
);
301 excp
= &task
->exc_actions
[exception
];
302 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
305 * How about at the host level?
307 host_priv
= host_priv_self();
308 mutex
= mutex_addr(host_priv
->lock
);
309 excp
= &host_priv
->exc_actions
[exception
];
310 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
313 * Nobody handled it, terminate the task.
317 if (debug_user_with_kdb
) {
319 * Debug the exception with kdb.
320 * If kdb handles the exception,
321 * then thread_kdb_return won't return.
323 db_printf("No exception server, calling kdb...\n");
326 #endif /* MACH_KDB */
328 (void) task_terminate(task
);
329 thread_exception_return();
335 exception_type_t exception
,
336 exception_data_t code
,
337 mach_msg_type_number_t codeCnt
)
340 struct exception_action
*excp
;
342 thread_t self
= current_thread();
349 * Maybe the task level will handle it.
351 task
= current_task();
352 mutex
= mutex_addr(task
->lock
);
353 excp
= &task
->exc_actions
[exception
];
356 * Save work if we are terminating.
357 * Just go back to our AST handler.
360 return(KERN_FAILURE
);
364 * Snapshot the exception action data under lock for consistency.
365 * Hold a reference to the port over the exception_raise_* calls
366 * so it can't be destroyed. This seems like overkill, but keeps
367 * the port from disappearing between now and when
368 * ipc_object_copyin_from_kernel is finally called.
371 exc_port
= excp
->port
;
372 if (!IP_VALID(exc_port
)) {
374 return(KERN_FAILURE
);
377 if (!ip_active(exc_port
)) {
380 return(KERN_FAILURE
);
382 ip_reference(exc_port
);
383 exc_port
->ip_srights
++;
386 flavor
= excp
->flavor
;
387 behavior
= excp
->behavior
;
391 case EXCEPTION_STATE
: {
392 mach_msg_type_number_t state_cnt
;
393 thread_state_data_t state
;
395 c_thr_exc_raise_state
++;
396 state_cnt
= _MachineStateCount
[flavor
];
397 kr
= thread_getstatus(self
, flavor
,
398 (thread_state_t
)state
,
400 if (kr
== KERN_SUCCESS
) {
401 kr
= exception_raise_state(exc_port
, exception
,
406 if (kr
== MACH_MSG_SUCCESS
)
407 kr
= thread_setstatus(self
, flavor
,
408 (thread_state_t
)state
,
412 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
413 return(KERN_SUCCESS
);
415 return(KERN_FAILURE
);
418 case EXCEPTION_DEFAULT
:
420 kr
= exception_raise(exc_port
,
421 retrieve_thread_self_fast(self
),
422 retrieve_task_self_fast(self
->task
),
426 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
427 return(KERN_SUCCESS
);
428 return(KERN_FAILURE
);
430 case EXCEPTION_STATE_IDENTITY
: {
431 mach_msg_type_number_t state_cnt
;
432 thread_state_data_t state
;
434 c_thr_exc_raise_state_id
++;
435 state_cnt
= _MachineStateCount
[flavor
];
436 kr
= thread_getstatus(self
, flavor
,
437 (thread_state_t
)state
,
439 if (kr
== KERN_SUCCESS
) {
440 kr
= exception_raise_state_identity(exc_port
,
441 retrieve_thread_self_fast(self
),
442 retrieve_task_self_fast(self
->task
),
448 if (kr
== MACH_MSG_SUCCESS
)
449 kr
= thread_setstatus(self
, flavor
,
450 (thread_state_t
)state
,
454 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
455 return(KERN_SUCCESS
);
456 return(KERN_FAILURE
);
461 return(KERN_FAILURE
);
463 return(KERN_FAILURE
);
470 * Handle interface for special perfomance monitoring
471 * This is a special case of the host exception handler
474 kern_return_t
sys_perf_notify(struct task
*task
,
475 exception_data_t code
,
476 mach_msg_type_number_t codeCnt
)
479 struct exception_action
*excp
;
480 thread_t thread
= current_thread();
483 wait_interrupt_t wsave
;
485 hostp
= host_priv_self(); /* Get the host privileged ports */
486 excp
= &hostp
->exc_actions
[EXC_RPC_ALERT
]; /* Point to the RPC_ALERT action */
488 mutex_lock(&hostp
->lock
); /* Lock the priv port */
489 xport
= excp
->port
; /* Get the port for this exception */
490 if (!IP_VALID(xport
)) { /* Is it valid? */
491 mutex_unlock(&hostp
->lock
); /* Unlock */
492 return(KERN_FAILURE
); /* Go away... */
495 ip_lock(xport
); /* Lock the exception port */
496 if (!ip_active(xport
)) { /* and is it active? */
497 ip_unlock(xport
); /* Nope, fail */
498 mutex_unlock(&hostp
->lock
); /* Unlock */
499 return(KERN_FAILURE
); /* Go away... */
502 if (task
->itk_space
== xport
->data
.receiver
) { /* Are we trying to send to ourselves? */
503 ip_unlock(xport
); /* Yes, fail */
504 mutex_unlock(&hostp
->lock
); /* Unlock */
505 return(KERN_FAILURE
); /* Go away... */
508 ip_reference(xport
); /* Bump reference so it doesn't go away */
509 xport
->ip_srights
++; /* Bump send rights */
510 ip_unlock(xport
); /* We can unlock it now */
512 mutex_unlock(&hostp
->lock
); /* All done with the lock */
514 wsave
= thread_interrupt_level(THREAD_UNINT
); /* Make sure we aren't aborted here */
516 ret
= exception_raise(xport
, /* Send the exception to the perf handler */
517 retrieve_thread_self_fast(thread
), /* Not always the dying guy */
518 retrieve_task_self_fast(thread
->task
), /* Not always the dying guy */
519 EXC_RPC_ALERT
, /* Unused exception type until now */
522 (void)thread_interrupt_level(wsave
); /* Restore interrupt level */
524 return(ret
); /* Tell caller how it went */