| /* |
| * Copyright 2014-2015, Imagination Technologies Limited and/or its |
| * affiliated group companies. |
| * All rights reserved. |
| * |
| * 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. |
| */ |
| |
| # Keep each function in a separate named section |
| #define _FUNCTION_SECTIONS_ |
| .set nomips16 |
| |
| #include <mips/asm.h> |
| #include <mips/regdef.h> |
| #include <mips/cpu.h> |
| #include <mips/hal.h> |
| |
| # Context size, adjusted for ABI parameter area |
| #define ADJ (NARGSAVE * SZARG) |
| # Round up to 16-byte boundary (maximum stack alignment required for any |
| # supported ABI) |
| #define CTX_SIZEROUND ((CTX_SIZE + ALSZ) & ALMASK) |
| #define CTX_SIZEADJ (CTX_SIZEROUND + ADJ) |
| |
| #define e_ISR s1 |
| #define e_CR s3 |
| #define e_BADV s4 |
| #define e_SR s5 |
| #define e_EPC s6 |
| #define e_RA s7 |
| |
| # DESCRIPTION: Exception entry point. This is small because it must go at |
| # EBASE+0x180. It saves enough context to chain onwards to |
| # __exception_save. |
| # |
| 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. |
| j _start0 |
| 1: |
| 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 |
| # Free up k1, defering sp adjustment until later |
| REG_S k1, (-CTX_SIZEROUND + CTX_K1)(sp) |
| |
| # Use k1 to invoke __exception_save |
| LA k1, _mips_general_exception |
| jr k1 |
| .set pop |
| END(__exception_entry) |
| |
| # |
| # FUNCTION: __exception_save |
| # |
| # DESCRIPTION: Exception context save. Save the context, then fake up a call |
| # frame. |
| # |
| ANESTED(__exception_save, _mips_general_exception, CTX_SIZEADJ, zero) |
| .globl __exception_save; |
| .set push |
| .set noat |
| |
| # k1 is already saved, so use it to save the users sp |
| move k1, sp |
| # Finally adjust sp |
| PTR_ADDU sp, sp, -CTX_SIZEADJ # This should be picked up by the backtracer |
| |
| # Save context |
| REG_S $1, CTX_REG(1) + ADJ(sp) |
| REG_S $2, CTX_REG(2) + ADJ(sp) |
| REG_S $3, CTX_REG(3) + ADJ(sp) |
| REG_S $4, CTX_REG(4) + ADJ(sp) |
| REG_S $5, CTX_REG(5) + ADJ(sp) |
| REG_S $6, CTX_REG(6) + ADJ(sp) |
| REG_S $7, CTX_REG(7) + ADJ(sp) |
| REG_S $8, CTX_REG(8) + ADJ(sp) |
| REG_S $9, CTX_REG(9) + ADJ(sp) |
| REG_S $10, CTX_REG(10) + ADJ(sp) |
| REG_S $11, CTX_REG(11) + ADJ(sp) |
| REG_S $12, CTX_REG(12) + ADJ(sp) |
| REG_S $13, CTX_REG(13) + ADJ(sp) |
| REG_S $14, CTX_REG(14) + ADJ(sp) |
| REG_S $15, CTX_REG(15) + ADJ(sp) |
| REG_S $16, CTX_REG(16) + ADJ(sp) |
| REG_S $17, CTX_REG(17) + ADJ(sp) |
| REG_S $18, CTX_REG(18) + ADJ(sp) |
| REG_S $19, CTX_REG(19) + ADJ(sp) |
| REG_S $20, CTX_REG(20) + ADJ(sp) |
| REG_S $21, CTX_REG(21) + ADJ(sp) |
| REG_S $22, CTX_REG(22) + ADJ(sp) |
| REG_S $23, CTX_REG(23) + ADJ(sp) |
| REG_S $24, CTX_REG(24) + ADJ(sp) |
| REG_S $25, CTX_REG(25) + ADJ(sp) |
| REG_S $26, CTX_REG(26) + ADJ(sp) |
| # k1/$27 has already been saved |
| REG_S $28, CTX_REG(28) + ADJ(sp) |
| REG_S k1, CTX_REG(29) + ADJ(sp) # Use saved sp from earlier |
| REG_S $30, CTX_REG(30) + ADJ(sp) |
| REG_S $31, CTX_REG(31) + ADJ(sp) |
| PTR_S $0, CTX_LINK + ADJ(sp) # Clear the link field |
| |
| #if (__mips_isa_rev < 6) |
| mfhi $9 |
| mflo $10 |
| REG_S $9, CTX_HI0 + ADJ(sp) |
| REG_S $10, CTX_LO0 + ADJ(sp) |
| #endif |
| |
| # Trick the backtracer into stepping back to the point where the exception |
| # occurred. |
| PTR_MFC0 ra, C0_EPC |
| mfc0 e_CR, C0_CR |
| REG_S ra, CTX_EPC + ADJ(sp) |
| |
| # Finish storing the rest of the CP0 registers |
| PTR_MFC0 $9, C0_BADVADDR |
| REG_S $9, CTX_BADVADDR + ADJ(sp) |
| sw e_CR, CTX_CAUSE + ADJ(sp) |
| |
| move $11, $0 |
| move $12, $0 |
| mfc0 $9, C0_CONFIG3 |
| ext $10, $9, CFG3_BP_SHIFT, 1 |
| beqz $10, 1f |
| mfc0 $11, C0_BADPINSTR |
| 1: |
| ext $9, $9, CFG3_BI_SHIFT, 1 |
| beqz $9, 1f |
| mfc0 $12, C0_BADINSTR |
| 1: |
| sw $11, CTX_BADPINSTR + ADJ(sp) |
| sw $12, CTX_BADINSTR + ADJ(sp) |
| |
| # Start computing the address of the context for a0 |
| move a0, sp |
| |
| # Clear EXL. Exceptions can now nest. |
| mfc0 e_SR, C0_SR |
| sw e_SR, CTX_STATUS + ADJ(sp) |
| lui $9, %hi(~SR_EXL) |
| addiu $9, $9, %lo(~SR_EXL) |
| and e_SR, e_SR, $9 |
| mtc0 e_SR, C0_SR |
| |
| # Manually set up the return address to restore the context below |
| LA ra, 1f |
| # Extract the cause code |
| and a1, e_CR, CR_XMASK |
| |
| # Finish computing the address of the context for a0 |
| addiu a0, a0, ADJ |
| |
| # Shift exception number down into expected range |
| srl a1, a1, 2 |
| |
| # Call the handler, indirect through t9 albeit not for any specific |
| # reason |
| LA t9, _mips_handle_exception |
| jr t9 |
| |
| 1: # Return point from handler |
| # Load context |
| |
| #if (__mips_isa_rev < 6) |
| REG_L $9, CTX_HI0 + ADJ(sp) |
| REG_L $10, CTX_LO0 + ADJ(sp) |
| mthi $9 |
| mtlo $10 |
| #endif |
| |
| REG_L $1, CTX_REG(1) + ADJ(sp) |
| REG_L $2, CTX_REG(2) + ADJ(sp) |
| REG_L $3, CTX_REG(3) + ADJ(sp) |
| REG_L $4, CTX_REG(4) + ADJ(sp) |
| REG_L $5, CTX_REG(5) + ADJ(sp) |
| REG_L $6, CTX_REG(6) + ADJ(sp) |
| REG_L $7, CTX_REG(7) + ADJ(sp) |
| REG_L $8, CTX_REG(8) + ADJ(sp) |
| REG_L $9, CTX_REG(9) + ADJ(sp) |
| REG_L $10, CTX_REG(10) + ADJ(sp) |
| REG_L $11, CTX_REG(11) + ADJ(sp) |
| REG_L $12, CTX_REG(12) + ADJ(sp) |
| REG_L $13, CTX_REG(13) + ADJ(sp) |
| REG_L $14, CTX_REG(14) + ADJ(sp) |
| REG_L $15, CTX_REG(15) + ADJ(sp) |
| REG_L $16, CTX_REG(16) + ADJ(sp) |
| REG_L $17, CTX_REG(17) + ADJ(sp) |
| REG_L $18, CTX_REG(18) + ADJ(sp) |
| REG_L $19, CTX_REG(19) + ADJ(sp) |
| REG_L $20, CTX_REG(20) + ADJ(sp) |
| REG_L $21, CTX_REG(21) + ADJ(sp) |
| REG_L $22, CTX_REG(22) + ADJ(sp) |
| REG_L $23, CTX_REG(23) + ADJ(sp) |
| REG_L $24, CTX_REG(24) + ADJ(sp) |
| REG_L $25, CTX_REG(25) + ADJ(sp) |
| # $26/K0 and $27/K1 are restored with interrupts disabled |
| REG_L $28, CTX_REG(28) + ADJ(sp) |
| # $29/SP is restored last |
| REG_L $30, CTX_REG(30) + ADJ(sp) |
| REG_L $31, CTX_REG(31) + ADJ(sp) |
| di |
| lw k0, CTX_STATUS + ADJ(sp) |
| REG_L k1, CTX_EPC + ADJ(sp) |
| mtc0 k0, C0_SR |
| PTR_MTC0 k1, C0_EPC |
| ehb |
| REG_L k0, CTX_K0 + ADJ(sp) |
| REG_L k1, CTX_K1 + ADJ(sp) |
| REG_L sp, CTX_SP + ADJ(sp) |
| # Return from exception |
| eret |
| .set pop |
| END(__exception_save) |