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