2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
58 #include <mach/mach_types.h>
59 #include <mach/boolean.h>
60 #include <mach/kern_return.h>
61 #include <mach/message.h>
62 #include <mach/port.h>
63 #include <mach/mig_errors.h>
64 #include <mach/thread_status.h>
65 #include <mach/exception_types.h>
67 #include <ipc/ipc_entry.h>
68 #include <ipc/ipc_object.h>
69 #include <ipc/ipc_notify.h>
70 #include <ipc/ipc_space.h>
71 #include <ipc/ipc_pset.h>
72 #include <ipc/ipc_machdep.h>
73 #include <kern/etap_macros.h>
74 #include <kern/counters.h>
75 #include <kern/ipc_tt.h>
76 #include <kern/task.h>
77 #include <kern/thread.h>
78 #include <kern/thread_swap.h>
79 #include <kern/processor.h>
80 #include <kern/sched.h>
81 #include <kern/sched_prim.h>
82 #include <kern/host.h>
83 #include <kern/misc_protos.h>
88 #include <ddb/db_trap.h>
93 #include <ddb/db_output.h>
95 #if iPSC386 || iPSC860
96 boolean_t debug_user_with_kdb
= TRUE
;
98 boolean_t debug_user_with_kdb
= FALSE
;
101 #endif /* MACH_KDB */
103 unsigned long c_thr_exc_raise
= 0;
104 unsigned long c_thr_exc_raise_state
= 0;
105 unsigned long c_thr_exc_raise_state_id
= 0;
106 unsigned long c_tsk_exc_raise
= 0;
107 unsigned long c_tsk_exc_raise_state
= 0;
108 unsigned long c_tsk_exc_raise_state_id
= 0;
112 * Routine: exception_deliver
114 * Make an upcall to the exception server provided.
116 * Nothing locked and no resources held.
117 * Called from an exception context, so
118 * thread_exception_return and thread_kdb_return
121 * If the exception was not handled by this handler
125 exception_type_t exception
,
126 exception_data_t code
,
127 mach_msg_type_number_t codeCnt
,
128 struct exception_action
*excp
,
131 thread_act_t a_self
= current_act();
138 * Save work if we are terminating.
139 * Just go back to our AST handler.
142 thread_exception_return();
145 * Snapshot the exception action data under lock for consistency.
146 * Hold a reference to the port over the exception_raise_* calls
147 * so it can't be destroyed. This seems like overkill, but keeps
148 * the port from disappearing between now and when
149 * ipc_object_copyin_from_kernel is finally called.
152 exc_port
= excp
->port
;
153 if (!IP_VALID(exc_port
)) {
158 if (!ip_active(exc_port
)) {
163 ip_reference(exc_port
);
164 exc_port
->ip_srights
++;
167 flavor
= excp
->flavor
;
168 behavior
= excp
->behavior
;
172 case EXCEPTION_STATE
: {
173 mach_msg_type_number_t state_cnt
;
174 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
176 c_thr_exc_raise_state
++;
177 state_cnt
= state_count
[flavor
];
178 kr
= thread_getstatus(a_self
, flavor
,
179 (thread_state_t
)state
,
181 if (kr
== KERN_SUCCESS
) {
182 kr
= exception_raise_state(exc_port
, exception
,
187 if (kr
== MACH_MSG_SUCCESS
)
188 kr
= thread_setstatus(a_self
, flavor
,
189 (thread_state_t
)state
,
193 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
194 thread_exception_return();
199 case EXCEPTION_DEFAULT
:
201 kr
= exception_raise(exc_port
,
202 retrieve_act_self_fast(a_self
),
203 retrieve_task_self_fast(a_self
->task
),
207 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
208 thread_exception_return();
212 case EXCEPTION_STATE_IDENTITY
: {
213 mach_msg_type_number_t state_cnt
;
214 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
216 c_thr_exc_raise_state_id
++;
217 state_cnt
= state_count
[flavor
];
218 kr
= thread_getstatus(a_self
, flavor
,
219 (thread_state_t
)state
,
221 if (kr
== KERN_SUCCESS
) {
222 kr
= exception_raise_state_identity(exc_port
,
223 retrieve_act_self_fast(a_self
),
224 retrieve_task_self_fast(a_self
->task
),
230 if (kr
== MACH_MSG_SUCCESS
)
231 kr
= thread_setstatus(a_self
, flavor
,
232 (thread_state_t
)state
,
236 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
237 thread_exception_return();
243 panic ("bad exception behavior!");
250 * The current thread caught an exception.
251 * We make an up-call to the thread's exception server.
253 * Nothing locked and no resources held.
254 * Called from an exception context, so
255 * thread_exception_return and thread_kdb_return
262 exception_type_t exception
,
263 exception_data_t code
,
264 mach_msg_type_number_t codeCnt
)
266 thread_act_t thr_act
;
268 host_priv_t host_priv
;
269 struct exception_action
*excp
;
272 assert(exception
!= EXC_RPC_ALERT
);
274 if (exception
== KERN_SUCCESS
)
278 * Try to raise the exception at the activation level.
280 thr_act
= current_act();
281 mutex
= mutex_addr(thr_act
->lock
);
282 excp
= &thr_act
->exc_actions
[exception
];
283 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
286 * Maybe the task level will handle it.
288 task
= current_task();
289 mutex
= mutex_addr(task
->lock
);
290 excp
= &task
->exc_actions
[exception
];
291 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
294 * How about at the host level?
296 host_priv
= host_priv_self();
297 mutex
= mutex_addr(host_priv
->lock
);
298 excp
= &host_priv
->exc_actions
[exception
];
299 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
302 * Nobody handled it, terminate the task.
306 if (debug_user_with_kdb
) {
308 * Debug the exception with kdb.
309 * If kdb handles the exception,
310 * then thread_kdb_return won't return.
312 db_printf("No exception server, calling kdb...\n");
315 #endif /* MACH_KDB */
317 (void) task_terminate(task
);
318 thread_exception_return();
324 exception_type_t exception
,
325 exception_data_t code
,
326 mach_msg_type_number_t codeCnt
)
329 host_priv_t host_priv
;
330 struct exception_action
*excp
;
332 thread_act_t a_self
= current_act();
339 * Maybe the task level will handle it.
341 task
= current_task();
342 mutex
= mutex_addr(task
->lock
);
343 excp
= &task
->exc_actions
[exception
];
346 * Save work if we are terminating.
347 * Just go back to our AST handler.
349 if (!a_self
->active
) {
350 return(KERN_FAILURE
);
354 * Snapshot the exception action data under lock for consistency.
355 * Hold a reference to the port over the exception_raise_* calls
356 * so it can't be destroyed. This seems like overkill, but keeps
357 * the port from disappearing between now and when
358 * ipc_object_copyin_from_kernel is finally called.
361 exc_port
= excp
->port
;
362 if (!IP_VALID(exc_port
)) {
364 return(KERN_FAILURE
);
367 if (!ip_active(exc_port
)) {
370 return(KERN_FAILURE
);
372 ip_reference(exc_port
);
373 exc_port
->ip_srights
++;
376 flavor
= excp
->flavor
;
377 behavior
= excp
->behavior
;
381 case EXCEPTION_STATE
: {
382 mach_msg_type_number_t state_cnt
;
383 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
385 c_thr_exc_raise_state
++;
386 state_cnt
= state_count
[flavor
];
387 kr
= thread_getstatus(a_self
, flavor
,
388 (thread_state_t
)state
,
390 if (kr
== KERN_SUCCESS
) {
391 kr
= exception_raise_state(exc_port
, exception
,
396 if (kr
== MACH_MSG_SUCCESS
)
397 kr
= thread_setstatus(a_self
, flavor
,
398 (thread_state_t
)state
,
402 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
403 return(KERN_SUCCESS
);
405 return(KERN_FAILURE
);
408 case EXCEPTION_DEFAULT
:
410 kr
= exception_raise(exc_port
,
411 retrieve_act_self_fast(a_self
),
412 retrieve_task_self_fast(a_self
->task
),
416 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
417 return(KERN_SUCCESS
);
418 return(KERN_FAILURE
);
420 case EXCEPTION_STATE_IDENTITY
: {
421 mach_msg_type_number_t state_cnt
;
422 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
424 c_thr_exc_raise_state_id
++;
425 state_cnt
= state_count
[flavor
];
426 kr
= thread_getstatus(a_self
, flavor
,
427 (thread_state_t
)state
,
429 if (kr
== KERN_SUCCESS
) {
430 kr
= exception_raise_state_identity(exc_port
,
431 retrieve_act_self_fast(a_self
),
432 retrieve_task_self_fast(a_self
->task
),
438 if (kr
== MACH_MSG_SUCCESS
)
439 kr
= thread_setstatus(a_self
, flavor
,
440 (thread_state_t
)state
,
444 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
445 return(KERN_SUCCESS
);
446 return(KERN_FAILURE
);
451 return(KERN_FAILURE
);
453 return(KERN_FAILURE
);