/* * Copyright (C) 2014-2018 MIPS Tech, LLC * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define _FUNCTION_SECTIONS_ #include #include #include #include #include MIPS_NOMIPS16 /* Stack adjustment for ABI parameter area. */ #define ADJ (NARGSAVE * SZARG) /* * Round the context size up to a 16-byte boundary which is the maximum * stack alignment required for any supported ABI. */ #define CTX_SIZEROUND ((CTX_SIZE + ALSZ) & ALMASK) /* * Exception entry points. These are designed for use at EBASE when * STATUS.BEV is clear. * The entry points will either chain on to a user-supplied function * or loop indefinitely. */ LEAF(__exception_entry) .set push .set noat .weak _mips_tlb_refill _mips_tlb_refill = __exception_save __tlb_refill_loop: /* * Support an alternative entry point at the start of the exception * vector. Since the exception vector is normally placed first * in the link map this allows a user to start execution from the * same address that an executable is loaded to. */ LA k1, __first_boot lw k1, 0(k1) beqz k1, 1f /* * The start code is responsible for clearing __first_boot prior * to installing the exception handlers. */ LA k1, _start jr k1 1: /* Support the case where no handler is defined. */ LA k1, _mips_tlb_refill beqz k1, __tlb_refill_loop jr k1 .org 0x80 .weak _mips_xtlb_refill _mips_xtlb_refill = __exception_save __xtlb_refill_loop: LA k1, _mips_xtlb_refill beqz k1, __xtlb_refill_loop jr k1 .org 0x100 .weak _mips_cache_error __cache_error_loop: LA k1, _mips_cache_error beqz k1, __cache_error_loop jr k1 .org 0x180 .weak _mips_general_exception __general_exception_loop: /* * Free up k1, defering sp adjustment until later. Preserving k1 * may be undesirable if an exception occurs due to a corrupt * stack but since the default handlers use the user-stack to * store the context then there is nothing to lose. */ REG_S k1, (-CTX_SIZEROUND + CTX_K1)(sp) LA k1, _mips_general_exception beqz k1, __general_exception_loop jr k1 .set pop END(__exception_entry) /* * FUNCTION: __exception_save * * DESCRIPTION: Saves the GP context to the stack and invokes * _mips_handle_exception with appropriate arguments. */ ANESTED(__exception_save, _mips_general_exception, CTX_SIZEROUND + ADJ, zero) .globl __exception_save; .set push .set noat /* Create pointer to gp_ctx. */ PTR_ADDU k1, sp, -CTX_SIZEROUND /* Save context. */ _gpctx_save /* va0 now holds C0_STATUS. */ /* Finish storing the rest of the CP0 registers. */ PTR_MFC0 t0, C0_BADVADDR REG_S t0, CTX_BADVADDR(k1) #if __mips_isa_rev < 6 move t0, zero move t1, zero mfc0 t2, C0_CONFIG3 ext t3, t2, CFG3_BP_SHIFT, 1 beqz t3, 1f #else /* MIPSR6 guarantees all CP0 regs are defined to at least return zero. */ #endif mfc0 t0, C0_BADPINSTR #if __mips_isa_rev < 6 1: ext t2, t2, CFG3_BI_SHIFT, 1 beqz t2, 1f #endif mfc0 t1, C0_BADINSTR 1: sw t0, CTX_BADPINSTR(k1) sw t1, CTX_BADINSTR(k1) /* Get and store the exception cause. */ mfc0 t0, C0_CR sw t0, CTX_CAUSE(k1) /* Extract the cause code for argument 1. */ ext a1, t0, CR_X_SHIFT, CR_X_BITS /* Create the argument space. */ addiu sp, k1, -ADJ /* Clear EXL. Exceptions can now nest. */ ins va0, zero, SR_EXL_SHIFT, 1 mtc0 va0, C0_SR /* Move the gp_ctx pointer for argument 0. */ addiu a0, sp, ADJ /* Manually set up the return address to restore the context below. */ LA ra, __exception_restore /* Call the handler, indirect through t9 albeit not for any specific reason. */ LA t9, _mips_handle_exception jr t9 .set pop END(__exception_save) /* * FUNCTION: __exception_restore * * DESCRIPTION: Load the GP context from immediately above the stack * pointer and eret. */ LEAF(__exception_restore) .set push .set noat /* Skip past the argument save area and fall through. */ addiu a0, sp, ADJ /* * FUNCTION: __gpctx_load_eret * * DESCRIPTION: Load the GP context from the address in register a0 * and eret. */ AENT(__gpctx_load_eret) _gpctx_load /* Return from exception. */ eret .set pop END(__exception_restore)