os161-1.99
 All Data Structures
trap.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #include <types.h>
00031 #include <signal.h>
00032 #include <lib.h>
00033 #include <mips/specialreg.h>
00034 #include <mips/trapframe.h>
00035 #include <cpu.h>
00036 #include <spl.h>
00037 #include <thread.h>
00038 #include <current.h>
00039 #include <vm.h>
00040 #include <mainbus.h>
00041 #include <syscall.h>
00042 
00043 
00044 /* in exception.S */
00045 extern void asm_usermode(struct trapframe *tf);
00046 
00047 /* called only from assembler, so not declared in a header */
00048 void mips_trap(struct trapframe *tf);
00049 
00050 
00051 /* Names for trap codes */
00052 #define NTRAPCODES 13
00053 static const char *const trapcodenames[NTRAPCODES] = {
00054         "Interrupt",
00055         "TLB modify trap",
00056         "TLB miss on load",
00057         "TLB miss on store",
00058         "Address error on load",
00059         "Address error on store",
00060         "Bus error on code",
00061         "Bus error on data",
00062         "System call",
00063         "Break instruction",
00064         "Illegal instruction",
00065         "Coprocessor unusable",
00066         "Arithmetic overflow",
00067 };
00068 
00069 /*
00070  * Function called when user-level code hits a fatal fault.
00071  */
00072 static
00073 void
00074 kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
00075 {
00076         int sig = 0;
00077 
00078         KASSERT(code < NTRAPCODES);
00079         switch (code) {
00080             case EX_IRQ:
00081             case EX_IBE:
00082             case EX_DBE:
00083             case EX_SYS:
00084                 /* should not be seen */
00085                 KASSERT(0);
00086                 sig = SIGABRT;
00087                 break;
00088             case EX_MOD:
00089             case EX_TLBL:
00090             case EX_TLBS:
00091                 sig = SIGSEGV;
00092                 break;
00093             case EX_ADEL:
00094             case EX_ADES:
00095                 sig = SIGBUS;
00096                 break;
00097             case EX_BP:
00098                 sig = SIGTRAP;
00099                 break;
00100             case EX_RI:
00101                 sig = SIGILL;
00102                 break;
00103             case EX_CPU:
00104                 sig = SIGSEGV;
00105                 break;
00106             case EX_OVF:
00107                 sig = SIGFPE;
00108                 break;
00109         }
00110 
00111         /*
00112          * You will probably want to change this.
00113          */
00114 
00115         kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
00116                 code, sig, trapcodenames[code], epc, vaddr);
00117         panic("I don't know how to handle this\n");
00118 }
00119 
00120 /*
00121  * General trap (exception) handling function for mips.
00122  * This is called by the assembly-language exception handler once
00123  * the trapframe has been set up.
00124  */
00125 void
00126 mips_trap(struct trapframe *tf)
00127 {
00128         uint32_t code;
00129         bool isutlb, iskern;
00130         int spl;
00131 
00132         /* The trap frame is supposed to be 37 registers long. */
00133         KASSERT(sizeof(struct trapframe)==(37*4));
00134 
00135         /*
00136          * Extract the exception code info from the register fields.
00137          */
00138         code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
00139         isutlb = (tf->tf_cause & CCA_UTLB) != 0;
00140         iskern = (tf->tf_status & CST_KUp) == 0;
00141 
00142         KASSERT(code < NTRAPCODES);
00143 
00144         /* Make sure we haven't run off our stack */
00145         if (curthread != NULL && curthread->t_stack != NULL) {
00146                 KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
00147                 KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
00148                                                 + STACK_SIZE));
00149         }
00150 
00151         /* Interrupt? Call the interrupt handler and return. */
00152         if (code == EX_IRQ) {
00153                 int old_in;
00154                 bool doadjust;
00155 
00156                 old_in = curthread->t_in_interrupt;
00157                 curthread->t_in_interrupt = 1;
00158 
00159                 /*
00160                  * The processor has turned interrupts off; if the
00161                  * currently recorded interrupt state is interrupts on
00162                  * (spl of 0), adjust the recorded state to match, and
00163                  * restore after processing the interrupt.
00164                  *
00165                  * How can we get an interrupt if the recorded state
00166                  * is interrupts off? Well, as things currently stand
00167                  * when the CPU finishes idling it flips interrupts on
00168                  * and off to allow things to happen, but leaves
00169                  * curspl high while doing so.
00170                  *
00171                  * While we're here, assert that the interrupt
00172                  * handling code hasn't leaked a spinlock or an
00173                  * splhigh().
00174                  */
00175 
00176                 if (curthread->t_curspl == 0) {
00177                         KASSERT(curthread->t_curspl == 0);
00178                         KASSERT(curthread->t_iplhigh_count == 0);
00179                         curthread->t_curspl = IPL_HIGH;
00180                         curthread->t_iplhigh_count++;
00181                         doadjust = true;
00182                 }
00183                 else {
00184                         doadjust = false;
00185                 }
00186 
00187                 mainbus_interrupt(tf);
00188 
00189                 if (doadjust) {
00190                         KASSERT(curthread->t_curspl == IPL_HIGH);
00191                         KASSERT(curthread->t_iplhigh_count == 1);
00192                         curthread->t_iplhigh_count--;
00193                         curthread->t_curspl = 0;
00194                 }
00195 
00196                 curthread->t_in_interrupt = old_in;
00197                 goto done2;
00198         }
00199 
00200         /*
00201          * The processor turned interrupts off when it took the trap.
00202          *
00203          * While we're in the kernel, and not actually handling an
00204          * interrupt, restore the interrupt state to where it was in
00205          * the previous context, which may be low (interrupts on).
00206          *
00207          * Do this by forcing splhigh(), which may do a redundant
00208          * cpu_irqoff() but forces the stored MI interrupt state into
00209          * sync, then restoring the previous state.
00210          */
00211         spl = splhigh();
00212         splx(spl);
00213 
00214         /* Syscall? Call the syscall handler and return. */
00215         if (code == EX_SYS) {
00216                 /* Interrupts should have been on while in user mode. */
00217                 KASSERT(curthread->t_curspl == 0);
00218                 KASSERT(curthread->t_iplhigh_count == 0);
00219 
00220                 DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", 
00221                       tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
00222 
00223                 syscall(tf);
00224                 goto done;
00225         }
00226 
00227         /*
00228          * Ok, it wasn't any of the really easy cases.
00229          * Call vm_fault on the TLB exceptions.
00230          * Panic on the bus error exceptions.
00231          */
00232         switch (code) {
00233         case EX_MOD:
00234                 if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
00235                         goto done;
00236                 }
00237                 break;
00238         case EX_TLBL:
00239                 if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
00240                         goto done;
00241                 }
00242                 break;
00243         case EX_TLBS:
00244                 if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
00245                         goto done;
00246                 }
00247                 break;
00248         case EX_IBE:
00249         case EX_DBE:
00250                 /*
00251                  * This means you loaded invalid TLB entries, or 
00252                  * touched invalid parts of the direct-mapped 
00253                  * segments. These are serious kernel errors, so
00254                  * panic.
00255                  * 
00256                  * The MIPS won't even tell you what invalid address
00257                  * caused the bus error.
00258                  */
00259                 panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
00260                 break;
00261         }
00262 
00263         /*
00264          * If we get to this point, it's a fatal fault - either it's
00265          * one of the other exceptions, like illegal instruction, or
00266          * it was a page fault we couldn't handle.
00267          */
00268 
00269         if (!iskern) {
00270                 /*
00271                  * Fatal fault in user mode.
00272                  * Kill the current user process.
00273                  */
00274                 kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
00275                 goto done;
00276         }
00277 
00278         /*
00279          * Fatal fault in kernel mode.
00280          *
00281          * If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
00282          * set by copyin/copyout and related functions to signify that
00283          * the addresses they're accessing are userlevel-supplied and
00284          * not trustable. What we actually want to do is resume
00285          * execution at the function pointed to by badfaultfunc. That's 
00286          * going to be "copyfail" (see copyinout.c), which longjmps 
00287          * back to copyin/copyout or wherever and returns EFAULT.
00288          *
00289          * Note that we do not just *call* this function, because that
00290          * won't necessarily do anything. We want the control flow
00291          * that is currently executing in copyin (or whichever), and
00292          * is stopped while we process the exception, to *teleport* to
00293          * copyfail.
00294          *
00295          * This is accomplished by changing tf->tf_epc and returning
00296          * from the exception handler.
00297          */
00298 
00299         if (curthread != NULL &&
00300             curthread->t_machdep.tm_badfaultfunc != NULL) {
00301                 tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
00302                 goto done;
00303         }
00304 
00305         /*
00306          * Really fatal kernel-mode fault.
00307          */
00308 
00309         kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
00310                 trapcodenames[code]);
00311         kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", 
00312                 tf->tf_epc, tf->tf_vaddr);
00313 
00314         panic("I can't handle this... I think I'll just die now...\n");
00315 
00316  done:
00317         /*
00318          * Turn interrupts off on the processor, without affecting the
00319          * stored interrupt state.
00320          */
00321         cpu_irqoff();
00322  done2:
00323 
00324         /*
00325          * The boot thread can get here (e.g. on interrupt return) but
00326          * since it doesn't go to userlevel, it can't be returning to
00327          * userlevel, so there's no need to set cputhreads[] and
00328          * cpustacks[]. Just return.
00329          */
00330         if (curthread->t_stack == NULL) {
00331                 return;
00332         }
00333 
00334         cputhreads[curcpu->c_number] = (vaddr_t)curthread;
00335         cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
00336 
00337         /*
00338          * This assertion will fail if either
00339          *   (1) curthread->t_stack is corrupted, or
00340          *   (2) the trap frame is somehow on the wrong kernel stack.
00341          *
00342          * If cpustacks[] is corrupted, the next trap back to the
00343          * kernel will (most likely) hang the system, so it's better
00344          * to find out now.
00345          */
00346         KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
00347 }
00348 
00349 /*
00350  * Function for entering user mode.
00351  *
00352  * This should not be used by threads returning from traps - they
00353  * should just return from mips_trap(). It should be used by threads
00354  * entering user mode for the first time - whether the child thread in
00355  * a fork(), or into a brand-new address space after exec(), or when
00356  * starting the first userlevel program.
00357  *
00358  * It works by jumping into the exception return code.
00359  *
00360  * mips_usermode is common code for this. It cannot usefully be called
00361  * outside the mips port, but should be called from one of the
00362  * following places:
00363  *    - enter_new_process, for use by exec and equivalent.
00364  *    - enter_forked_process, in syscall.c, for use by fork.
00365  */
00366 void
00367 mips_usermode(struct trapframe *tf)
00368 {
00369 
00370         /*
00371          * Interrupts should be off within the kernel while entering
00372          * user mode. However, while in user mode, interrupts should
00373          * be on. To interact properly with the spl-handling logic
00374          * above, we explicitly call spl0() and then call cpu_irqoff().
00375          */
00376         spl0();
00377         cpu_irqoff();
00378 
00379         cputhreads[curcpu->c_number] = (vaddr_t)curthread;
00380         cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
00381 
00382         /*
00383          * This assertion will fail if either
00384          *   (1) cpustacks[] is corrupted, or
00385          *   (2) the trap frame is not on our own kernel stack, or
00386          *   (3) the boot thread tries to enter user mode.
00387          *
00388          * If cpustacks[] is corrupted, the next trap back to the
00389          * kernel will (most likely) hang the system, so it's better
00390          * to find out now.
00391          *
00392          * It's necessary for the trap frame used here to be on the
00393          * current thread's own stack. It cannot correctly be on
00394          * either another thread's stack or in the kernel heap.
00395          * (Exercise: why?)
00396          */
00397         KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
00398 
00399         /*
00400          * This actually does it. See exception.S.
00401          */
00402         asm_usermode(tf);
00403 }
00404 
00405 /*
00406  * enter_new_process: go to user mode after loading an executable.
00407  *
00408  * Performs the necessary initialization so that the user program will
00409  * get the arguments supplied in argc/argv (note that argv must be a
00410  * user-level address), and begin executing at the specified entry
00411  * point. The stack pointer is initialized from the stackptr
00412  * argument. Note that passing argc/argv may use additional stack
00413  * space on some other platforms (but not on mips).
00414  *
00415  * Works by creating an ersatz trapframe.
00416  */
00417 void
00418 enter_new_process(int argc, userptr_t argv, vaddr_t stack, vaddr_t entry)
00419 {
00420         struct trapframe tf;
00421 
00422         bzero(&tf, sizeof(tf));
00423 
00424         tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
00425         tf.tf_epc = entry;
00426         tf.tf_a0 = argc;
00427         tf.tf_a1 = (vaddr_t)argv;
00428         tf.tf_sp = stack;
00429 
00430         mips_usermode(&tf);
00431 }
 All Data Structures