Path: blob/master/kern/arch/mips/locore/exception-mips1.S
2127 views
/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <kern/mips/regdefs.h>30#include <mips/specialreg.h>3132/*33* Entry points for exceptions.34*35* MIPS-1 (r2000/r3000) style exception handling, with the "rfe"36* instruction rather than "eret", and the three sets of status bits.37*/383940/*41* Do not allow the assembler to use $1 (at), because we need to be42* able to save it.43*/44.set noat45.set noreorder4647/*48* UTLB exception handler.49*50* This code is copied to address 0x80000000, where the MIPS processor51* automatically invokes it.52*53* To avoid colliding with the other exception code, it must not54* exceed 128 bytes (32 instructions).55*56* This is the special entry point for the fast-path TLB refill for57* faults in the user address space. We don't implement fast-path TLB58* refill by default. Note that if you do, you either need to make59* sure the refill code doesn't fault or write extra code in60* common_exception to tidy up after such faults.61*/6263.text64.globl mips_utlb_handler65.type mips_utlb_handler,@function66.ent mips_utlb_handler67mips_utlb_handler:68j common_exception /* Don't need to do anything special */69nop /* Delay slot */70.globl mips_utlb_end71mips_utlb_end:72.end mips_utlb_handler7374/*75* General exception handler.76*77* This code is copied to address 0x80000080, where78* the MIPS processor automatically invokes it.79*/8081.text82.globl mips_general_handler83.type mips_general_handler,@function84.ent mips_general_handler85mips_general_handler:86j common_exception /* Don't need to do anything special */87nop /* Delay slot */88.globl mips_general_end89mips_general_end:90.end mips_general_handler9192/* This keeps gdb from conflating common_exception and mips_general_end */93nop /* padding */949596/*97* Shared exception code for both handlers.98*/99100.text101.type common_exception,@function102.ent common_exception103common_exception:104mfc0 k0, c0_status /* Get status register */105andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */106beq k0, $0, 1f /* If clear, from kernel, already have stack */107nop /* delay slot */108109/* Coming from user mode - find kernel stack */110mfc0 k1, c0_context /* we keep the CPU number here */111srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */112sll k1, k1, 2 /* shift it back to make an array index */113lui k0, %hi(cpustacks) /* get base address of cpustacks[] */114addu k0, k0, k1 /* index it */115move k1, sp /* Save previous stack pointer in k1 */116b 2f /* Skip to common code */117lw sp, %lo(cpustacks)(k0) /* Load kernel stack pointer (in delay slot) */1181:119/* Coming from kernel mode - just save previous stuff */120move k1, sp /* Save previous stack in k1 (delay slot) */1212:122/*123* At this point:124* Interrupts are off. (The processor did this for us.)125* k0 contains the value for curthread, to go into s7.126* k1 contains the old stack pointer.127* sp points into the kernel stack.128* All other registers are untouched.129*/130131/*132* Allocate stack space for 37 words to hold the trap frame,133* plus four more words for a minimal argument block, plus134* one more for proper (64-bit) stack alignment.135*/136addi sp, sp, -168137138/*139* Save general registers.140* We exclude k0/k1, which the kernel is free to clobber (and which141* we already have clobbered), and $0, whose value is fixed.142*143* The order here must match mips/include/trapframe.h.144*145* gdb disassembles this code to try to figure out what registers146* are where, and it isn't very bright. So in order to make gdb be147* able to trace the stack back through here, we play some silly148* games.149*150* In particular:151* (1) We store the return address register into the epc slot,152* which makes gdb think it's the return address slot. Then153* we store the real epc value over that.154* (2) We store the current sp into the sp slot, which makes gdb155* think it's the stack pointer slot. Then we store the real156* value.157* (3) gdb also assumes that saved registers in a function are158* saved in order. This is why we put epc where it is, and159* handle the real value of ra afterwards.160* (4) Because gdb will think we're saving k0 and k1, we need to161* leave slots for them in the trap frame, even though the162* stuff we save there is useless.163*164* This logic has not been tested against a recent gdb and has165* probably bitrotted. Someone(TM) should figure out what gdb166* currently expects -- or maybe even patch gdb to understand a167* better form of this that doesn't waste so many cycles.168*/169sw ra, 160(sp) /* dummy for gdb */170sw s8, 156(sp) /* save s8 */171sw sp, 152(sp) /* dummy for gdb */172sw gp, 148(sp) /* save gp */173sw k1, 144(sp) /* dummy for gdb */174sw k0, 140(sp) /* dummy for gdb */175176sw k1, 152(sp) /* real saved sp */177nop /* delay slot for store */178179mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */180sw k1, 160(sp) /* real saved PC */181182sw t9, 136(sp)183sw t8, 132(sp)184sw s7, 128(sp)185sw s6, 124(sp)186sw s5, 120(sp)187sw s4, 116(sp)188sw s3, 112(sp)189sw s2, 108(sp)190sw s1, 104(sp)191sw s0, 100(sp)192sw t7, 96(sp)193sw t6, 92(sp)194sw t5, 88(sp)195sw t4, 84(sp)196sw t3, 80(sp)197sw t2, 76(sp)198sw t1, 72(sp)199sw t0, 68(sp)200sw a3, 64(sp)201sw a2, 60(sp)202sw a1, 56(sp)203sw a0, 52(sp)204sw v1, 48(sp)205sw v0, 44(sp)206sw AT, 40(sp)207208sw ra, 36(sp)209210/*211* Save special registers.212*/213mfhi t0214mflo t1215sw t0, 32(sp)216sw t1, 28(sp)217218/*219* Save remaining exception context information.220*/221222mfc0 t2, c0_status /* Copr.0 reg 11 == status */223sw t2, 20(sp)224mfc0 t3, c0_vaddr /* Copr.0 reg 8 == faulting vaddr */225sw t3, 16(sp)226mfc0 t4, c0_cause227sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */228229/*230* Pretend to save $0 for gdb's benefit.231*/232sw $0, 12(sp)233234/*235* Load the curthread register if coming from user mode.236*/237andi k0, t2, CST_KUp /* Check the we-were-in-user-mode bit */238beq k0, $0, 3f /* If clear, were in kernel, skip ahead */239nop /* delay slot */240241mfc0 k1, c0_context /* we keep the CPU number here */242srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */243sll k1, k1, 2 /* shift it back to make an array index */244lui k0, %hi(cputhreads) /* get base address of cputhreads[] */245addu k0, k0, k1 /* index it */246lw s7, %lo(cputhreads)(k0) /* Load curthread value */2473:248249/*250* Load the kernel GP value.251*/252la gp, _gp253254/*255* Prepare to call mips_trap(struct trapframe *)256*/257258addiu a0, sp, 16 /* set argument - pointer to the trapframe */259jal mips_trap /* call it */260nop /* delay slot */261262/* Something must be here or gdb doesn't find the stack frame. */263nop264265/*266* Now restore stuff and return from the exception.267* Interrupts should be off.268*/269exception_return:270271/* 16(sp) no need to restore tf_vaddr */272lw t0, 20(sp) /* load status register value into t0 */273nop /* load delay slot */274mtc0 t0, c0_status /* store it back to coprocessor 0 */275/* 24(sp) no need to restore tf_cause */276277/* restore special registers */278lw t1, 28(sp)279lw t0, 32(sp)280mtlo t1281mthi t0282283/* load the general registers */284lw ra, 36(sp)285286lw AT, 40(sp)287lw v0, 44(sp)288lw v1, 48(sp)289lw a0, 52(sp)290lw a1, 56(sp)291lw a2, 60(sp)292lw a3, 64(sp)293lw t0, 68(sp)294lw t1, 72(sp)295lw t2, 76(sp)296lw t3, 80(sp)297lw t4, 84(sp)298lw t5, 88(sp)299lw t6, 92(sp)300lw t7, 96(sp)301lw s0, 100(sp)302lw s1, 104(sp)303lw s2, 108(sp)304lw s3, 112(sp)305lw s4, 116(sp)306lw s5, 120(sp)307lw s6, 124(sp)308lw s7, 128(sp)309lw t8, 132(sp)310lw t9, 136(sp)311312/* 140(sp) "saved" k0 was dummy garbage anyway */313/* 144(sp) "saved" k1 was dummy garbage anyway */314315lw gp, 148(sp) /* restore gp */316/* 152(sp) stack pointer - below */317lw s8, 156(sp) /* restore s8 */318lw k0, 160(sp) /* fetch exception return PC into k0 */319320lw sp, 152(sp) /* fetch saved sp (must be last) */321322/* done */323jr k0 /* jump back */324rfe /* in delay slot */325.end common_exception326327/*328* Code to enter user mode for the first time.329* Does not return.330*331* This is called from mips_usermode().332* Interrupts on this processor should be off.333*/334335.text336.globl asm_usermode337.type asm_usermode,@function338.ent asm_usermode339asm_usermode:340/*341* a0 is the address of a trapframe to use for exception "return".342* It's allocated on our stack.343*344* Move it to the stack pointer - we don't need the actual stack345* position any more. (When we come back from usermode, cpustacks[]346* will be used to reinitialize our stack pointer, and that was347* set by mips_usermode.)348*349* Then just jump to the exception return code above.350*/351352j exception_return353addiu sp, a0, -16 /* in delay slot */354.end asm_usermode355356357