]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/arm/cswitch.s
xnu-4570.1.46.tar.gz
[apple/xnu.git] / osfmk / arm / cswitch.s
diff --git a/osfmk/arm/cswitch.s b/osfmk/arm/cswitch.s
new file mode 100644 (file)
index 0000000..7c3812d
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#include <machine/asm.h>
+#include <arm/proc_reg.h>
+#include "assym.s"
+
+/*
+ * save_vfp_registers
+ *
+ * Expects a pointer to the VFP save area in r3; saves the callee-saved registers to that save area.
+ * Clobbers r2 and r3.
+ */
+.macro save_vfp_registers
+#if     __ARM_VFP__
+       fmrx            r2, fpscr                                               // Get the current FPSCR...
+       str                     r2, [r3, VSS_FPSCR]                             // ...and save it to the save area
+       add                     r3, r3, #64                                             // Only s16-s31 are callee-saved
+#if     (__ARM_VFP__ >= 3)
+       vstmia.64       r3!, {d8-d11}
+       vstmia.64       r3!, {d12-d15}
+#else
+       fstmias         r3!, {s16-s31}
+#endif /* __ARM_VFP__ >= 3 */
+#endif /* __ARM_VFP__ */
+.endmacro
+
+/*
+ * load_vfp_registers
+ *
+ * Expects a pointer to the VFP save area in r3; loads the callee-saved registers from that save area.
+ * Clobbers r2 and r3.
+ */
+.macro load_vfp_registers
+#if     __ARM_VFP__
+       add                     r2, r3, #64                                             // Only s16-s31 are callee-saved
+#if     (__ARM_VFP__ >= 3)
+       vldmia.64       r2!, {d8-d11}
+       vldmia.64       r2!, {d12-d15}
+#else
+       fldmias         r2!, {s16-s31}
+#endif /* __ARM_VFP__ >= 3 */
+       ldr                     r3, [r3, VSS_FPSCR]                             // Get our saved FPSCR value...
+       fmxr            fpscr, r3                                               // ...and restore it
+#endif /* __ARM_VFP__ */
+.endmacro
+
+/*
+ * void     machine_load_context(thread_t        thread)
+ *
+ * Load the context for the first thread to run on a
+ * cpu, and go.
+ */
+       .syntax unified
+       .text
+       .align 2
+       .globl  EXT(machine_load_context)
+
+LEXT(machine_load_context)
+       mcr             p15, 0, r0, c13, c0, 4                          // Write TPIDRPRW
+       ldr             r1, [r0, TH_CTH_SELF]
+       mrc             p15, 0, r2, c13, c0, 3                          // Read TPIDRURO
+       and             r2, r2, #3                                                      // Extract cpu number
+       orr             r1, r1, r2                                                      // 
+       mcr             p15, 0, r1, c13, c0, 3                          // Write TPIDRURO
+       ldr             r1, [r0, TH_CTH_DATA]
+       mcr             p15, 0, r1, c13, c0, 2                          // Write TPIDRURW
+       mov             r7, #0                                                          // Clear frame pointer
+       ldr             r3, [r0, TH_KSTACKPTR]                          // Get kernel stack top
+       mov             r0, #0                                                          // no param
+       add             r3, r3, SS_R4
+       ldmia   r3!, {r4-r14}                                           // Load thread status
+       bx              lr                                                                      // Return
+
+/*
+ *     void Call_continuation( void (*continuation)(void), 
+ *                             void *param, 
+ *                             wait_result_t wresult, 
+ *                             vm_offset_t stack_ptr)
+ */
+       .text
+       .align  5
+       .globl  EXT(Call_continuation)
+
+LEXT(Call_continuation)
+       mrc             p15, 0, r9, c13, c0, 4                          // Read TPIDRPRW
+       ldr             sp, [r9, TH_KSTACKPTR]                          // Set stack pointer
+       mov             r7, #0                                                          // Clear frame pointer
+       mov             r6,r0                                                           // Load continuation
+       mov             r0,r1                                                           // Set first parameter
+       mov             r1,r2                                                           // Set wait result arg
+       blx             r6                                                                      // Branch to continuation
+       mrc             p15, 0, r0, c13, c0, 4                          // Read TPIDRPRW
+       LOAD_ADDR_PC(thread_terminate)
+       b               .                                                                       // Not reach
+
+
+/*
+ *     thread_t Switch_context(thread_t        old,
+ *                             void            (*cont)(void),
+ *                             thread_t        new)
+ */
+       .text
+       .align 5
+       .globl  EXT(Switch_context)
+
+LEXT(Switch_context)
+       teq             r1, #0                                                          // Test if blocking on continuaton
+       bne             switch_threads                                          // No need to save GPR/NEON state if we are
+#if     __ARM_VFP__
+       mov             r1, r2                                                          // r2 will be clobbered by the save, so preserve it
+       add             r3, r0, ACT_KVFP                                        // Get the kernel VFP save area for the old thread...
+       save_vfp_registers                                                      // ...and save our VFP state to it
+       mov             r2, r1                                                          // Restore r2 (the new thread pointer)
+#endif /* __ARM_VFP__ */
+       ldr             r3, [r0, TH_KSTACKPTR]                          // Get old kernel stack top
+       add             r3, r3, SS_R4
+       stmia           r3!, {r4-r14}                                   // Save general registers to pcb
+switch_threads:
+       ldr             r3, [r2, TH_KSTACKPTR]                          // get kernel stack top
+       mcr             p15, 0, r2, c13, c0, 4                          // Write TPIDRPRW
+       ldr             r6, [r2, TH_CTH_SELF]
+       mrc             p15, 0, r5, c13, c0, 3                          // Read TPIDRURO
+       and             r5, r5, #3                                                      // Extract cpu number
+       orr             r6, r6, r5
+       mcr             p15, 0, r6, c13, c0, 3                          // Write TPIDRURO
+       ldr             r6, [r2, TH_CTH_DATA]
+       mcr             p15, 0, r6, c13, c0, 2                          // Write TPIDRURW
+load_reg:      
+       add             r3, r3, SS_R4
+       ldmia   r3!, {r4-r14}                                           // Restore new thread status
+#if     __ARM_VFP__
+       add             r3, r2, ACT_KVFP                                        // Get the kernel VFP save area for the new thread...
+       load_vfp_registers                                                      // ...and load the saved state
+#endif /* __ARM_VFP__ */
+       bx              lr                                                                      // Return
+
+/*
+ *     thread_t Shutdown_context(void (*doshutdown)(processor_t), processor_t processor)
+ *
+ */
+       .text
+       .align 5
+       .globl  EXT(Shutdown_context)
+
+LEXT(Shutdown_context)
+       mrc             p15, 0, r9, c13, c0, 4                          // Read TPIDRPRW
+#if __ARM_VFP__
+       add             r3, r9, ACT_KVFP                                        // Get the kernel VFP save area for the current thread...
+       save_vfp_registers                                                      // ...and save our VFP state to it
+#endif
+       ldr             r3, [r9, TH_KSTACKPTR]                          // Get kernel stack top
+       add             r3, r3, SS_R4
+       stmia   r3!, {r4-r14}                                           // Save general registers to pcb
+       cpsid   if                                                                      // Disable FIQ IRQ
+
+       ldr             r12, [r9, ACT_CPUDATAP]                         // Get current cpu
+       ldr             sp, [r12, CPU_ISTACKPTR]                        // Switch to interrupt stack
+       LOAD_ADDR_PC(cpu_doshutdown)
+
+/*
+ *     thread_t Idle_context(void)
+ *
+ */
+       .text
+       .align 5
+       .globl  EXT(Idle_context)
+
+LEXT(Idle_context)
+
+       mrc             p15, 0, r9, c13, c0, 4                          // Read TPIDRPRW
+#if    __ARM_VFP__
+       add             r3, r9, ACT_KVFP                                        // Get the kernel VFP save area for the current thread...
+       save_vfp_registers                                                      // ...and save our VFP state to it
+#endif
+       ldr             r3, [r9, TH_KSTACKPTR]                          // Get kernel stack top
+       add             r3, r3, SS_R4
+       stmia   r3!, {r4-r14}                                           // Save general registers to pcb
+
+       ldr             r12, [r9, ACT_CPUDATAP]                         // Get current cpu
+       ldr             sp, [r12, CPU_ISTACKPTR]                        // Switch to interrupt stack
+       LOAD_ADDR_PC(cpu_idle)
+
+/*
+ *     thread_t Idle_context(void)
+ *
+ */
+       .text
+       .align 5
+       .globl  EXT(Idle_load_context)
+
+LEXT(Idle_load_context)
+
+       mrc             p15, 0, r12, c13, c0, 4                         // Read TPIDRPRW
+       ldr             r3, [r12, TH_KSTACKPTR]                         // Get kernel stack top
+       add             r3, r3, SS_R4
+       ldmia   r3!, {r4-r14}                                           // Restore new thread status
+#if __ARM_VFP__
+       add             r3, r9, ACT_KVFP                                        // Get the kernel VFP save area for the current thread...
+       load_vfp_registers                                                      // ...and load the saved state
+#endif
+       bx              lr                                                                      // Return
+
+/*
+ * void vfp_save(struct arm_vfpsaved_state  *vfp_ss)
+ */
+       .text
+       .align 2
+       .globl  EXT(vfp_save)
+
+LEXT(vfp_save)
+#if    __ARM_VFP__
+       fmrx        r1, fpscr                       // Get the current FPSCR...
+       str         r1, [r0, VSS_FPSCR]             // ...and save it to the save area
+#if     (__ARM_VFP__ >= 3)
+       vstmia.64   r0!, {d0-d3}                    // Save vfp registers
+       vstmia.64   r0!, {d4-d7}
+       vstmia.64   r0!, {d8-d11}
+       vstmia.64   r0!, {d12-d15}
+       vstmia.64   r0!, {d16-d19}
+       vstmia.64   r0!, {d20-d23}
+       vstmia.64   r0!, {d24-d27}
+       vstmia.64   r0!, {d28-d31}
+#else
+       fstmias     r0!, {s0-s31}                   // Save vfp registers
+#endif
+#endif  /* __ARM_VFP__ */
+       bx          lr                              // Return
+
+/*
+ * void vfp_load(struct arm_vfpsaved_state *vfp_ss)
+ *
+ * Loads the state in vfp_ss into the VFP registers.
+ */
+       .text
+       .align 2
+       .globl  EXT(vfp_load)
+LEXT(vfp_load)
+#if __ARM_VFP__
+       /* r0: vfp_ss, r1: unused, r2: unused, r3: unused */
+       mov         r1, r0
+#if (__ARM_VFP__ >= 3)
+       vldmia.64   r0!, {d0-d3}                    // Restore vfp registers
+       vldmia.64   r0!, {d4-d7}
+       vldmia.64   r0!, {d8-d11}
+       vldmia.64   r0!, {d12-d15}
+       vldmia.64   r0!, {d16-d19}
+       vldmia.64   r0!, {d20-d23}
+       vldmia.64   r0!, {d24-d27}
+       vldmia.64   r0!, {d28-d31}
+#else
+       fldmias     r0!, {s0-s31}                   // Restore vfp registers
+#endif /* __ARM_VFP__ >= 3 */
+       ldr         r1, [r1, VSS_FPSCR]             // Get fpscr from the save state...
+       fmxr        fpscr, r1                       // ...and load it into the register
+#endif /* __ARM_VFP__ */
+       bx          lr                              // Return
+
+#include        "globals_asm.h"
+
+LOAD_ADDR_GEN_DEF(thread_terminate)
+LOAD_ADDR_GEN_DEF(cpu_doshutdown)
+LOAD_ADDR_GEN_DEF(cpu_idle)
+
+/* vim: set ts=4: */
+