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

CVSweb