|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/sys/kern/exception.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /*- 2 * Copyright (c) 2005-2007, Kohsuke Ohtani 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * exception.c - exception handling routines 32 */ 33 34 /** 35 * An user mode task can set its own exception handler with 36 * exception_setup() system call. 37 * 38 * There are two different types of exceptions in a system - H/W and 39 * S/W exception. The kernel determines to which thread it delivers 40 * depending on the exception type. 41 * 42 * - H/W exception 43 * 44 * This type of exception is caused by H/W trap & fault. The 45 * exception will be sent to the thread which caused the trap. 46 * If no handler is specified by the task, it will be terminated 47 * by the kernel immediately. 48 * 49 * - S/W exception 50 * 51 * The user mode task can send S/W exception to another task by 52 * exception_raise() system call. 53 * The exception will be sent to the thread that is sleeping with 54 * exception_wait() call. If no thread is waiting for the exception, 55 * the exception is sent to the first thread in the target task. 56 * 57 * Kernel supports 32 types of exceptions. The following pre-defined 58 * exceptions are raised by kernel itself. 59 * 60 * Exception Type Reason 61 * --------- ---- ----------------------- 62 * SIGILL h/w illegal instruction 63 * SIGTRAP h/w break point 64 * SIGFPE h/w math error 65 * SIGSEGV h/w invalid memory access 66 * SIGALRM s/w alarm event 67 * 68 * The POSIX emulation library will setup own exception handler to 69 * convert the Prex exceptions into UNIX signals. It will maintain its 70 * own signal mask, and transfer control to the POSIX signal handler. 71 */ 72 73 #include <kernel.h> 74 #include <event.h> 75 #include <task.h> 76 #include <thread.h> 77 #include <sched.h> 78 #include <task.h> 79 #include <hal.h> 80 #include <exception.h> 81 82 static struct event exception_event; 83 84 /* 85 * Install an exception handler for the current task. 86 * 87 * EXC_DFL can be specified as handler to remove the current handler. 88 * If handler is removed, all pending exceptions are discarded 89 * immediately. At this time, all threads blocked in exception_wait() 90 * are automatically unblocked. 91 * 92 * We allow only one exception handler per task. If the handler 93 * has already been set in task, exception_setup() just override 94 * the previous handler. 95 */ 96 int 97 exception_setup(void (*handler)(int)) 98 { 99 task_t self = curtask; 100 list_t head, n; 101 thread_t t; 102 int s; 103 104 if (handler != EXC_DFL && !user_area(handler)) 105 return EFAULT; 106 if (handler == NULL) 107 return EINVAL; 108 109 sched_lock(); 110 if (self->handler != EXC_DFL && handler == EXC_DFL) { 111 /* 112 * Remove existing exception handler. Do clean up 113 * job for all threads in the target task. 114 */ 115 head = &self->threads; 116 for (n = list_first(head); n != head; n = list_next(n)) { 117 118 /* 119 * Clear pending exceptions. 120 */ 121 s = splhigh(); 122 t = list_entry(n, struct thread, task_link); 123 t->excbits = 0; 124 splx(s); 125 126 /* 127 * If the thread is waiting for an exception, 128 * cancel it. 129 */ 130 if (t->slpevt == &exception_event) { 131 DPRINTF(("Exception cancelled task=%s\n", 132 self->name)); 133 sched_unsleep(t, SLP_BREAK); 134 } 135 } 136 } 137 self->handler = handler; 138 sched_unlock(); 139 return 0; 140 } 141 142 /* 143 * exception_raise - system call to raise an exception. 144 * 145 * The exception pending flag is marked here, and it is 146 * processed by exception_deliver() later. The task must have 147 * CAP_KILL capability to raise an exception to another task. 148 */ 149 int 150 exception_raise(task_t task, int excno) 151 { 152 int error; 153 154 sched_lock(); 155 if (!task_valid(task)) { 156 DPRINTF(("Bad exception task=%lx\n", (long)task)); 157 sched_unlock(); 158 return ESRCH; 159 } 160 if (task != curtask && !task_capable(CAP_KILL)) { 161 sched_unlock(); 162 return EPERM; 163 } 164 error = exception_post(task, excno); 165 sched_unlock(); 166 return error; 167 } 168 169 /* 170 * exception_post-- the internal version of exception_raise(). 171 */ 172 int 173 exception_post(task_t task, int excno) 174 { 175 list_t head, n; 176 thread_t t = NULL; 177 int s, found = 0; 178 179 sched_lock(); 180 if (task->flags & TF_SYSTEM) { 181 sched_unlock(); 182 return EPERM; 183 } 184 185 if ((task->handler == EXC_DFL) || 186 (task->nthreads == 0) || 187 (excno < 0) || (excno >= NEXC)) { 188 sched_unlock(); 189 return EINVAL; 190 } 191 192 /* 193 * Determine which thread should we send an exception. 194 * First, search the thread that is currently waiting 195 * an exception by calling exception_wait(). 196 */ 197 head = &task->threads; 198 for (n = list_first(head); n != head; n = list_next(n)) { 199 t = list_entry(n, struct thread, task_link); 200 if (t->slpevt == &exception_event) { 201 found = 1; 202 break; 203 } 204 } 205 206 /* 207 * If no thread is waiting exceptions, we send it to 208 * the master thread in the task. 209 */ 210 if (!found) { 211 if (!list_empty(&task->threads)) { 212 n = list_first(&task->threads); 213 t = list_entry(n, struct thread, task_link); 214 } 215 } 216 217 /* 218 * Mark pending bit for this exception. 219 */ 220 s = splhigh(); 221 t->excbits |= (1 << excno); 222 splx(s); 223 224 /* 225 * Wakeup the target thread regardless of its 226 * waiting event. 227 */ 228 sched_unsleep(t, SLP_INTR); 229 230 sched_unlock(); 231 return 0; 232 } 233 234 /* 235 * exception_wait - block a current thread until some 236 * exceptions are raised to the current thread. 237 * 238 * The routine returns EINTR on success. 239 */ 240 int 241 exception_wait(int *excno) 242 { 243 int i, rc, s; 244 245 if (curtask->handler == EXC_DFL) 246 return EINVAL; 247 248 /* Check fault before sleeping. */ 249 i = 0; 250 if (copyout(&i, excno, sizeof(i))) 251 return EFAULT; 252 253 sched_lock(); 254 255 /* 256 * Sleep until some exceptions occur. 257 */ 258 rc = sched_sleep(&exception_event); 259 if (rc == SLP_BREAK) { 260 sched_unlock(); 261 return EINVAL; 262 } 263 s = splhigh(); 264 for (i = 0; i < NEXC; i++) { 265 if (curthread->excbits & (1 << i)) 266 break; 267 } 268 splx(s); 269 ASSERT(i != NEXC); 270 sched_unlock(); 271 272 if (copyout(&i, excno, sizeof(i))) 273 return EFAULT; 274 return EINTR; 275 } 276 277 /* 278 * Mark an exception flag for the current thread. 279 * 280 * This is called by HAL code when H/W trap is occurred. If a 281 * current task does not have exception handler, then the 282 * current task will be terminated. This routine can be called 283 * at interrupt level. 284 */ 285 void 286 exception_mark(int excno) 287 { 288 int s; 289 290 ASSERT(excno > 0 && excno < NEXC); 291 292 /* Mark pending bit */ 293 s = splhigh(); 294 curthread->excbits |= (1 << excno); 295 splx(s); 296 } 297 298 /* 299 * exception_deliver - deliver pending exception to the task. 300 * 301 * Check if pending exception exists for the current task, and 302 * deliver it to the exception handler if needed. All 303 * exceptions are delivered at the time when the control goes 304 * back to the user mode. Some application may use longjmp() 305 * during its signal handler. So, current context must be 306 * saved to the user mode stack. 307 */ 308 void 309 exception_deliver(void) 310 { 311 task_t self = curtask; 312 void (*handler)(int); 313 uint32_t bitmap; 314 int s, excno; 315 316 ASSERT(curthread->state != TS_EXIT); 317 sched_lock(); 318 319 s = splhigh(); 320 bitmap = curthread->excbits; 321 splx(s); 322 323 if (bitmap != 0) { 324 /* 325 * Find a pending exception. 326 */ 327 for (excno = 0; excno < NEXC; excno++) { 328 if (bitmap & (1 << excno)) 329 break; 330 } 331 handler = self->handler; 332 if (handler == EXC_DFL) { 333 DPRINTF(("Exception #%d is not handled by task.\n", 334 excno)); 335 DPRINTF(("Terminate task:%s (id:%lx)\n", 336 self->name, (long)self)); 337 338 task_terminate(self); 339 /* NOTREACHED */ 340 } 341 342 /* 343 * Transfer control to an exception handler. 344 */ 345 s = splhigh(); 346 context_save(&curthread->ctx); 347 context_set(&curthread->ctx, CTX_UENTRY, (register_t)handler); 348 context_set(&curthread->ctx, CTX_UARG, (register_t)excno); 349 curthread->excbits &= ~(1 << excno); 350 splx(s); 351 } 352 sched_unlock(); 353 } 354 355 /* 356 * exception_return() is called from exception handler to 357 * restore the original context. 358 */ 359 void 360 exception_return(void) 361 { 362 int s; 363 364 s = splhigh(); 365 context_restore(&curthread->ctx); 366 splx(s); 367 } 368 369 void 370 exception_init(void) 371 { 372 373 event_init(&exception_event, "exception"); 374 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |