root/kern/arch/mips/locore/exception-mips1.S

/* [<][>][^][v][top][bottom][index][help] */
   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 <kern/mips/regdefs.h>
  31 #include <mips/specialreg.h>
  32 
  33 /*
  34  * Entry points for exceptions.
  35  *
  36  * MIPS-1 (r2000/r3000) style exception handling, with the "rfe"
  37  * instruction rather than "eret", and the three sets of status bits.
  38  */
  39 
  40 
  41    /* 
  42     * Do not allow the assembler to use $1 (at), because we need to be
  43     * able to save it.
  44     */
  45    .set noat
  46    .set noreorder
  47 
  48 /*
  49  * UTLB exception handler.
  50  *
  51  * This code is copied to address 0x80000000, where the MIPS processor
  52  * automatically invokes it.
  53  *   
  54  * To avoid colliding with the other exception code, it must not
  55  * exceed 128 bytes (32 instructions).
  56  *
  57  * This is the special entry point for the fast-path TLB refill for
  58  * faults in the user address space. We don't implement fast-path TLB
  59  * refill by default. Note that if you do, you either need to make
  60  * sure the refill code doesn't fault or write extra code in
  61  * common_exception to tidy up after such faults.
  62  */
  63 
  64    .text
  65    .globl mips_utlb_handler
  66    .type mips_utlb_handler,@function
  67    .ent mips_utlb_handler
  68 mips_utlb_handler:
  69    j common_exception           /* Don't need to do anything special */
  70    nop                          /* Delay slot */
  71    .globl mips_utlb_end
  72 mips_utlb_end:
  73    .end mips_utlb_handler
  74 
  75 /*
  76  * General exception handler.
  77  *
  78  * This code is copied to address 0x80000080, where
  79  * the MIPS processor automatically invokes it.
  80  */
  81       
  82    .text
  83    .globl mips_general_handler
  84    .type mips_general_handler,@function
  85    .ent mips_general_handler
  86 mips_general_handler:
  87    j common_exception           /* Don't need to do anything special */
  88    nop                          /* Delay slot */
  89    .globl mips_general_end
  90 mips_general_end:
  91    .end mips_general_handler
  92 
  93    /* This keeps gdb from conflating common_exception and mips_general_end */
  94    nop                          /* padding */
  95 
  96 
  97 /*
  98  * Shared exception code for both handlers.
  99  */
 100    
 101    .text
 102    .type common_exception,@function
 103    .ent common_exception
 104 common_exception:       
 105    mfc0 k0, c0_status           /* Get status register */
 106    andi k0, k0, CST_KUp         /* Check the we-were-in-user-mode bit */
 107    beq  k0, $0, 1f              /* If clear, from kernel, already have stack */
 108    nop                          /* delay slot */
 109 
 110    /* Coming from user mode - find kernel stack */
 111    mfc0 k1, c0_context          /* we keep the CPU number here */
 112    srl k1, k1, CTX_PTBASESHIFT  /* shift it to get just the CPU number */
 113    sll k1, k1, 2                /* shift it back to make an array index */
 114    lui k0, %hi(cpustacks)       /* get base address of cpustacks[] */
 115    addu k0, k0, k1              /* index it */
 116    move k1, sp                  /* Save previous stack pointer in k1 */
 117    b 2f                         /* Skip to common code */
 118    lw sp, %lo(cpustacks)(k0)    /* Load kernel stack pointer (in delay slot) */
 119 1:
 120    /* Coming from kernel mode - just save previous stuff */
 121    move k1, sp                  /* Save previous stack in k1 (delay slot) */
 122 2:
 123    /*
 124     * At this point:
 125     *      Interrupts are off. (The processor did this for us.)
 126     *      k0 contains the value for curthread, to go into s7.
 127     *      k1 contains the old stack pointer.
 128     *      sp points into the kernel stack.
 129     *      All other registers are untouched.
 130     */
 131    
 132    /*
 133     * Allocate stack space for 37 words to hold the trap frame,
 134     * plus four more words for a minimal argument block, plus
 135     * one more for proper (64-bit) stack alignment.
 136     */
 137    addi sp, sp, -168
 138 
 139    /* 
 140     * Save general registers.
 141     * We exclude k0/k1, which the kernel is free to clobber (and which
 142     * we already have clobbered), and $0, whose value is fixed.
 143     *
 144     * The order here must match mips/include/trapframe.h.
 145     *
 146     * gdb disassembles this code to try to figure out what registers
 147     * are where, and it isn't very bright. So in order to make gdb be
 148     * able to trace the stack back through here, we play some silly
 149     * games.
 150     *
 151     * In particular:
 152     *    (1) We store the return address register into the epc slot,
 153     *        which makes gdb think it's the return address slot. Then
 154     *        we store the real epc value over that.
 155     *    (2) We store the current sp into the sp slot, which makes gdb
 156     *        think it's the stack pointer slot. Then we store the real
 157     *        value.
 158     *    (3) gdb also assumes that saved registers in a function are
 159     *        saved in order. This is why we put epc where it is, and
 160     *        handle the real value of ra afterwards.
 161     *    (4) Because gdb will think we're saving k0 and k1, we need to
 162     *        leave slots for them in the trap frame, even though the
 163     *        stuff we save there is useless.
 164     *
 165     * This logic has not been tested against a recent gdb and has
 166     * probably bitrotted. Someone(TM) should figure out what gdb
 167     * currently expects -- or maybe even patch gdb to understand a
 168     * better form of this that doesn't waste so many cycles.
 169     */
 170    sw ra, 160(sp)       /* dummy for gdb */
 171    sw s8, 156(sp)       /* save s8 */
 172    sw sp, 152(sp)       /* dummy for gdb */
 173    sw gp, 148(sp)       /* save gp */
 174    sw k1, 144(sp)       /* dummy for gdb */
 175    sw k0, 140(sp)       /* dummy for gdb */
 176 
 177    sw k1, 152(sp)       /* real saved sp */
 178    nop                  /* delay slot for store */
 179    
 180    mfc0 k1, c0_epc      /* Copr.0 reg 13 == PC for exception */
 181    sw k1, 160(sp)       /* real saved PC */
 182 
 183    sw t9, 136(sp)
 184    sw t8, 132(sp)
 185    sw s7, 128(sp)
 186    sw s6, 124(sp)
 187    sw s5, 120(sp)
 188    sw s4, 116(sp)
 189    sw s3, 112(sp)
 190    sw s2, 108(sp)
 191    sw s1, 104(sp)
 192    sw s0, 100(sp)
 193    sw t7, 96(sp)
 194    sw t6, 92(sp)
 195    sw t5, 88(sp)
 196    sw t4, 84(sp)
 197    sw t3, 80(sp)
 198    sw t2, 76(sp)
 199    sw t1, 72(sp)
 200    sw t0, 68(sp)
 201    sw a3, 64(sp)
 202    sw a2, 60(sp)
 203    sw a1, 56(sp)
 204    sw a0, 52(sp)
 205    sw v1, 48(sp)
 206    sw v0, 44(sp)
 207    sw AT, 40(sp)
 208 
 209    sw ra, 36(sp)
 210 
 211    /*
 212     * Save special registers.
 213     */
 214    mfhi t0
 215    mflo t1
 216    sw t0, 32(sp)
 217    sw t1, 28(sp)
 218 
 219    /*
 220     * Save remaining exception context information.
 221     */
 222 
 223    mfc0 t2, c0_status            /* Copr.0 reg 11 == status */
 224    sw   t2, 20(sp)
 225    mfc0 t3, c0_vaddr             /* Copr.0 reg 8 == faulting vaddr */
 226    sw   t3, 16(sp)
 227    mfc0 t4, c0_cause
 228    sw   t4, 24(sp)               /* Copr.0 reg 13 == exception cause */
 229 
 230    /*
 231     * Pretend to save $0 for gdb's benefit.
 232     */
 233    sw $0, 12(sp)
 234 
 235    /*
 236     * Load the curthread register if coming from user mode.
 237     */
 238    andi k0, t2, CST_KUp         /* Check the we-were-in-user-mode bit */
 239    beq  k0, $0, 3f              /* If clear, were in kernel, skip ahead */
 240    nop                          /* delay slot */
 241 
 242    mfc0 k1, c0_context          /* we keep the CPU number here */
 243    srl k1, k1, CTX_PTBASESHIFT  /* shift it to get just the CPU number */
 244    sll k1, k1, 2                /* shift it back to make an array index */
 245    lui k0, %hi(cputhreads)      /* get base address of cputhreads[] */
 246    addu k0, k0, k1              /* index it */
 247    lw s7, %lo(cputhreads)(k0)   /* Load curthread value */
 248 3:
 249 
 250    /*
 251     * Load the kernel GP value.
 252     */
 253    la gp, _gp
 254 
 255    /*
 256     * Prepare to call mips_trap(struct trapframe *)
 257     */
 258 
 259    addiu a0, sp, 16             /* set argument - pointer to the trapframe */
 260    jal mips_trap                /* call it */
 261    nop                          /* delay slot */
 262 
 263    /* Something must be here or gdb doesn't find the stack frame. */
 264    nop
 265    
 266    /*
 267     * Now restore stuff and return from the exception.
 268     * Interrupts should be off.
 269     */
 270 exception_return:
 271 
 272    /*     16(sp)                   no need to restore tf_vaddr */
 273    lw t0, 20(sp)                /* load status register value into t0 */
 274    nop                          /* load delay slot */
 275    mtc0 t0, c0_status           /* store it back to coprocessor 0 */
 276    /*     24(sp)                   no need to restore tf_cause */
 277 
 278    /* restore special registers */
 279    lw t1, 28(sp)
 280    lw t0, 32(sp)
 281    mtlo t1
 282    mthi t0
 283 
 284    /* load the general registers */
 285    lw ra, 36(sp)
 286 
 287    lw AT, 40(sp)
 288    lw v0, 44(sp)
 289    lw v1, 48(sp)
 290    lw a0, 52(sp)
 291    lw a1, 56(sp)
 292    lw a2, 60(sp)
 293    lw a3, 64(sp)
 294    lw t0, 68(sp)
 295    lw t1, 72(sp)
 296    lw t2, 76(sp)
 297    lw t3, 80(sp)
 298    lw t4, 84(sp)
 299    lw t5, 88(sp)
 300    lw t6, 92(sp)
 301    lw t7, 96(sp)
 302    lw s0, 100(sp)
 303    lw s1, 104(sp)
 304    lw s2, 108(sp)
 305    lw s3, 112(sp)
 306    lw s4, 116(sp)
 307    lw s5, 120(sp)
 308    lw s6, 124(sp)
 309    lw s7, 128(sp)
 310    lw t8, 132(sp)
 311    lw t9, 136(sp)
 312 
 313    /*     140(sp)                  "saved" k0 was dummy garbage anyway */
 314    /*     144(sp)                  "saved" k1 was dummy garbage anyway */
 315 
 316    lw gp, 148(sp)               /* restore gp */
 317    /*     152(sp)                  stack pointer - below */
 318    lw s8, 156(sp)               /* restore s8 */
 319    lw k0, 160(sp)               /* fetch exception return PC into k0 */
 320 
 321    lw sp, 152(sp)               /* fetch saved sp (must be last) */
 322    
 323    /* done */
 324    jr k0                        /* jump back */
 325    rfe                          /* in delay slot */
 326    .end common_exception 
 327 
 328 /*
 329  * Code to enter user mode for the first time.
 330  * Does not return.
 331  *
 332  * This is called from mips_usermode().
 333  * Interrupts on this processor should be off.
 334  */
 335 
 336    .text
 337    .globl asm_usermode
 338    .type asm_usermode,@function
 339    .ent asm_usermode
 340 asm_usermode:
 341    /*
 342     * a0 is the address of a trapframe to use for exception "return".
 343     * It's allocated on our stack.
 344     *
 345     * Move it to the stack pointer - we don't need the actual stack
 346     * position any more. (When we come back from usermode, cpustacks[]
 347     * will be used to reinitialize our stack pointer, and that was
 348     * set by mips_usermode.)
 349     *
 350     * Then just jump to the exception return code above.
 351     */
 352 
 353    j exception_return
 354    addiu sp, a0, -16            /* in delay slot */
 355    .end asm_usermode

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