aboutsummaryrefslogtreecommitdiff
path: root/payloads/libpayload/arch/mips/exception_asm.S
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload/arch/mips/exception_asm.S')
-rw-r--r--payloads/libpayload/arch/mips/exception_asm.S208
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