]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
11 | * | |
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 | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Mach Operating System | |
24 | * Copyright (c) 1987 Carnegie-Mellon University | |
25 | * All rights reserved. The CMU software License Agreement specifies | |
26 | * the terms and conditions for use and redistribution. | |
27 | */ | |
28 | ||
29 | /* | |
30 | ********************************************************************* | |
31 | * HISTORY | |
32 | ********************************************************************** | |
33 | */ | |
34 | ||
35 | #include <sys/param.h> | |
36 | ||
37 | #include <mach/boolean.h> | |
38 | #include <mach/exception.h> | |
39 | #include <mach/kern_return.h> | |
40 | #include <mach/message.h> | |
41 | #include <mach/port.h> | |
42 | #include <mach/mig_errors.h> | |
43 | #include <kern/task.h> | |
44 | #include <kern/thread.h> | |
45 | #include <kern/sched_prim.h> | |
46 | #include <kern/thread_act.h> | |
47 | #include <kern/kalloc.h> | |
48 | ||
49 | #include <sys/proc.h> | |
50 | #include <sys/user.h> | |
51 | #include <sys/systm.h> | |
52 | #include <sys/ux_exception.h> | |
53 | ||
54 | /* | |
55 | * Unix exception handler. | |
56 | */ | |
57 | ||
58 | static void ux_exception(); | |
59 | ||
60 | decl_simple_lock_data(static, ux_handler_init_lock) | |
61 | mach_port_name_t ux_exception_port; | |
62 | static task_t ux_handler_self; | |
63 | ||
64 | static | |
65 | void | |
66 | ux_handler(void) | |
67 | { | |
68 | task_t self = current_task(); | |
69 | mach_port_name_t exc_port_name; | |
70 | mach_port_name_t exc_set_name; | |
71 | ||
72 | (void) thread_funnel_set(kernel_flock, TRUE); | |
73 | ||
74 | /* self->kernel_vm_space = TRUE; */ | |
75 | ux_handler_self = self; | |
76 | ||
77 | ||
78 | /* | |
79 | * Allocate a port set that we will receive on. | |
80 | */ | |
81 | if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_PORT_SET, &exc_set_name) != MACH_MSG_SUCCESS) | |
82 | panic("ux_handler: port_set_allocate failed"); | |
83 | ||
84 | /* | |
85 | * Allocate an exception port and use object_copyin to | |
86 | * translate it to the global name. Put it into the set. | |
87 | */ | |
88 | if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_RECEIVE, &exc_port_name) != MACH_MSG_SUCCESS) | |
89 | panic("ux_handler: port_allocate failed"); | |
90 | if (mach_port_move_member(get_task_ipcspace(ux_handler_self), | |
91 | exc_port_name, exc_set_name) != MACH_MSG_SUCCESS) | |
92 | panic("ux_handler: port_set_add failed"); | |
93 | ||
94 | if (ipc_object_copyin(get_task_ipcspace(self), exc_port_name, | |
95 | MACH_MSG_TYPE_MAKE_SEND, | |
96 | (void *) &ux_exception_port) != MACH_MSG_SUCCESS) | |
97 | panic("ux_handler: object_copyin(ux_exception_port) failed"); | |
98 | ||
99 | thread_wakeup(&ux_exception_port); | |
100 | ||
101 | /* Message handling loop. */ | |
102 | ||
103 | for (;;) { | |
104 | struct rep_msg { | |
105 | mach_msg_header_t Head; | |
106 | NDR_record_t NDR; | |
107 | kern_return_t RetCode; | |
108 | } rep_msg; | |
109 | struct exc_msg { | |
110 | mach_msg_header_t Head; | |
111 | /* start of the kernel processed data */ | |
112 | mach_msg_body_t msgh_body; | |
113 | mach_msg_port_descriptor_t thread; | |
114 | mach_msg_port_descriptor_t task; | |
115 | /* end of the kernel processed data */ | |
116 | NDR_record_t NDR; | |
117 | exception_type_t exception; | |
118 | mach_msg_type_number_t codeCnt; | |
119 | exception_data_t code; | |
120 | /* some times RCV_TO_LARGE probs */ | |
121 | char pad[512]; | |
122 | } exc_msg; | |
123 | mach_port_name_t reply_port; | |
124 | kern_return_t result; | |
125 | ||
126 | exc_msg.Head.msgh_local_port = (mach_port_t)exc_set_name; | |
127 | exc_msg.Head.msgh_size = sizeof (exc_msg); | |
128 | #if 0 | |
129 | result = mach_msg_receive(&exc_msg.Head); | |
130 | #else | |
131 | result = mach_msg_receive(&exc_msg.Head, MACH_RCV_MSG, | |
132 | sizeof (exc_msg), exc_set_name, | |
133 | MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, | |
134 | 0); | |
135 | #endif | |
136 | if (result == MACH_MSG_SUCCESS) { | |
137 | reply_port = (mach_port_name_t)exc_msg.Head.msgh_remote_port; | |
138 | ||
139 | if (exc_server(&exc_msg.Head, &rep_msg.Head)) | |
140 | (void) mach_msg_send(&rep_msg.Head, MACH_SEND_MSG, | |
141 | sizeof (rep_msg),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL); | |
142 | ||
143 | if (reply_port != MACH_PORT_NULL) | |
144 | (void) mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port); | |
145 | } | |
146 | else if (result == MACH_RCV_TOO_LARGE) | |
147 | /* ignore oversized messages */; | |
148 | else | |
149 | panic("exception_handler"); | |
150 | } | |
151 | thread_funnel_set(kernel_flock, FALSE); | |
152 | } | |
153 | ||
154 | void | |
155 | ux_handler_init(void) | |
156 | { | |
157 | task_t handler_task; | |
158 | ||
159 | simple_lock_init(&ux_handler_init_lock); | |
160 | ux_exception_port = MACH_PORT_NULL; | |
161 | if (kernel_task_create(kernel_task, | |
162 | 0, 0, &handler_task) != MACH_MSG_SUCCESS) { | |
163 | panic("Failed to created ux handler task\n"); | |
164 | } | |
165 | (void) kernel_thread(handler_task, ux_handler); | |
166 | simple_lock(&ux_handler_init_lock); | |
167 | if (ux_exception_port == MACH_PORT_NULL) { | |
168 | simple_unlock(&ux_handler_init_lock); | |
169 | assert_wait(&ux_exception_port, THREAD_UNINT); | |
170 | thread_block(THREAD_CONTINUE_NULL); | |
171 | } | |
172 | else | |
173 | simple_unlock(&ux_handler_init_lock); | |
174 | } | |
175 | ||
176 | kern_return_t | |
177 | catch_exception_raise( | |
178 | mach_port_name_t exception_port, | |
179 | mach_port_name_t thread_name, | |
180 | mach_port_name_t task_name, | |
181 | int exception, | |
182 | exception_data_t code, | |
183 | mach_msg_type_number_t codecnt | |
184 | ) | |
185 | { | |
186 | task_t self = current_task(); | |
187 | thread_act_t th_act; | |
188 | ipc_port_t thread_port; | |
189 | ipc_port_t task_port; | |
190 | kern_return_t result = MACH_MSG_SUCCESS; | |
191 | int signal = 0; | |
192 | u_long ucode = 0; | |
193 | struct uthread *ut; | |
194 | ||
195 | /* | |
196 | * Convert local thread name to global port. | |
197 | */ | |
198 | if (MACH_PORT_VALID(thread_name) && | |
199 | (ipc_object_copyin(get_task_ipcspace(self), thread_name, | |
200 | MACH_MSG_TYPE_PORT_SEND, | |
201 | (void *) &thread_port) == MACH_MSG_SUCCESS)) { | |
202 | if (IPC_PORT_VALID(thread_port)) { | |
203 | th_act = (thread_act_t)convert_port_to_act(thread_port); | |
204 | ipc_port_release(thread_port); | |
205 | } else { | |
206 | th_act = THR_ACT_NULL; | |
207 | } | |
208 | ||
209 | /* | |
210 | * Catch bogus ports | |
211 | */ | |
212 | if (th_act != THR_ACT_NULL) { | |
213 | ||
214 | /* | |
215 | * Convert exception to unix signal and code. | |
216 | */ | |
217 | ut = get_bsdthread_info(th_act); | |
218 | ux_exception(exception, code[0], code[1], | |
219 | &signal, &ucode); | |
220 | ||
221 | /* | |
222 | * Send signal. | |
223 | */ | |
224 | if (signal != 0) | |
225 | threadsignal(th_act, signal, ucode); | |
226 | ||
227 | act_deallocate(th_act); | |
228 | } | |
229 | else | |
230 | result = KERN_INVALID_ARGUMENT; | |
231 | } | |
232 | else | |
233 | result = KERN_INVALID_ARGUMENT; | |
234 | ||
235 | /* | |
236 | * Delete our send rights to the task and thread ports. | |
237 | */ | |
238 | (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name); | |
239 | (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self),thread_name); | |
240 | ||
241 | return (result); | |
242 | } | |
243 | kern_return_t | |
244 | catch_exception_raise_state(mach_port_name_t exception_port, int exception, exception_data_t code, mach_msg_type_number_t codeCnt, int flavor, thread_state_t old_state, int old_stateCnt, thread_state_t new_state, int new_stateCnt) | |
245 | { | |
246 | return(KERN_INVALID_ARGUMENT); | |
247 | } | |
248 | kern_return_t | |
249 | catch_exception_raise_state_identity(mach_port_name_t exception_port, mach_port_t thread, mach_port_t task, int exception, exception_data_t code, mach_msg_type_number_t codeCnt, int flavor, thread_state_t old_state, int old_stateCnt, thread_state_t new_state, int new_stateCnt) | |
250 | { | |
251 | return(KERN_INVALID_ARGUMENT); | |
252 | } | |
253 | ||
254 | boolean_t machine_exception(); | |
255 | ||
256 | /* | |
257 | * ux_exception translates a mach exception, code and subcode to | |
258 | * a signal and u.u_code. Calls machine_exception (machine dependent) | |
259 | * to attempt translation first. | |
260 | */ | |
261 | ||
262 | static | |
263 | void ux_exception( | |
264 | int exception, | |
265 | int code, | |
266 | int subcode, | |
267 | int *ux_signal, | |
268 | int *ux_code | |
269 | ) | |
270 | { | |
271 | /* | |
272 | * Try machine-dependent translation first. | |
273 | */ | |
274 | if (machine_exception(exception, code, subcode, ux_signal, ux_code)) | |
275 | return; | |
276 | ||
277 | switch(exception) { | |
278 | ||
279 | case EXC_BAD_ACCESS: | |
280 | if (code == KERN_INVALID_ADDRESS) | |
281 | *ux_signal = SIGSEGV; | |
282 | else | |
283 | *ux_signal = SIGBUS; | |
284 | break; | |
285 | ||
286 | case EXC_BAD_INSTRUCTION: | |
287 | *ux_signal = SIGILL; | |
288 | break; | |
289 | ||
290 | case EXC_ARITHMETIC: | |
291 | *ux_signal = SIGFPE; | |
292 | break; | |
293 | ||
294 | case EXC_EMULATION: | |
295 | *ux_signal = SIGEMT; | |
296 | break; | |
297 | ||
298 | case EXC_SOFTWARE: | |
299 | switch (code) { | |
300 | ||
301 | case EXC_UNIX_BAD_SYSCALL: | |
302 | *ux_signal = SIGSYS; | |
303 | break; | |
304 | case EXC_UNIX_BAD_PIPE: | |
305 | *ux_signal = SIGPIPE; | |
306 | break; | |
307 | case EXC_UNIX_ABORT: | |
308 | *ux_signal = SIGABRT; | |
309 | break; | |
310 | case EXC_SOFT_SIGNAL: | |
311 | *ux_signal = SIGKILL; | |
312 | break; | |
313 | } | |
314 | break; | |
315 | ||
316 | case EXC_BREAKPOINT: | |
317 | *ux_signal = SIGTRAP; | |
318 | break; | |
319 | } | |
320 | } |