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 }