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

Annotation of prex/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:  *
        !            87:  * NULL can be specified as handler to remove current handler.
        !            88:  * If handler is removed, all pending exceptions are discarded
        !            89:  * immediately. In this case, all threads blocked in
        !            90:  * exception_wait() are unblocked.
        !            91:  *
        !            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.
        !            95:  */
        !            96: int
        !            97: exception_setup(void (*handler)(int))
        !            98: {
        !            99:        task_t self = cur_task();
        !           100:        list_t head, n;
        !           101:        thread_t th;
        !           102:
        !           103:        if (handler != NULL && !user_area(handler))
        !           104:                return EFAULT;
        !           105:
        !           106:        sched_lock();
        !           107:        if (self->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->excbits = 0;
        !           120:                        irq_unlock();
        !           121:
        !           122:                        /*
        !           123:                         * If the thread is waiting for an exception,
        !           124:                         * cancel it.
        !           125:                         */
        !           126:                        if (th->slpevt == &exception_event)
        !           127:                                sched_unsleep(th, SLP_BREAK);
        !           128:                }
        !           129:        }
        !           130:        self->handler = handler;
        !           131:        sched_unlock();
        !           132:        return 0;
        !           133: }
        !           134:
        !           135: /*
        !           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.
        !           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:                goto out;
        !           155:        }
        !           156:        if (task != cur_task() && !task_capable(CAP_KILL)) {
        !           157:                err = EPERM;
        !           158:                goto out;
        !           159:        }
        !           160:        if (task == &kern_task || task->handler == NULL ||
        !           161:            list_empty(&task->threads)) {
        !           162:                err = EPERM;
        !           163:                goto out;
        !           164:        }
        !           165:        err = exception_post(task, exc);
        !           166:  out:
        !           167:        sched_unlock();
        !           168:        return err;
        !           169: }
        !           170:
        !           171: /*
        !           172:  * exception_post-- the internal version of exception_raise().
        !           173:  */
        !           174: int
        !           175: exception_post(task_t task, int exc)
        !           176: {
        !           177:        list_t head, n;
        !           178:        thread_t th;
        !           179:
        !           180:        if (exc < 0 || exc >= NEXC)
        !           181:                return EINVAL;
        !           182:
        !           183:        /*
        !           184:         * Determine which thread should we send an exception.
        !           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.
        !           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);
        !           193:                if (th->slpevt == &exception_event)
        !           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();
        !           204:        th->excbits |= (1 << exc);
        !           205:        irq_unlock();
        !           206:
        !           207:        /*
        !           208:         * Wakeup the target thread regardless of its
        !           209:         * waiting event.
        !           210:         */
        !           211:        sched_unsleep(th, SLP_INTR);
        !           212:
        !           213:        return 0;
        !           214: }
        !           215:
        !           216: /*
        !           217:  * exception_wait - block a current thread until some exceptions
        !           218:  * are raised to the current thread.
        !           219:  *
        !           220:  * The routine returns EINTR on success.
        !           221:  */
        !           222: int
        !           223: exception_wait(int *exc)
        !           224: {
        !           225:        task_t self = cur_task();
        !           226:        int i, rc;
        !           227:
        !           228:        self = cur_task();
        !           229:        if (self->handler == NULL)
        !           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();
        !           245:        for (i = 0; i < NEXC; i++) {
        !           246:                if (cur_thread->excbits & (1 << i))
        !           247:                        break;
        !           248:        }
        !           249:        irq_unlock();
        !           250:        ASSERT(i != NEXC);
        !           251:        sched_unlock();
        !           252:
        !           253:        if (umem_copyout(&i, exc, sizeof(i)))
        !           254:                return EFAULT;
        !           255:        return EINTR;
        !           256: }
        !           257:
        !           258: /*
        !           259:  * Mark an exception flag for the current thread.
        !           260:  *
        !           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.
        !           265:  */
        !           266: void
        !           267: exception_mark(int exc)
        !           268: {
        !           269:        ASSERT(exc > 0 && exc < NEXC);
        !           270:
        !           271:        /* Mark pending bit */
        !           272:        irq_lock();
        !           273:        cur_thread->excbits |= (1 << exc);
        !           274:        irq_unlock();
        !           275: }
        !           276:
        !           277: /*
        !           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.
        !           287:  */
        !           288: void
        !           289: exception_deliver(void)
        !           290: {
        !           291:        thread_t th = cur_thread;
        !           292:        task_t self = cur_task();
        !           293:        void (*handler)(int);
        !           294:        uint32_t bitmap;
        !           295:        int exc;
        !           296:
        !           297:        sched_lock();
        !           298:        irq_lock();
        !           299:        bitmap = th->excbits;
        !           300:        irq_unlock();
        !           301:
        !           302:        if (bitmap != 0) {
        !           303:                /*
        !           304:                 * Find a pending exception.
        !           305:                 */
        !           306:                for (exc = 0; exc < NEXC; exc++) {
        !           307:                        if (bitmap & (1 << exc))
        !           308:                                break;
        !           309:                }
        !           310:                handler = self->handler;
        !           311:                if (handler == NULL) {
        !           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:
        !           318:                        task_terminate(self);
        !           319:                        goto out;
        !           320:                }
        !           321:                /*
        !           322:                 * Transfer control to an exception handler.
        !           323:                 */
        !           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);
        !           327:
        !           328:                irq_lock();
        !           329:                th->excbits &= ~(1 << exc);
        !           330:                irq_unlock();
        !           331:        }
        !           332:  out:
        !           333:        sched_unlock();
        !           334: }
        !           335:
        !           336: /*
        !           337:  * exception_return() is called from exception handler to
        !           338:  * restore the original context.
        !           339:  */
        !           340: int
        !           341: exception_return(void)
        !           342: {
        !           343:
        !           344:        context_restore(&cur_thread->ctx);
        !           345:        return 0;
        !           346: }
        !           347:
        !           348: void
        !           349: exception_init(void)
        !           350: {
        !           351:
        !           352:        event_init(&exception_event, "exception");
        !           353: }

CVSweb