[BACK]Return to exception.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / kern

Annotation of prex-old/sys/kern/exception.c, Revision 1.1.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