Annotation of prex-old/sys/kern/exception.c, Revision 1.1
1.1 ! nbrk 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 specify 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 <irq.h>
! 80: #include <exception.h>
! 81:
! 82: static struct event exception_event;
! 83:
! 84: /*
! 85: * Install an exception handler for the current task.
! 86: * NULL can be specified as handler to remove current handler.
! 87: * If handler is removed, all pending exceptions are discarded
! 88: * immediately. In this case, all threads blocked in exception_wait()
! 89: * are unblocked.
! 90: *
! 91: * Only one exception handler can be set per task. If the previous
! 92: * handler exists in task, exception_setup() just override that
! 93: * handler.
! 94: */
! 95: int
! 96: exception_setup(void (*handler)(int, u_long))
! 97: {
! 98: task_t self;
! 99: list_t head, n;
! 100: thread_t th;
! 101:
! 102: if (handler != NULL && !user_area(handler))
! 103: return EFAULT;
! 104:
! 105: sched_lock();
! 106: self = cur_task();
! 107: if (self->exc_handler && handler == NULL) {
! 108: /*
! 109: * Remove existing exception handler. Do clean up
! 110: * job for all threads in the target task.
! 111: */
! 112: head = &self->threads;
! 113: for (n = list_first(head); n != head; n = list_next(n)) {
! 114: /*
! 115: * Clear pending exceptions.
! 116: */
! 117: th = list_entry(n, struct thread, task_link);
! 118: irq_lock();
! 119: th->exc_bitmap = 0;
! 120: irq_unlock();
! 121: /*
! 122: * If the thread is waiting for an exception,
! 123: * cancel it.
! 124: */
! 125: if (th->sleep_event == &exception_event)
! 126: sched_unsleep(th, SLP_BREAK);
! 127: }
! 128: }
! 129: self->exc_handler = handler;
! 130: sched_unlock();
! 131: return 0;
! 132: }
! 133:
! 134: /*
! 135: * exception_raise - raise an exception for specified task.
! 136: * @task: task id
! 137: * @exc: exception code
! 138: *
! 139: * The exception pending flag is marked here, and it is processed
! 140: * by exception_deliver() later. If the task want to raise an
! 141: * exception to another task, the caller task must have CAP_KILL
! 142: * capability. If the exception is sent to the kernel task, this
! 143: * routine just returns error.
! 144: */
! 145: int
! 146: exception_raise(task_t task, int exc)
! 147: {
! 148: int err;
! 149:
! 150: sched_lock();
! 151:
! 152: if (!task_valid(task)) {
! 153: err = ESRCH;
! 154: } else if (task != cur_task() && !task_capable(CAP_KILL)) {
! 155: err = EPERM;
! 156: } else if (task == &kern_task || task->exc_handler == NULL ||
! 157: list_empty(&task->threads)) {
! 158: err = EPERM;
! 159: } else {
! 160: err = exception_post(task, exc);
! 161: }
! 162: sched_unlock();
! 163: return err;
! 164: }
! 165:
! 166: /*
! 167: * Post an exception to the specified task.
! 168: */
! 169: int
! 170: exception_post(task_t task, int exc)
! 171: {
! 172: list_t head, n;
! 173: thread_t th;
! 174:
! 175: if (exc < 0 || exc >= NR_EXCS)
! 176: return EINVAL;
! 177:
! 178: /*
! 179: * Determine which thread should we send an exception.
! 180: * First, search the thread that is waiting an exception by
! 181: * calling exception_wait(). Then, if no thread is waiting
! 182: * exceptions, it is sent to the master thread in task.
! 183: */
! 184: head = &task->threads;
! 185: for (n = list_first(head); n != head; n = list_next(n)) {
! 186: th = list_entry(n, struct thread, task_link);
! 187: if (th->sleep_event == &exception_event)
! 188: break;
! 189: }
! 190: if (n == head) {
! 191: n = list_first(head);
! 192: th = list_entry(n, struct thread, task_link);
! 193: }
! 194: /*
! 195: * Mark pending bit for this exception.
! 196: */
! 197: irq_lock();
! 198: th->exc_bitmap |= (1 << exc);
! 199: irq_unlock();
! 200:
! 201: /*
! 202: * Wakeup the target thread regardless of its waiting
! 203: * event.
! 204: */
! 205: sched_unsleep(th, SLP_INTR);
! 206:
! 207: return 0;
! 208: }
! 209:
! 210: /*
! 211: * exception_wait - block a current thread until some exceptions are
! 212: * raised to the current thread.
! 213: * @exc: exception code returned.
! 214: *
! 215: * The routine returns EINTR on success.
! 216: */
! 217: int
! 218: exception_wait(int *exc)
! 219: {
! 220: int i, rc;
! 221:
! 222: if (cur_task()->exc_handler == NULL)
! 223: return EINVAL;
! 224: if (!user_area(exc))
! 225: return EFAULT;
! 226:
! 227: sched_lock();
! 228:
! 229: /*
! 230: * Sleep until some exceptions occur.
! 231: */
! 232: rc = sched_sleep(&exception_event);
! 233: if (rc == SLP_BREAK) {
! 234: sched_unlock();
! 235: return EINVAL;
! 236: }
! 237: irq_lock();
! 238: for (i = 0; i < NR_EXCS; i++) {
! 239: if (cur_thread->exc_bitmap & (1 << i))
! 240: break;
! 241: }
! 242: irq_unlock();
! 243: ASSERT(i != NR_EXCS);
! 244: sched_unlock();
! 245:
! 246: if (umem_copyout(&i, exc, sizeof(int)))
! 247: return EFAULT;
! 248: return EINTR;
! 249: }
! 250:
! 251: /*
! 252: * Mark an exception flag for the current thread.
! 253: *
! 254: * This is called from architecture dependent code when H/W trap is
! 255: * occurred. If current task does not have exception handler, then
! 256: * current task will be terminated.
! 257: * This routine may be called at interrupt level.
! 258: */
! 259: void
! 260: exception_mark(int exc)
! 261: {
! 262: ASSERT(exc > 0 && exc < NR_EXCS);
! 263:
! 264: /* Mark pending bit */
! 265: irq_lock();
! 266: cur_thread->exc_bitmap |= (1 << exc);
! 267: irq_unlock();
! 268: }
! 269:
! 270: /*
! 271: * Check if pending exception exists for current task, and deliver
! 272: * it to the exception handler if needed.
! 273: * All exception is delivered at the time when the control goes back
! 274: * to the user mode.
! 275: * This routine is called from architecture dependent code.
! 276: * Some application may use longjmp() during its signal handler.
! 277: * So, current context must be saved to user mode stack.
! 278: */
! 279: void
! 280: exception_deliver(void)
! 281: {
! 282: thread_t th = cur_thread;
! 283: task_t self = cur_task();
! 284: void (*handler)(int, u_long);
! 285: uint32_t bitmap;
! 286: int exc;
! 287:
! 288: sched_lock();
! 289: irq_lock();
! 290: bitmap = th->exc_bitmap;
! 291: irq_unlock();
! 292:
! 293: if (bitmap != 0) {
! 294: /*
! 295: * Find a pending exception.
! 296: */
! 297: for (exc = 0; exc < NR_EXCS; exc++) {
! 298: if (bitmap & (1 << exc))
! 299: break;
! 300: }
! 301: handler = self->exc_handler;
! 302: if (handler == NULL) {
! 303: printk("Exception #%d is not handled by task.\n", exc);
! 304: printk("Terminate task:%s (id:%x)\n",
! 305: self->name ? self->name : "no name", self);
! 306: task_terminate(self);
! 307: goto out;
! 308: }
! 309: /*
! 310: * Transfer control to an exception handler.
! 311: */
! 312: context_save(&th->context, exc);
! 313: context_set(&th->context, CTX_UENTRY, (u_long)handler);
! 314:
! 315: irq_lock();
! 316: th->exc_bitmap &= ~(1 << exc);
! 317: irq_unlock();
! 318: }
! 319: out:
! 320: sched_unlock();
! 321: }
! 322:
! 323: /*
! 324: * exception_return() is called from exception handler to restore
! 325: * the original context.
! 326: * @regs: context pointer which is passed to exception handler.
! 327: *
! 328: * TODO: should validate passed data area.
! 329: */
! 330: int
! 331: exception_return(void *regs)
! 332: {
! 333:
! 334: if ((regs == NULL) || !user_area(regs))
! 335: return EFAULT;
! 336:
! 337: context_restore(&cur_thread->context, regs);
! 338: return 0;
! 339: }
! 340:
! 341: void
! 342: exception_init(void)
! 343: {
! 344:
! 345: event_init(&exception_event, "exception");
! 346: }
CVSweb