root/kern/arch/mips/locore/trap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. kill_curthread
  2. mips_trap
  3. mips_usermode
  4. enter_new_process

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   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 University nor the names of its 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 UNIVERSITY 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 UNIVERSITY 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 #include <types.h>
  31 #include <signal.h>
  32 #include <lib.h>
  33 #include <mips/specialreg.h>
  34 #include <mips/trapframe.h>
  35 #include <cpu.h>
  36 #include <spl.h>
  37 #include <thread.h>
  38 #include <current.h>
  39 #include <vm.h>
  40 #include <mainbus.h>
  41 #include <syscall.h>
  42 
  43 
  44 /* in exception.S */
  45 extern void asm_usermode(struct trapframe *tf);
  46 
  47 /* called only from assembler, so not declared in a header */
  48 void mips_trap(struct trapframe *tf);
  49 
  50 
  51 /* Names for trap codes */
  52 #define NTRAPCODES 13
  53 static const char *const trapcodenames[NTRAPCODES] = {
  54         "Interrupt",
  55         "TLB modify trap",
  56         "TLB miss on load",
  57         "TLB miss on store",
  58         "Address error on load",
  59         "Address error on store",
  60         "Bus error on code",
  61         "Bus error on data",
  62         "System call",
  63         "Break instruction",
  64         "Illegal instruction",
  65         "Coprocessor unusable",
  66         "Arithmetic overflow",
  67 };
  68 
  69 /*
  70  * Function called when user-level code hits a fatal fault.
  71  */
  72 static
  73 void
  74 kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
  75 {
  76         int sig = 0;
  77 
  78         KASSERT(code < NTRAPCODES);
  79         switch (code) {
  80             case EX_IRQ:
  81             case EX_IBE:
  82             case EX_DBE:
  83             case EX_SYS:
  84                 /* should not be seen */
  85                 KASSERT(0);
  86                 sig = SIGABRT;
  87                 break;
  88             case EX_MOD:
  89             case EX_TLBL:
  90             case EX_TLBS:
  91                 sig = SIGSEGV;
  92                 break;
  93             case EX_ADEL:
  94             case EX_ADES:
  95                 sig = SIGBUS;
  96                 break;
  97             case EX_BP:
  98                 sig = SIGTRAP;
  99                 break;
 100             case EX_RI:
 101                 sig = SIGILL;
 102                 break;
 103             case EX_CPU:
 104                 sig = SIGSEGV;
 105                 break;
 106             case EX_OVF:
 107                 sig = SIGFPE;
 108                 break;
 109         }
 110 
 111         /*
 112          * You will probably want to change this.
 113          */
 114 
 115         kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
 116                 code, sig, trapcodenames[code], epc, vaddr);
 117         panic("I don't know how to handle this\n");
 118 }
 119 
 120 /*
 121  * General trap (exception) handling function for mips.
 122  * This is called by the assembly-language exception handler once
 123  * the trapframe has been set up.
 124  */
 125 void
 126 mips_trap(struct trapframe *tf)
 127 {
 128         uint32_t code;
 129         bool isutlb, iskern;
 130         int spl;
 131 
 132         /* The trap frame is supposed to be 37 registers long. */
 133         KASSERT(sizeof(struct trapframe)==(37*4));
 134 
 135         /*
 136          * Extract the exception code info from the register fields.
 137          */
 138         code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT;
 139         isutlb = (tf->tf_cause & CCA_UTLB) != 0;
 140         iskern = (tf->tf_status & CST_KUp) == 0;
 141 
 142         KASSERT(code < NTRAPCODES);
 143 
 144         /* Make sure we haven't run off our stack */
 145         if (curthread != NULL && curthread->t_stack != NULL) {
 146                 KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack);
 147                 KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack
 148                                                 + STACK_SIZE));
 149         }
 150 
 151         /* Interrupt? Call the interrupt handler and return. */
 152         if (code == EX_IRQ) {
 153                 int old_in;
 154                 bool doadjust;
 155 
 156                 old_in = curthread->t_in_interrupt;
 157                 curthread->t_in_interrupt = 1;
 158 
 159                 /*
 160                  * The processor has turned interrupts off; if the
 161                  * currently recorded interrupt state is interrupts on
 162                  * (spl of 0), adjust the recorded state to match, and
 163                  * restore after processing the interrupt.
 164                  *
 165                  * How can we get an interrupt if the recorded state
 166                  * is interrupts off? Well, as things currently stand
 167                  * when the CPU finishes idling it flips interrupts on
 168                  * and off to allow things to happen, but leaves
 169                  * curspl high while doing so.
 170                  *
 171                  * While we're here, assert that the interrupt
 172                  * handling code hasn't leaked a spinlock or an
 173                  * splhigh().
 174                  */
 175 
 176                 if (curthread->t_curspl == 0) {
 177                         KASSERT(curthread->t_curspl == 0);
 178                         KASSERT(curthread->t_iplhigh_count == 0);
 179                         curthread->t_curspl = IPL_HIGH;
 180                         curthread->t_iplhigh_count++;
 181                         doadjust = true;
 182                 }
 183                 else {
 184                         doadjust = false;
 185                 }
 186 
 187                 mainbus_interrupt(tf);
 188 
 189                 if (doadjust) {
 190                         KASSERT(curthread->t_curspl == IPL_HIGH);
 191                         KASSERT(curthread->t_iplhigh_count == 1);
 192                         curthread->t_iplhigh_count--;
 193                         curthread->t_curspl = 0;
 194                 }
 195 
 196                 curthread->t_in_interrupt = old_in;
 197                 goto done2;
 198         }
 199 
 200         /*
 201          * The processor turned interrupts off when it took the trap.
 202          *
 203          * While we're in the kernel, and not actually handling an
 204          * interrupt, restore the interrupt state to where it was in
 205          * the previous context, which may be low (interrupts on).
 206          *
 207          * Do this by forcing splhigh(), which may do a redundant
 208          * cpu_irqoff() but forces the stored MI interrupt state into
 209          * sync, then restoring the previous state.
 210          */
 211         spl = splhigh();
 212         splx(spl);
 213 
 214         /* Syscall? Call the syscall handler and return. */
 215         if (code == EX_SYS) {
 216                 /* Interrupts should have been on while in user mode. */
 217                 KASSERT(curthread->t_curspl == 0);
 218                 KASSERT(curthread->t_iplhigh_count == 0);
 219 
 220                 DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", 
 221                       tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3);
 222 
 223                 syscall(tf);
 224                 goto done;
 225         }
 226 
 227         /*
 228          * Ok, it wasn't any of the really easy cases.
 229          * Call vm_fault on the TLB exceptions.
 230          * Panic on the bus error exceptions.
 231          */
 232         switch (code) {
 233         case EX_MOD:
 234                 if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) {
 235                         goto done;
 236                 }
 237                 break;
 238         case EX_TLBL:
 239                 if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) {
 240                         goto done;
 241                 }
 242                 break;
 243         case EX_TLBS:
 244                 if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) {
 245                         goto done;
 246                 }
 247                 break;
 248         case EX_IBE:
 249         case EX_DBE:
 250                 /*
 251                  * This means you loaded invalid TLB entries, or 
 252                  * touched invalid parts of the direct-mapped 
 253                  * segments. These are serious kernel errors, so
 254                  * panic.
 255                  * 
 256                  * The MIPS won't even tell you what invalid address
 257                  * caused the bus error.
 258                  */
 259                 panic("Bus error exception, PC=0x%x\n", tf->tf_epc);
 260                 break;
 261         }
 262 
 263         /*
 264          * If we get to this point, it's a fatal fault - either it's
 265          * one of the other exceptions, like illegal instruction, or
 266          * it was a page fault we couldn't handle.
 267          */
 268 
 269         if (!iskern) {
 270                 /*
 271                  * Fatal fault in user mode.
 272                  * Kill the current user process.
 273                  */
 274                 kill_curthread(tf->tf_epc, code, tf->tf_vaddr);
 275                 goto done;
 276         }
 277 
 278         /*
 279          * Fatal fault in kernel mode.
 280          *
 281          * If pcb_badfaultfunc is set, we do not panic; badfaultfunc is
 282          * set by copyin/copyout and related functions to signify that
 283          * the addresses they're accessing are userlevel-supplied and
 284          * not trustable. What we actually want to do is resume
 285          * execution at the function pointed to by badfaultfunc. That's 
 286          * going to be "copyfail" (see copyinout.c), which longjmps 
 287          * back to copyin/copyout or wherever and returns EFAULT.
 288          *
 289          * Note that we do not just *call* this function, because that
 290          * won't necessarily do anything. We want the control flow
 291          * that is currently executing in copyin (or whichever), and
 292          * is stopped while we process the exception, to *teleport* to
 293          * copyfail.
 294          *
 295          * This is accomplished by changing tf->tf_epc and returning
 296          * from the exception handler.
 297          */
 298 
 299         if (curthread != NULL &&
 300             curthread->t_machdep.tm_badfaultfunc != NULL) {
 301                 tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc;
 302                 goto done;
 303         }
 304 
 305         /*
 306          * Really fatal kernel-mode fault.
 307          */
 308 
 309         kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code,
 310                 trapcodenames[code]);
 311         kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", 
 312                 tf->tf_epc, tf->tf_vaddr);
 313 
 314         panic("I can't handle this... I think I'll just die now...\n");
 315 
 316  done:
 317         /*
 318          * Turn interrupts off on the processor, without affecting the
 319          * stored interrupt state.
 320          */
 321         cpu_irqoff();
 322  done2:
 323 
 324         /*
 325          * The boot thread can get here (e.g. on interrupt return) but
 326          * since it doesn't go to userlevel, it can't be returning to
 327          * userlevel, so there's no need to set cputhreads[] and
 328          * cpustacks[]. Just return.
 329          */
 330         if (curthread->t_stack == NULL) {
 331                 return;
 332         }
 333 
 334         cputhreads[curcpu->c_number] = (vaddr_t)curthread;
 335         cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
 336 
 337         /*
 338          * This assertion will fail if either
 339          *   (1) curthread->t_stack is corrupted, or
 340          *   (2) the trap frame is somehow on the wrong kernel stack.
 341          *
 342          * If cpustacks[] is corrupted, the next trap back to the
 343          * kernel will (most likely) hang the system, so it's better
 344          * to find out now.
 345          */
 346         KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
 347 }
 348 
 349 /*
 350  * Function for entering user mode.
 351  *
 352  * This should not be used by threads returning from traps - they
 353  * should just return from mips_trap(). It should be used by threads
 354  * entering user mode for the first time - whether the child thread in
 355  * a fork(), or into a brand-new address space after exec(), or when
 356  * starting the first userlevel program.
 357  *
 358  * It works by jumping into the exception return code.
 359  *
 360  * mips_usermode is common code for this. It cannot usefully be called
 361  * outside the mips port, but should be called from one of the
 362  * following places:
 363  *    - enter_new_process, for use by exec and equivalent.
 364  *    - enter_forked_process, in syscall.c, for use by fork.
 365  */
 366 void
 367 mips_usermode(struct trapframe *tf)
 368 {
 369 
 370         /*
 371          * Interrupts should be off within the kernel while entering
 372          * user mode. However, while in user mode, interrupts should
 373          * be on. To interact properly with the spl-handling logic
 374          * above, we explicitly call spl0() and then call cpu_irqoff().
 375          */
 376         spl0();
 377         cpu_irqoff();
 378 
 379         cputhreads[curcpu->c_number] = (vaddr_t)curthread;
 380         cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE;
 381 
 382         /*
 383          * This assertion will fail if either
 384          *   (1) cpustacks[] is corrupted, or
 385          *   (2) the trap frame is not on our own kernel stack, or
 386          *   (3) the boot thread tries to enter user mode.
 387          *
 388          * If cpustacks[] is corrupted, the next trap back to the
 389          * kernel will (most likely) hang the system, so it's better
 390          * to find out now.
 391          *
 392          * It's necessary for the trap frame used here to be on the
 393          * current thread's own stack. It cannot correctly be on
 394          * either another thread's stack or in the kernel heap.
 395          * (Exercise: why?)
 396          */
 397         KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf));
 398 
 399         /*
 400          * This actually does it. See exception.S.
 401          */
 402         asm_usermode(tf);
 403 }
 404 
 405 /*
 406  * enter_new_process: go to user mode after loading an executable.
 407  *
 408  * Performs the necessary initialization so that the user program will
 409  * get the arguments supplied in argc/argv (note that argv must be a
 410  * user-level address), and begin executing at the specified entry
 411  * point. The stack pointer is initialized from the stackptr
 412  * argument. Note that passing argc/argv may use additional stack
 413  * space on some other platforms (but not on mips).
 414  *
 415  * Works by creating an ersatz trapframe.
 416  */
 417 void
 418 enter_new_process(int argc, userptr_t argv, vaddr_t stack, vaddr_t entry)
 419 {
 420         struct trapframe tf;
 421 
 422         bzero(&tf, sizeof(tf));
 423 
 424         tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp;
 425         tf.tf_epc = entry;
 426         tf.tf_a0 = argc;
 427         tf.tf_a1 = (vaddr_t)argv;
 428         tf.tf_sp = stack;
 429 
 430         mips_usermode(&tf);
 431 }

/* [<][>][^][v][top][bottom][index][help] */