2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
55 #include <mach/boolean.h>
56 #include <mach/kern_return.h>
57 #include <mach/message.h>
58 #include <mach/port.h>
59 #include <mach/mig_errors.h>
60 #include <mach/thread_status.h>
61 #include <mach/exception_types.h>
63 #include <ipc/ipc_entry.h>
64 #include <ipc/ipc_object.h>
65 #include <ipc/ipc_notify.h>
66 #include <ipc/ipc_space.h>
67 #include <ipc/ipc_pset.h>
68 #include <ipc/ipc_machdep.h>
69 #include <kern/etap_macros.h>
70 #include <kern/counters.h>
71 #include <kern/ipc_tt.h>
72 #include <kern/task.h>
73 #include <kern/thread.h>
74 #include <kern/thread_swap.h>
75 #include <kern/processor.h>
76 #include <kern/sched.h>
77 #include <kern/sched_prim.h>
78 #include <kern/host.h>
79 #include <kern/misc_protos.h>
84 #include <ddb/db_trap.h>
89 #include <ddb/db_output.h>
91 #if iPSC386 || iPSC860
92 boolean_t debug_user_with_kdb
= TRUE
;
94 boolean_t debug_user_with_kdb
= FALSE
;
99 unsigned long c_thr_exc_raise
= 0;
100 unsigned long c_thr_exc_raise_state
= 0;
101 unsigned long c_thr_exc_raise_state_id
= 0;
102 unsigned long c_tsk_exc_raise
= 0;
103 unsigned long c_tsk_exc_raise_state
= 0;
104 unsigned long c_tsk_exc_raise_state_id
= 0;
108 * Routine: exception_deliver
110 * Make an upcall to the exception server provided.
112 * Nothing locked and no resources held.
113 * Called from an exception context, so
114 * thread_exception_return and thread_kdb_return
117 * If the exception was not handled by this handler
121 exception_type_t exception
,
122 exception_data_t code
,
123 mach_msg_type_number_t codeCnt
,
124 struct exception_action
*excp
,
127 thread_act_t a_self
= current_act();
134 * Save work if we are terminating.
135 * Just go back to our AST handler.
138 thread_exception_return();
141 * Snapshot the exception action data under lock for consistency.
142 * Hold a reference to the port over the exception_raise_* calls
143 * so it can't be destroyed. This seems like overkill, but keeps
144 * the port from disappearing between now and when
145 * ipc_object_copyin_from_kernel is finally called.
148 exc_port
= excp
->port
;
149 if (!IP_VALID(exc_port
)) {
154 if (!ip_active(exc_port
)) {
159 ip_reference(exc_port
);
160 exc_port
->ip_srights
++;
163 flavor
= excp
->flavor
;
164 behavior
= excp
->behavior
;
168 case EXCEPTION_STATE
: {
169 mach_msg_type_number_t state_cnt
;
170 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
172 c_thr_exc_raise_state
++;
173 state_cnt
= state_count
[flavor
];
174 kr
= thread_getstatus(a_self
, flavor
,
175 (thread_state_t
)state
,
177 if (kr
== KERN_SUCCESS
) {
178 kr
= exception_raise_state(exc_port
, exception
,
183 if (kr
== MACH_MSG_SUCCESS
)
184 kr
= thread_setstatus(a_self
, flavor
,
185 (thread_state_t
)state
,
189 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
190 thread_exception_return();
195 case EXCEPTION_DEFAULT
:
197 kr
= exception_raise(exc_port
,
198 retrieve_act_self_fast(a_self
),
199 retrieve_task_self_fast(a_self
->task
),
203 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
204 thread_exception_return();
208 case EXCEPTION_STATE_IDENTITY
: {
209 mach_msg_type_number_t state_cnt
;
210 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
212 c_thr_exc_raise_state_id
++;
213 state_cnt
= state_count
[flavor
];
214 kr
= thread_getstatus(a_self
, flavor
,
215 (thread_state_t
)state
,
217 if (kr
== KERN_SUCCESS
) {
218 kr
= exception_raise_state_identity(exc_port
,
219 retrieve_act_self_fast(a_self
),
220 retrieve_task_self_fast(a_self
->task
),
226 if (kr
== MACH_MSG_SUCCESS
)
227 kr
= thread_setstatus(a_self
, flavor
,
228 (thread_state_t
)state
,
232 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
233 thread_exception_return();
239 panic ("bad exception behavior!");
246 * The current thread caught an exception.
247 * We make an up-call to the thread's exception server.
249 * Nothing locked and no resources held.
250 * Called from an exception context, so
251 * thread_exception_return and thread_kdb_return
258 exception_type_t exception
,
259 exception_data_t code
,
260 mach_msg_type_number_t codeCnt
)
262 thread_act_t thr_act
;
264 host_priv_t host_priv
;
265 struct exception_action
*excp
;
268 assert(exception
!= EXC_RPC_ALERT
);
270 if (exception
== KERN_SUCCESS
)
274 * Try to raise the exception at the activation level.
276 thr_act
= current_act();
277 mutex
= mutex_addr(thr_act
->lock
);
278 excp
= &thr_act
->exc_actions
[exception
];
279 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
282 * Maybe the task level will handle it.
284 task
= current_task();
285 mutex
= mutex_addr(task
->lock
);
286 excp
= &task
->exc_actions
[exception
];
287 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
290 * How about at the host level?
292 host_priv
= host_priv_self();
293 mutex
= mutex_addr(host_priv
->lock
);
294 excp
= &host_priv
->exc_actions
[exception
];
295 exception_deliver(exception
, code
, codeCnt
, excp
, mutex
);
298 * Nobody handled it, terminate the task.
302 if (debug_user_with_kdb
) {
304 * Debug the exception with kdb.
305 * If kdb handles the exception,
306 * then thread_kdb_return won't return.
308 db_printf("No exception server, calling kdb...\n");
311 #endif /* MACH_KDB */
313 (void) task_terminate(task
);
314 thread_exception_return();
320 exception_type_t exception
,
321 exception_data_t code
,
322 mach_msg_type_number_t codeCnt
)
325 host_priv_t host_priv
;
326 struct exception_action
*excp
;
328 thread_act_t a_self
= current_act();
335 * Maybe the task level will handle it.
337 task
= current_task();
338 mutex
= mutex_addr(task
->lock
);
339 excp
= &task
->exc_actions
[exception
];
342 * Save work if we are terminating.
343 * Just go back to our AST handler.
345 if (!a_self
->active
) {
346 return(KERN_FAILURE
);
350 * Snapshot the exception action data under lock for consistency.
351 * Hold a reference to the port over the exception_raise_* calls
352 * so it can't be destroyed. This seems like overkill, but keeps
353 * the port from disappearing between now and when
354 * ipc_object_copyin_from_kernel is finally called.
357 exc_port
= excp
->port
;
358 if (!IP_VALID(exc_port
)) {
360 return(KERN_FAILURE
);
363 if (!ip_active(exc_port
)) {
366 return(KERN_FAILURE
);
368 ip_reference(exc_port
);
369 exc_port
->ip_srights
++;
372 flavor
= excp
->flavor
;
373 behavior
= excp
->behavior
;
377 case EXCEPTION_STATE
: {
378 mach_msg_type_number_t state_cnt
;
379 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
381 c_thr_exc_raise_state
++;
382 state_cnt
= state_count
[flavor
];
383 kr
= thread_getstatus(a_self
, flavor
,
384 (thread_state_t
)state
,
386 if (kr
== KERN_SUCCESS
) {
387 kr
= exception_raise_state(exc_port
, exception
,
392 if (kr
== MACH_MSG_SUCCESS
)
393 kr
= thread_setstatus(a_self
, flavor
,
394 (thread_state_t
)state
,
398 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
399 return(KERN_SUCCESS
);
401 return(KERN_FAILURE
);
404 case EXCEPTION_DEFAULT
:
406 kr
= exception_raise(exc_port
,
407 retrieve_act_self_fast(a_self
),
408 retrieve_task_self_fast(a_self
->task
),
412 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
413 return(KERN_SUCCESS
);
414 return(KERN_FAILURE
);
416 case EXCEPTION_STATE_IDENTITY
: {
417 mach_msg_type_number_t state_cnt
;
418 natural_t state
[ THREAD_MACHINE_STATE_MAX
];
420 c_thr_exc_raise_state_id
++;
421 state_cnt
= state_count
[flavor
];
422 kr
= thread_getstatus(a_self
, flavor
,
423 (thread_state_t
)state
,
425 if (kr
== KERN_SUCCESS
) {
426 kr
= exception_raise_state_identity(exc_port
,
427 retrieve_act_self_fast(a_self
),
428 retrieve_task_self_fast(a_self
->task
),
434 if (kr
== MACH_MSG_SUCCESS
)
435 kr
= thread_setstatus(a_self
, flavor
,
436 (thread_state_t
)state
,
440 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
441 return(KERN_SUCCESS
);
442 return(KERN_FAILURE
);
447 return(KERN_FAILURE
);
449 return(KERN_FAILURE
);