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/boolean.h>
59 #include <mach/kern_return.h>
60 #include <mach/message.h>
61 #include <mach/port.h>
62 #include <mach/mig_errors.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/etap_macros.h>
73 #include <kern/counters.h>
74 #include <kern/ipc_tt.h>
75 #include <kern/task.h>
76 #include <kern/thread.h>
77 #include <kern/thread_swap.h>
78 #include <kern/processor.h>
79 #include <kern/sched.h>
80 #include <kern/sched_prim.h>
81 #include <kern/host.h>
82 #include <kern/misc_protos.h>
87 #include <ddb/db_trap.h>
92 #include <ddb/db_output.h>
94 #if iPSC386 || iPSC860
95 boolean_t debug_user_with_kdb
= TRUE
;
97 boolean_t debug_user_with_kdb
= FALSE
;
100 #endif /* MACH_KDB */
102 unsigned long c_thr_exc_raise
= 0;
103 unsigned long c_thr_exc_raise_state
= 0;
104 unsigned long c_thr_exc_raise_state_id
= 0;
105 unsigned long c_tsk_exc_raise
= 0;
106 unsigned long c_tsk_exc_raise_state
= 0;
107 unsigned long c_tsk_exc_raise_state_id
= 0;
111 * Routine: exception_deliver
113 * Make an upcall to the exception server provided.
115 * Nothing locked and no resources held.
116 * Called from an exception context, so
117 * thread_exception_return and thread_kdb_return
120 * If the exception was not handled by this handler
124 exception_type_t exception
,
125 exception_data_t code
,
126 mach_msg_type_number_t codeCnt
,
127 struct exception_action
*excp
,
130 thread_act_t a_self
= current_act();
137 * Save work if we are terminating.
138 * Just go back to our AST handler.
141 thread_exception_return();
144 * Snapshot the exception action data under lock for consistency.
145 * Hold a reference to the port over the exception_raise_* calls
146 * so it can't be destroyed. This seems like overkill, but keeps
147 * the port from disappearing between now and when
148 * ipc_object_copyin_from_kernel is finally called.
151 exc_port
= excp
->port
;
152 if (!IP_VALID(exc_port
)) {
157 if (!ip_active(exc_port
)) {
162 ip_reference(exc_port
);
163 exc_port
->ip_srights
++;
166 flavor
= excp
->flavor
;
167 behavior
= excp
->behavior
;
171 case EXCEPTION_STATE
: {
172 mach_msg_type_number_t state_cnt
;
173 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
175 c_thr_exc_raise_state
++;
176 state_cnt
= state_count
[flavor
];
177 kr
= thread_getstatus(a_self
, flavor
,
178 (thread_state_t
)state
,
180 if (kr
== KERN_SUCCESS
) {
181 kr
= exception_raise_state(exc_port
, exception
,
186 if (kr
== MACH_MSG_SUCCESS
)
187 kr
= thread_setstatus(a_self
, flavor
,
188 (thread_state_t
)state
,
192 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
193 thread_exception_return();
198 case EXCEPTION_DEFAULT
:
200 kr
= exception_raise(exc_port
,
201 retrieve_act_self_fast(a_self
),
202 retrieve_task_self_fast(a_self
->task
),
206 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
207 thread_exception_return();
211 case EXCEPTION_STATE_IDENTITY
: {
212 mach_msg_type_number_t state_cnt
;
213 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
215 c_thr_exc_raise_state_id
++;
216 state_cnt
= state_count
[flavor
];
217 kr
= thread_getstatus(a_self
, flavor
,
218 (thread_state_t
)state
,
220 if (kr
== KERN_SUCCESS
) {
221 kr
= exception_raise_state_identity(exc_port
,
222 retrieve_act_self_fast(a_self
),
223 retrieve_task_self_fast(a_self
->task
),
229 if (kr
== MACH_MSG_SUCCESS
)
230 kr
= thread_setstatus(a_self
, flavor
,
231 (thread_state_t
)state
,
235 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
236 thread_exception_return();
242 panic ("bad exception behavior!");
249 * The current thread caught an exception.
250 * We make an up-call to the thread's exception server.
252 * Nothing locked and no resources held.
253 * Called from an exception context, so
254 * thread_exception_return and thread_kdb_return
261 exception_type_t exception
,
262 exception_data_t code
,
263 mach_msg_type_number_t codeCnt
)
265 thread_act_t thr_act
;
267 host_priv_t host_priv
;
268 struct exception_action
*excp
;
271 assert(exception
!= EXC_RPC_ALERT
);
273 if (exception
== KERN_SUCCESS
)
277 * Try to raise the exception at the activation level.
279 thr_act
= current_act();
280 mutex
= mutex_addr(thr_act
->lock
);
281 excp
= &thr_act
->exc_actions
[exception
];
282 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
285 * Maybe the task level will handle it.
287 task
= current_task();
288 mutex
= mutex_addr(task
->lock
);
289 excp
= &task
->exc_actions
[exception
];
290 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
293 * How about at the host level?
295 host_priv
= host_priv_self();
296 mutex
= mutex_addr(host_priv
->lock
);
297 excp
= &host_priv
->exc_actions
[exception
];
298 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
301 * Nobody handled it, terminate the task.
305 if (debug_user_with_kdb
) {
307 * Debug the exception with kdb.
308 * If kdb handles the exception,
309 * then thread_kdb_return won't return.
311 db_printf("No exception server, calling kdb...\n");
314 #endif /* MACH_KDB */
316 (void) task_terminate(task
);
317 thread_exception_return();
323 exception_type_t exception
,
324 exception_data_t code
,
325 mach_msg_type_number_t codeCnt
)
328 host_priv_t host_priv
;
329 struct exception_action
*excp
;
331 thread_act_t a_self
= current_act();
338 * Maybe the task level will handle it.
340 task
= current_task();
341 mutex
= mutex_addr(task
->lock
);
342 excp
= &task
->exc_actions
[exception
];
345 * Save work if we are terminating.
346 * Just go back to our AST handler.
348 if (!a_self
->active
) {
349 return(KERN_FAILURE
);
353 * Snapshot the exception action data under lock for consistency.
354 * Hold a reference to the port over the exception_raise_* calls
355 * so it can't be destroyed. This seems like overkill, but keeps
356 * the port from disappearing between now and when
357 * ipc_object_copyin_from_kernel is finally called.
360 exc_port
= excp
->port
;
361 if (!IP_VALID(exc_port
)) {
363 return(KERN_FAILURE
);
366 if (!ip_active(exc_port
)) {
369 return(KERN_FAILURE
);
371 ip_reference(exc_port
);
372 exc_port
->ip_srights
++;
375 flavor
= excp
->flavor
;
376 behavior
= excp
->behavior
;
380 case EXCEPTION_STATE
: {
381 mach_msg_type_number_t state_cnt
;
382 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
384 c_thr_exc_raise_state
++;
385 state_cnt
= state_count
[flavor
];
386 kr
= thread_getstatus(a_self
, flavor
,
387 (thread_state_t
)state
,
389 if (kr
== KERN_SUCCESS
) {
390 kr
= exception_raise_state(exc_port
, exception
,
395 if (kr
== MACH_MSG_SUCCESS
)
396 kr
= thread_setstatus(a_self
, flavor
,
397 (thread_state_t
)state
,
401 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
402 return(KERN_SUCCESS
);
404 return(KERN_FAILURE
);
407 case EXCEPTION_DEFAULT
:
409 kr
= exception_raise(exc_port
,
410 retrieve_act_self_fast(a_self
),
411 retrieve_task_self_fast(a_self
->task
),
415 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
416 return(KERN_SUCCESS
);
417 return(KERN_FAILURE
);
419 case EXCEPTION_STATE_IDENTITY
: {
420 mach_msg_type_number_t state_cnt
;
421 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
423 c_thr_exc_raise_state_id
++;
424 state_cnt
= state_count
[flavor
];
425 kr
= thread_getstatus(a_self
, flavor
,
426 (thread_state_t
)state
,
428 if (kr
== KERN_SUCCESS
) {
429 kr
= exception_raise_state_identity(exc_port
,
430 retrieve_act_self_fast(a_self
),
431 retrieve_task_self_fast(a_self
->task
),
437 if (kr
== MACH_MSG_SUCCESS
)
438 kr
= thread_setstatus(a_self
, flavor
,
439 (thread_state_t
)state
,
443 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
444 return(KERN_SUCCESS
);
445 return(KERN_FAILURE
);
450 return(KERN_FAILURE
);
452 return(KERN_FAILURE
);