[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     ! 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