blob: a81e5a1d40511d9bbd7d0310568952f500f38a43 [file] [log] [blame]
/*
* 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)