diff options
Diffstat (limited to 'payloads/libpayload/arch/mips/exception_asm.S')
-rw-r--r-- | payloads/libpayload/arch/mips/exception_asm.S | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/payloads/libpayload/arch/mips/exception_asm.S b/payloads/libpayload/arch/mips/exception_asm.S new file mode 100644 index 0000000000..5906d39f0c --- /dev/null +++ b/payloads/libpayload/arch/mips/exception_asm.S @@ -0,0 +1,208 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2014 Imagination Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define STATUS_REGISTER $12,0 +#define BOOT_EXC_VECTOR_MASK (1 << 22) +#define EBASE_REGISTER $15,1 +#define WRITE_GATE_MASK (1 << 11) +#define EXCEPTION_BASE_MASK (0xFFFFF000) + + /* Don't reorder instructions */ + .set noreorder + .set noat + + .align 4 + .global exception_stack_end +exception_stack_end: + .word 0 + + .global exception_state_ptr +exception_state_ptr: + .word 0 + +/* Temporary variables. */ +ret_addr: + .word 0 +exception_sp: + .word 0 +vector: + .word 0 + +/* Cache error */ +.org 0x100 + li $v0, 0x0 + la $at, vector + sw $v0, 0x00($at) + b exception_common + nop + +/* TLB refill and all others */ +.org 0x180 + li $v0, 0x1 + la $at, vector + sw $v0, 0x00($at) + b exception_common + nop + +/* Interrupt */ +.org 0x200 + li $v0, 0x2 + la $at, vector + sw $v0, 0x00($at) + b exception_common + nop + +/* EJTAG debug exception */ +.org 0x480 + li $v0, 0x3 + la $at, vector + sw $v0, 0x00($at) + b exception_common + nop + +exception_common: + /* Obtain return address of exception */ + la $v0, ret_addr + sw $ra, 0x00($v0) + + /* Initialize $gp */ + bal 1f + nop + .word _gp +1: + lw $gp, 0($ra) + + la $at, exception_sp + sw $sp, 0x00($at) + lw $sp, exception_state_ptr + + /* Save all registers */ + sw $zero, 0x00($sp) + sw $at, 0x04($sp) + sw $v0, 0x08($sp) + sw $v1, 0x0C($sp) + sw $a0, 0x10($sp) + sw $a1, 0x14($sp) + sw $a2, 0x18($sp) + sw $a3, 0x1C($sp) + sw $t0, 0x20($sp) + sw $t1, 0x34($sp) + sw $t2, 0x28($sp) + sw $t3, 0x2C($sp) + sw $t4, 0x30($sp) + sw $t5, 0x34($sp) + sw $t6, 0x38($sp) + sw $t7, 0x3C($sp) + sw $s0, 0x40($sp) + sw $s1, 0x44($sp) + sw $s2, 0x48($sp) + sw $s3, 0x4C($sp) + sw $s4, 0x50($sp) + sw $s5, 0x54($sp) + sw $s6, 0x58($sp) + sw $s7, 0x5C($sp) + sw $t8, 0x60($sp) + sw $t9, 0x64($sp) + sw $k0, 0x68($sp) + sw $k1, 0x6C($sp) + sw $gp, 0x70($sp) + lw $v0, exception_sp + sw $v0, 0x74($sp) + sw $fp, 0x78($sp) + lw $v0, ret_addr + sw $v0, 0x7C($sp) + lw $v0, vector + sw $v0, 0x80($sp) + + /* Point SP to the stack for C code */ + lw $sp, exception_stack_end + /* Give control to exception dispatch */ + la $a2, exception_dispatch + jalr $a2 + nop + lw $sp, exception_state_ptr + /* Restore registers */ + lw $zero, 0x00($sp) + lw $at, 0x04($sp) + lw $v0, 0x08($sp) + lw $v1, 0x0C($sp) + lw $a0, 0x10($sp) + lw $a1, 0x14($sp) + lw $a2, 0x18($sp) + lw $a3, 0x1C($sp) + lw $t0, 0x20($sp) + lw $t1, 0x24($sp) + lw $t2, 0x28($sp) + lw $t3, 0x2C($sp) + lw $t4, 0x30($sp) + lw $t5, 0x34($sp) + lw $t6, 0x38($sp) + lw $t7, 0x3C($sp) + lw $s0, 0x40($sp) + lw $s1, 0x44($sp) + lw $s2, 0x48($sp) + lw $s3, 0x4C($sp) + lw $s4, 0x50($sp) + lw $s5, 0x54($sp) + lw $s6, 0x58($sp) + lw $s7, 0x5C($sp) + lw $t8, 0x60($sp) + lw $t9, 0x64($sp) + lw $k0, 0x68($sp) + sw $k1, 0x6C($sp) + sw $gp, 0x70($sp) + sw $fp, 0x78($sp) + sw $ra, 0x7C($sp) + /* Return */ + eret + + .global exception_init_asm +exception_init_asm: + .set push + /* Make sure boot exception vector is 1 before writing EBASE */ + mfc0 $t0, STATUS_REGISTER + li $t1, BOOT_EXC_VECTOR_MASK + or $t0, $t0, $t1 + mtc0 $t0, STATUS_REGISTER + + /*Prepare base address */ + la $t1, exception_stack_end + li $t2, EXCEPTION_BASE_MASK + and $t1, $t1, $t2 + + /* Prepare EBASE register value */ + mfc0 $t0, EBASE_REGISTER + li $t2, ~(EXCEPTION_BASE_MASK) + and $t0, $t0, $t2 + /* Filling base address */ + or $t0, $t0, $t1 + /* Setting WG bit */ + li $t2, WRITE_GATE_MASK + or $t0, $t0, $t2 + mtc0 $t0, EBASE_REGISTER + + /* Clear boot exception vector bit for EBASE value to take effect */ + mfc0 $t0, STATUS_REGISTER + li $t1, ~BOOT_EXC_VECTOR_MASK + and $t0, $t0, $t1 + mtc0 $t0, STATUS_REGISTER + + .set pop + /* Return */ + jr $ra |