summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/shared/exceptions/ppc_exc_naked.S
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/shared/exceptions/ppc_exc_naked.S')
-rw-r--r--bsps/powerpc/shared/exceptions/ppc_exc_naked.S207
1 files changed, 207 insertions, 0 deletions
diff --git a/bsps/powerpc/shared/exceptions/ppc_exc_naked.S b/bsps/powerpc/shared/exceptions/ppc_exc_naked.S
new file mode 100644
index 0000000000..1c27575fea
--- /dev/null
+++ b/bsps/powerpc/shared/exceptions/ppc_exc_naked.S
@@ -0,0 +1,207 @@
+/**
+ * @file
+ *
+ * @ingroup ppc_exc
+ *
+ * @brief PowerPC Exceptions implementation.
+ */
+
+/*
+ * Copyright (c) 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include "ppc_exc_asm_macros.h"
+
+ .global ppc_exc_min_prolog_tmpl_naked
+
+ppc_exc_min_prolog_tmpl_naked:
+
+ stwu r1, -EXCEPTION_FRAME_END(r1)
+ stw VECTOR_REGISTER, VECTOR_OFFSET(r1)
+ li VECTOR_REGISTER, 0
+
+ /*
+ * We store the absolute branch target address here. It will be used
+ * to generate the branch operation in ppc_exc_make_prologue().
+ */
+ .int ppc_exc_wrap_naked
+
+ .global ppc_exc_wrap_naked
+ppc_exc_wrap_naked:
+
+ /* Save scratch registers */
+ stw SCRATCH_REGISTER_0, SCRATCH_REGISTER_0_OFFSET(r1)
+ stw SCRATCH_REGISTER_1, SCRATCH_REGISTER_1_OFFSET(r1)
+ stw SCRATCH_REGISTER_2, SCRATCH_REGISTER_2_OFFSET(r1)
+
+ /* Save volatile registers */
+ stw r0, GPR0_OFFSET(r1)
+ stw r3, GPR3_OFFSET(r1)
+ stw r8, GPR8_OFFSET(r1)
+ stw r9, GPR9_OFFSET(r1)
+ stw r10, GPR10_OFFSET(r1)
+ stw r11, GPR11_OFFSET(r1)
+ stw r12, GPR12_OFFSET(r1)
+
+ /* Save CR */
+ mfcr SCRATCH_REGISTER_0
+ stw SCRATCH_REGISTER_0, EXC_CR_OFFSET(r1)
+
+ /* Save SRR0 */
+ mfspr SCRATCH_REGISTER_0, srr0
+ stw SCRATCH_REGISTER_0, SRR0_FRAME_OFFSET(r1)
+
+ /* Save SRR1 */
+ mfspr SCRATCH_REGISTER_0, srr1
+ stw SCRATCH_REGISTER_0, SRR1_FRAME_OFFSET(r1)
+
+ /* Save CTR */
+ mfctr SCRATCH_REGISTER_0
+ stw SCRATCH_REGISTER_0, EXC_CTR_OFFSET(r1)
+
+ /* Save XER */
+ mfxer SCRATCH_REGISTER_0
+ stw SCRATCH_REGISTER_0, EXC_XER_OFFSET(r1)
+
+ /* Save LR */
+ mflr SCRATCH_REGISTER_0
+ stw SCRATCH_REGISTER_0, EXC_LR_OFFSET(r1)
+
+#ifndef PPC_EXC_CONFIG_BOOKE_ONLY
+
+ /* Load MSR bit mask */
+ lwz SCRATCH_REGISTER_0, ppc_exc_msr_bits@sdarel(r13)
+
+ /*
+ * Change the MSR if necessary (MMU, RI), remember decision in
+ * non-volatile CR_MSR.
+ */
+ cmpwi CR_MSR, SCRATCH_REGISTER_0, 0
+ bne CR_MSR, wrap_change_msr_naked
+
+wrap_change_msr_done_naked:
+
+#endif /* PPC_EXC_CONFIG_BOOKE_ONLY */
+
+ /*
+ * Call high level exception handler
+ */
+
+ /*
+ * Get the handler table index from the vector number. We have to
+ * discard the exception type. Take only the least significant five
+ * bits (= LAST_VALID_EXC + 1) from the vector register. Multiply by
+ * four (= size of function pointer).
+ */
+ rlwinm SCRATCH_REGISTER_1, VECTOR_REGISTER, 2, 25, 29
+
+ /* Load handler table address */
+ LA SCRATCH_REGISTER_0, ppc_exc_handler_table
+
+ /* Load handler address */
+ lwzx SCRATCH_REGISTER_0, SCRATCH_REGISTER_0, SCRATCH_REGISTER_1
+
+ /*
+ * First parameter = exception frame pointer + FRAME_LINK_SPACE
+ *
+ * We add FRAME_LINK_SPACE to the frame pointer because the high level
+ * handler expects a BSP_Exception_frame structure.
+ */
+ addi r3, r1, FRAME_LINK_SPACE
+
+ /*
+ * Second parameter = vector number (r4 is the VECTOR_REGISTER)
+ *
+ * Discard the exception type and store the vector number
+ * in the vector register. Take only the least significant
+ * five bits (= LAST_VALID_EXC + 1).
+ */
+ rlwinm VECTOR_REGISTER, VECTOR_REGISTER, 0, 27, 31
+
+ /* Call handler */
+ mtctr SCRATCH_REGISTER_0
+ bctrl
+
+#ifndef PPC_EXC_CONFIG_BOOKE_ONLY
+
+ /* Restore MSR? */
+ bne CR_MSR, wrap_restore_msr_naked
+
+wrap_restore_msr_done_naked:
+
+#endif /* PPC_EXC_CONFIG_BOOKE_ONLY */
+
+ /* Restore XER and CTR */
+ lwz SCRATCH_REGISTER_0, EXC_XER_OFFSET(r1)
+ lwz SCRATCH_REGISTER_1, EXC_CTR_OFFSET(r1)
+ mtxer SCRATCH_REGISTER_0
+ mtctr SCRATCH_REGISTER_1
+
+ /* Restore CR and LR */
+ lwz SCRATCH_REGISTER_0, EXC_CR_OFFSET(r1)
+ lwz SCRATCH_REGISTER_1, EXC_LR_OFFSET(r1)
+ mtcr SCRATCH_REGISTER_0
+ mtlr SCRATCH_REGISTER_1
+
+ /* Restore volatile registers */
+ lwz r0, GPR0_OFFSET(r1)
+ lwz r3, GPR3_OFFSET(r1)
+ lwz r8, GPR8_OFFSET(r1)
+ lwz r9, GPR9_OFFSET(r1)
+ lwz r10, GPR10_OFFSET(r1)
+ lwz r11, GPR11_OFFSET(r1)
+ lwz r12, GPR12_OFFSET(r1)
+
+ /* Restore vector register */
+ lwz VECTOR_REGISTER, VECTOR_OFFSET(r1)
+
+ /* Restore scratch registers and SRRs */
+ lwz SCRATCH_REGISTER_0, SRR0_FRAME_OFFSET(r1)
+ lwz SCRATCH_REGISTER_1, SRR1_FRAME_OFFSET(r1)
+ lwz SCRATCH_REGISTER_2, SCRATCH_REGISTER_2_OFFSET(r1)
+ mtspr srr0, SCRATCH_REGISTER_0
+ lwz SCRATCH_REGISTER_0, SCRATCH_REGISTER_0_OFFSET(r1)
+ mtspr srr1, SCRATCH_REGISTER_1
+ lwz SCRATCH_REGISTER_1, SCRATCH_REGISTER_1_OFFSET(r1)
+
+ /*
+ * We restore r1 from the frame rather than just popping (adding to
+ * current r1) since the exception handler might have done strange
+ * things (e.g. a debugger moving and relocating the stack).
+ */
+ lwz r1, 0(r1)
+
+ /* Return */
+ rfi
+
+#ifndef PPC_EXC_CONFIG_BOOKE_ONLY
+
+wrap_change_msr_naked:
+
+ mfmsr SCRATCH_REGISTER_1
+ or SCRATCH_REGISTER_1, SCRATCH_REGISTER_1, SCRATCH_REGISTER_0
+ mtmsr SCRATCH_REGISTER_1
+ sync
+ isync
+ b wrap_change_msr_done_naked
+
+wrap_restore_msr_naked:
+
+ lwz SCRATCH_REGISTER_0, ppc_exc_msr_bits@sdarel(r13)
+ mfmsr SCRATCH_REGISTER_1
+ andc SCRATCH_REGISTER_1, SCRATCH_REGISTER_1, SCRATCH_REGISTER_0
+ mtmsr SCRATCH_REGISTER_1
+ sync
+ isync
+ b wrap_restore_msr_done_naked
+
+#endif /* PPC_EXC_CONFIG_BOOKE_ONLY */