2 * Copyright (c) 2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <machine/asm.h>
29 #include <arm/proc_reg.h>
35 * Expects a pointer to the VFP save area in r3; saves the callee-saved registers to that save area.
38 .macro save_vfp_registers
40 fmrx r2, fpscr // Get the current FPSCR...
41 str r2, [r3, VSS_FPSCR] // ...and save it to the save area
42 add r3, r3, #64 // Only s16-s31 are callee-saved
43 #if (__ARM_VFP__ >= 3)
44 vstmia.64 r3!, {d8-d11}
45 vstmia.64 r3!, {d12-d15}
47 fstmias r3!, {s16-s31}
48 #endif /* __ARM_VFP__ >= 3 */
49 #endif /* __ARM_VFP__ */
55 * Expects a pointer to the VFP save area in r3; loads the callee-saved registers from that save area.
58 .macro load_vfp_registers
60 add r2, r3, #64 // Only s16-s31 are callee-saved
61 #if (__ARM_VFP__ >= 3)
62 vldmia.64 r2!, {d8-d11}
63 vldmia.64 r2!, {d12-d15}
65 fldmias r2!, {s16-s31}
66 #endif /* __ARM_VFP__ >= 3 */
67 ldr r3, [r3, VSS_FPSCR] // Get our saved FPSCR value...
68 fmxr fpscr, r3 // ...and restore it
69 #endif /* __ARM_VFP__ */
73 * void machine_load_context(thread_t thread)
75 * Load the context for the first thread to run on a
81 .globl EXT(machine_load_context)
83 LEXT(machine_load_context)
84 mcr p15, 0, r0, c13, c0, 4 // Write TPIDRPRW
85 ldr r1, [r0, TH_CTH_SELF]
86 mrc p15, 0, r2, c13, c0, 3 // Read TPIDRURO
87 and r2, r2, #3 // Extract cpu number
89 mcr p15, 0, r1, c13, c0, 3 // Write TPIDRURO
90 ldr r1, [r0, TH_CTH_DATA]
91 mcr p15, 0, r1, c13, c0, 2 // Write TPIDRURW
92 mov r7, #0 // Clear frame pointer
93 ldr r3, [r0, TH_KSTACKPTR] // Get kernel stack top
94 mov r0, #0 // no param
96 ldmia r3!, {r4-r14} // Load thread status
100 * void Call_continuation( void (*continuation)(void),
102 * wait_result_t wresult,
103 * vm_offset_t stack_ptr)
107 .globl EXT(Call_continuation)
109 LEXT(Call_continuation)
110 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
111 ldr sp, [r9, TH_KSTACKPTR] // Set stack pointer
112 mov r7, #0 // Clear frame pointer
113 mov r6,r0 // Load continuation
114 mov r0,r1 // Set first parameter
115 mov r1,r2 // Set wait result arg
116 blx r6 // Branch to continuation
117 mrc p15, 0, r0, c13, c0, 4 // Read TPIDRPRW
118 LOAD_ADDR_PC(thread_terminate)
123 * thread_t Switch_context(thread_t old,
124 * void (*cont)(void),
129 .globl EXT(Switch_context)
132 teq r1, #0 // Test if blocking on continuaton
133 bne switch_threads // No need to save GPR/NEON state if we are
135 mov r1, r2 // r2 will be clobbered by the save, so preserve it
136 add r3, r0, ACT_KVFP // Get the kernel VFP save area for the old thread...
137 save_vfp_registers // ...and save our VFP state to it
138 mov r2, r1 // Restore r2 (the new thread pointer)
139 #endif /* __ARM_VFP__ */
140 ldr r3, [r0, TH_KSTACKPTR] // Get old kernel stack top
142 stmia r3!, {r4-r14} // Save general registers to pcb
144 ldr r3, [r2, TH_KSTACKPTR] // get kernel stack top
145 mcr p15, 0, r2, c13, c0, 4 // Write TPIDRPRW
146 ldr r6, [r2, TH_CTH_SELF]
147 mrc p15, 0, r5, c13, c0, 3 // Read TPIDRURO
148 and r5, r5, #3 // Extract cpu number
150 mcr p15, 0, r6, c13, c0, 3 // Write TPIDRURO
151 ldr r6, [r2, TH_CTH_DATA]
152 mcr p15, 0, r6, c13, c0, 2 // Write TPIDRURW
155 ldmia r3!, {r4-r14} // Restore new thread status
157 add r3, r2, ACT_KVFP // Get the kernel VFP save area for the new thread...
158 load_vfp_registers // ...and load the saved state
159 #endif /* __ARM_VFP__ */
163 * thread_t Shutdown_context(void (*doshutdown)(processor_t), processor_t processor)
168 .globl EXT(Shutdown_context)
170 LEXT(Shutdown_context)
171 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
173 add r3, r9, ACT_KVFP // Get the kernel VFP save area for the current thread...
174 save_vfp_registers // ...and save our VFP state to it
176 ldr r3, [r9, TH_KSTACKPTR] // Get kernel stack top
178 stmia r3!, {r4-r14} // Save general registers to pcb
179 cpsid if // Disable FIQ IRQ
181 ldr r12, [r9, ACT_CPUDATAP] // Get current cpu
182 ldr sp, [r12, CPU_ISTACKPTR] // Switch to interrupt stack
183 LOAD_ADDR_PC(cpu_doshutdown)
186 * thread_t Idle_context(void)
191 .globl EXT(Idle_context)
195 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
197 add r3, r9, ACT_KVFP // Get the kernel VFP save area for the current thread...
198 save_vfp_registers // ...and save our VFP state to it
200 ldr r3, [r9, TH_KSTACKPTR] // Get kernel stack top
202 stmia r3!, {r4-r14} // Save general registers to pcb
204 ldr r12, [r9, ACT_CPUDATAP] // Get current cpu
205 ldr sp, [r12, CPU_ISTACKPTR] // Switch to interrupt stack
206 LOAD_ADDR_PC(cpu_idle)
209 * thread_t Idle_context(void)
214 .globl EXT(Idle_load_context)
216 LEXT(Idle_load_context)
218 mrc p15, 0, r12, c13, c0, 4 // Read TPIDRPRW
219 ldr r3, [r12, TH_KSTACKPTR] // Get kernel stack top
221 ldmia r3!, {r4-r14} // Restore new thread status
223 add r3, r9, ACT_KVFP // Get the kernel VFP save area for the current thread...
224 load_vfp_registers // ...and load the saved state
229 * void vfp_save(struct arm_vfpsaved_state *vfp_ss)
237 fmrx r1, fpscr // Get the current FPSCR...
238 str r1, [r0, VSS_FPSCR] // ...and save it to the save area
239 #if (__ARM_VFP__ >= 3)
240 vstmia.64 r0!, {d0-d3} // Save vfp registers
241 vstmia.64 r0!, {d4-d7}
242 vstmia.64 r0!, {d8-d11}
243 vstmia.64 r0!, {d12-d15}
244 vstmia.64 r0!, {d16-d19}
245 vstmia.64 r0!, {d20-d23}
246 vstmia.64 r0!, {d24-d27}
247 vstmia.64 r0!, {d28-d31}
249 fstmias r0!, {s0-s31} // Save vfp registers
251 #endif /* __ARM_VFP__ */
255 * void vfp_load(struct arm_vfpsaved_state *vfp_ss)
257 * Loads the state in vfp_ss into the VFP registers.
264 /* r0: vfp_ss, r1: unused, r2: unused, r3: unused */
266 #if (__ARM_VFP__ >= 3)
267 vldmia.64 r0!, {d0-d3} // Restore vfp registers
268 vldmia.64 r0!, {d4-d7}
269 vldmia.64 r0!, {d8-d11}
270 vldmia.64 r0!, {d12-d15}
271 vldmia.64 r0!, {d16-d19}
272 vldmia.64 r0!, {d20-d23}
273 vldmia.64 r0!, {d24-d27}
274 vldmia.64 r0!, {d28-d31}
276 fldmias r0!, {s0-s31} // Restore vfp registers
277 #endif /* __ARM_VFP__ >= 3 */
278 ldr r1, [r1, VSS_FPSCR] // Get fpscr from the save state...
279 fmxr fpscr, r1 // ...and load it into the register
280 #endif /* __ARM_VFP__ */
283 #include "globals_asm.h"
285 LOAD_ADDR_GEN_DEF(thread_terminate)
286 LOAD_ADDR_GEN_DEF(cpu_doshutdown)
287 LOAD_ADDR_GEN_DEF(cpu_idle)