blob: 9377b954768632f2f40a0b6cc07d4ee58226aab8 [file] [log] [blame]
/*
* Copyright 2016, 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.
*/
#include <mips/regdef.h>
#include <mips/asm.h>
#include <mips/cpu.h>
#include <mips/hal.h>
#define OS_STACK_ALIGNMENT (8)
#define CTX_ALIGNED_SIZE ((((CTX_SIZE - 1) / OS_STACK_ALIGNMENT) + 1) * \
OS_STACK_ALIGNMENT)
# note that k0 is not saved when using these macros.
# The cause register is saved but not resored.
# saves to location k0
.macro _gpctx_save
REG_S $1, CTX_REG(1) (k0)
REG_S $2, CTX_REG(2) (k0)
REG_S $3, CTX_REG(3) (k0)
REG_S $4, CTX_REG(4) (k0)
REG_S $5, CTX_REG(5) (k0)
REG_S $6, CTX_REG(6) (k0)
REG_S $7, CTX_REG(7) (k0)
REG_S $8, CTX_REG(8) (k0)
REG_S $9, CTX_REG(9) (k0)
REG_S $10, CTX_REG(10) (k0)
REG_S $11, CTX_REG(11) (k0)
REG_S $12, CTX_REG(12) (k0)
REG_S $13, CTX_REG(13) (k0)
REG_S $14, CTX_REG(14) (k0)
REG_S $15, CTX_REG(15) (k0)
REG_S $16, CTX_REG(16) (k0)
REG_S $17, CTX_REG(17)(k0)
REG_S $18, CTX_REG(18)(k0)
REG_S $19, CTX_REG(19)(k0)
REG_S $20, CTX_REG(20)(k0)
REG_S $21, CTX_REG(21)(k0)
REG_S $22, CTX_REG(22)(k0)
REG_S $23, CTX_REG(23)(k0)
REG_S $24, CTX_REG(24)(k0)
REG_S $25, CTX_REG(25)(k0)
# k0 not saved
REG_S $27, CTX_REG(27)(k0)
REG_S $28, CTX_REG(28)(k0)
REG_S $29, CTX_REG(29)(k0)
REG_S $30, CTX_REG(30)(k0)
REG_S $31, CTX_REG(31)(k0)
PTR_S $0, CTX_LINK(k0) # Clear the link field
#if (__mips_isa_rev < 6)
mfhi $9
mflo $10
REG_S $9, CTX_HI0(k0)
REG_S $10, CTX_LO0(k0)
#endif
# cp0
PTR_MFC0 $9, C0_EPC
REG_S $9, CTX_EPC(k0)
PTR_MFC0 $9, C0_BADVADDR
REG_S $9, CTX_BADVADDR(k0)
mfc0 $9, C0_SR
sw $9, CTX_STATUS(k0)
mfc0 $9, C0_CR
sw $9, CTX_CAUSE(k0)
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(k0)
sw $12, CTX_BADINSTR(k0)
.endm
# restores from location a0
.macro _gpctx_load
#if (__mips_isa_rev < 6)
REG_L $9, CTX_HI0(a0)
REG_L $10, CTX_LO0(a0)
mthi $9
mtlo $10
#endif
REG_L $1, CTX_REG(1)(a0)
REG_L $2, CTX_REG(2)(a0)
REG_L $3, CTX_REG(3)(a0)
# a0 is loaded last
REG_L $5, CTX_REG(5)(a0)
REG_L $6, CTX_REG(6)(a0)
REG_L $7, CTX_REG(7)(a0)
REG_L $8, CTX_REG(8)(a0)
REG_L $9, CTX_REG(9)(a0)
REG_L $10, CTX_REG(10)(a0)
REG_L $11, CTX_REG(11)(a0)
REG_L $12, CTX_REG(12)(a0)
REG_L $13, CTX_REG(13)(a0)
REG_L $14, CTX_REG(14)(a0)
REG_L $15, CTX_REG(15)(a0)
REG_L $16, CTX_REG(16)(a0)
REG_L $17, CTX_REG(17)(a0)
REG_L $18, CTX_REG(18)(a0)
REG_L $19, CTX_REG(19)(a0)
REG_L $20, CTX_REG(20)(a0)
REG_L $21, CTX_REG(21)(a0)
REG_L $22, CTX_REG(22)(a0)
REG_L $23, CTX_REG(23)(a0)
REG_L $24, CTX_REG(24)(a0)
REG_L $25, CTX_REG(25)(a0)
# restore k0 after interrupts have been disabled
REG_L $27, CTX_REG(27)(a0)
REG_L $28, CTX_REG(28)(a0)
# restore sp after interrupts have been disabled
REG_L $30, CTX_REG(30)(a0)
REG_L $31, CTX_REG(31)(a0)
di
REG_L k0, CTX_EPC(a0)
PTR_MTC0 k0, C0_EPC
lw k0, CTX_STATUS(a0)
# STATUS here will have EXL set
mtc0 k0, C0_SR
ehb
# restore k0 and sp as these may be overwritten by nested interrupts
REG_L $26, CTX_REG(26)(a0)
REG_L $29, CTX_REG(29)(a0)
# restore a0 last
REG_L $4, CTX_REG(4)(a0)
.endm
.text
.global get_global_pointer
.ent get_global_pointer
get_global_pointer:
.set noat
move v0, gp
jr ra
.end
.text
.global _mips_isr_sw0
.ent _mips_isr_sw0
_mips_isr_sw0:
# context switch
.set noat
# save k0
REG_S $26, (CTX_REG(25) - CTX_ALIGNED_SIZE)(sp)
addi k0, sp, -CTX_ALIGNED_SIZE
_gpctx_save # save the context
.set at
lw t0, g_current_task # get current task
beqz t0, 1f
sw k0, 0(t0) # update stored sp
1:
lw t1, g_os_run_list # get new task
sw t1, g_current_task # g_current_task = g_os_run_list
mfc0 k0, C0_CR
andi k0, k0, 0xfeff # clear interrupt in cause register
lui k1, 0x0080 # make sure IV is set
or k0, k0, k1
mtc0 k0, C0_CR
lw a0, 0(t1)
.set noat
_gpctx_load # updates actual sp
eret
.end