]> git.saurik.com Git - apple/xnu.git/blob - osfmk/arm/cswitch.s
xnu-6153.61.1.tar.gz
[apple/xnu.git] / osfmk / arm / cswitch.s
1 /*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <machine/asm.h>
29 #include <arm/proc_reg.h>
30 #include "assym.s"
31
32 /*
33 * save_vfp_registers
34 *
35 * Expects a pointer to the VFP save area in r3; saves the callee-saved registers to that save area.
36 * Clobbers r2 and r3.
37 */
38 .macro save_vfp_registers
39 #if __ARM_VFP__
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}
46 #else
47 fstmias r3!, {s16-s31}
48 #endif /* __ARM_VFP__ >= 3 */
49 #endif /* __ARM_VFP__ */
50 .endmacro
51
52 /*
53 * load_vfp_registers
54 *
55 * Expects a pointer to the VFP save area in r3; loads the callee-saved registers from that save area.
56 * Clobbers r2 and r3.
57 */
58 .macro load_vfp_registers
59 #if __ARM_VFP__
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}
64 #else
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__ */
70 .endmacro
71
72 /*
73 * void machine_load_context(thread_t thread)
74 *
75 * Load the context for the first thread to run on a
76 * cpu, and go.
77 */
78 .syntax unified
79 .text
80 .align 2
81 .globl EXT(machine_load_context)
82
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
88 orr r1, r1, r2 //
89 mcr p15, 0, r1, c13, c0, 3 // Write TPIDRURO
90 mov r1, #0
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
95 add r3, r3, SS_R4
96 ldmia r3!, {r4-r14} // Load thread status
97 bx lr // Return
98
99 /*
100 * typedef void (*thread_continue_t)(void *param, wait_result_t)
101 *
102 * void Call_continuation( thread_continue_t continuation,
103 * void *param,
104 * wait_result_t wresult,
105 * bool enable interrupts)
106 */
107 .text
108 .align 5
109 .globl EXT(Call_continuation)
110
111 LEXT(Call_continuation)
112 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
113 ldr sp, [r9, TH_KSTACKPTR] // Set stack pointer
114 mov r7, #0 // Clear frame pointer
115
116 mov r4,r0 // Load continuation
117 mov r5,r1 // continuation parameter
118 mov r6,r2 // Set wait result arg
119
120 teq r3, #0
121 beq 1f
122 mov r0, #1
123 bl _ml_set_interrupts_enabled
124 1:
125
126 mov r0,r5 // Set first parameter
127 mov r1,r6 // Set wait result arg
128 blx r4 // Branch to continuation
129
130 mrc p15, 0, r0, c13, c0, 4 // Read TPIDRPRW
131 LOAD_ADDR_PC(thread_terminate)
132 b . // Not reach
133
134
135 /*
136 * thread_t Switch_context(thread_t old,
137 * void (*cont)(void),
138 * thread_t new)
139 */
140 .text
141 .align 5
142 .globl EXT(Switch_context)
143
144 LEXT(Switch_context)
145 teq r1, #0 // Test if blocking on continuaton
146 bne switch_threads // No need to save GPR/NEON state if we are
147 #if __ARM_VFP__
148 mov r1, r2 // r2 will be clobbered by the save, so preserve it
149 ldr r3, [r0, TH_KSTACKPTR] // Get old kernel stack top
150 add r3, r3, SS_KVFP // Get the kernel VFP save area for the old thread...
151 save_vfp_registers // ...and save our VFP state to it
152 mov r2, r1 // Restore r2 (the new thread pointer)
153 #endif /* __ARM_VFP__ */
154 ldr r3, [r0, TH_KSTACKPTR] // Get old kernel stack top
155 add r3, r3, SS_R4
156 stmia r3!, {r4-r14} // Save general registers to pcb
157 switch_threads:
158 ldr r3, [r2, TH_KSTACKPTR] // get kernel stack top
159 mcr p15, 0, r2, c13, c0, 4 // Write TPIDRPRW
160 ldr r6, [r2, TH_CTH_SELF]
161 mrc p15, 0, r5, c13, c0, 3 // Read TPIDRURO
162 and r5, r5, #3 // Extract cpu number
163 orr r6, r6, r5
164 mcr p15, 0, r6, c13, c0, 3 // Write TPIDRURO
165 mov r6, #0
166 mcr p15, 0, r6, c13, c0, 2 // Write TPIDRURW
167 load_reg:
168 add r3, r3, SS_R4
169 ldmia r3!, {r4-r14} // Restore new thread status
170 #if __ARM_VFP__
171 ldr r3, [r2, TH_KSTACKPTR] // get kernel stack top
172 add r3, r3, SS_KVFP // Get the kernel VFP save area for the new thread...
173 load_vfp_registers // ...and load the saved state
174 #endif /* __ARM_VFP__ */
175 bx lr // Return
176
177 /*
178 * thread_t Shutdown_context(void (*doshutdown)(processor_t), processor_t processor)
179 *
180 */
181 .text
182 .align 5
183 .globl EXT(Shutdown_context)
184
185 LEXT(Shutdown_context)
186 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
187 #if __ARM_VFP__
188 ldr r3, [r9, TH_KSTACKPTR] // get kernel stack top
189 add r3, r3, SS_KVFP // Get the kernel VFP save area for the current thread...
190 save_vfp_registers // ...and save our VFP state to it
191 #endif
192 ldr r3, [r9, TH_KSTACKPTR] // Get kernel stack top
193 add r3, r3, SS_R4
194 stmia r3!, {r4-r14} // Save general registers to pcb
195 cpsid if // Disable FIQ IRQ
196
197 ldr r12, [r9, ACT_CPUDATAP] // Get current cpu
198 ldr sp, [r12, CPU_ISTACKPTR] // Switch to interrupt stack
199 LOAD_ADDR_PC(cpu_doshutdown)
200
201 /*
202 * thread_t Idle_context(void)
203 *
204 */
205 .text
206 .align 5
207 .globl EXT(Idle_context)
208
209 LEXT(Idle_context)
210
211 mrc p15, 0, r9, c13, c0, 4 // Read TPIDRPRW
212 #if __ARM_VFP__
213 ldr r3, [r9, TH_KSTACKPTR] // get kernel stack top
214 add r3, r3, SS_KVFP // Get the kernel VFP save area for the current thread...
215 save_vfp_registers // ...and save our VFP state to it
216 #endif
217 ldr r3, [r9, TH_KSTACKPTR] // Get kernel stack top
218 add r3, r3, SS_R4
219 stmia r3!, {r4-r14} // Save general registers to pcb
220
221 ldr r12, [r9, ACT_CPUDATAP] // Get current cpu
222 ldr sp, [r12, CPU_ISTACKPTR] // Switch to interrupt stack
223 LOAD_ADDR_PC(cpu_idle)
224
225 /*
226 * thread_t Idle_context(void)
227 *
228 */
229 .text
230 .align 5
231 .globl EXT(Idle_load_context)
232
233 LEXT(Idle_load_context)
234
235 mrc p15, 0, r12, c13, c0, 4 // Read TPIDRPRW
236 ldr r3, [r12, TH_KSTACKPTR] // Get kernel stack top
237 add r3, r3, SS_R4
238 ldmia r3!, {r4-r14} // Restore new thread status
239 #if __ARM_VFP__
240 ldr r3, [r9, TH_KSTACKPTR] // get kernel stack top
241 add r3, r3, SS_KVFP // Get the kernel VFP save area for the current thread...
242 load_vfp_registers // ...and load the saved state
243 #endif
244 bx lr // Return
245
246 /*
247 * void vfp_save(struct arm_vfpsaved_state *vfp_ss)
248 */
249 .text
250 .align 2
251 .globl EXT(vfp_save)
252
253 LEXT(vfp_save)
254 #if __ARM_VFP__
255 fmrx r1, fpscr // Get the current FPSCR...
256 str r1, [r0, VSS_FPSCR] // ...and save it to the save area
257 #if (__ARM_VFP__ >= 3)
258 vstmia.64 r0!, {d0-d3} // Save vfp registers
259 vstmia.64 r0!, {d4-d7}
260 vstmia.64 r0!, {d8-d11}
261 vstmia.64 r0!, {d12-d15}
262 vstmia.64 r0!, {d16-d19}
263 vstmia.64 r0!, {d20-d23}
264 vstmia.64 r0!, {d24-d27}
265 vstmia.64 r0!, {d28-d31}
266 #else
267 fstmias r0!, {s0-s31} // Save vfp registers
268 #endif
269 #endif /* __ARM_VFP__ */
270 bx lr // Return
271
272 /*
273 * void vfp_load(struct arm_vfpsaved_state *vfp_ss)
274 *
275 * Loads the state in vfp_ss into the VFP registers.
276 */
277 .text
278 .align 2
279 .globl EXT(vfp_load)
280 LEXT(vfp_load)
281 #if __ARM_VFP__
282 /* r0: vfp_ss, r1: unused, r2: unused, r3: unused */
283 mov r1, r0
284 #if (__ARM_VFP__ >= 3)
285 vldmia.64 r0!, {d0-d3} // Restore vfp registers
286 vldmia.64 r0!, {d4-d7}
287 vldmia.64 r0!, {d8-d11}
288 vldmia.64 r0!, {d12-d15}
289 vldmia.64 r0!, {d16-d19}
290 vldmia.64 r0!, {d20-d23}
291 vldmia.64 r0!, {d24-d27}
292 vldmia.64 r0!, {d28-d31}
293 #else
294 fldmias r0!, {s0-s31} // Restore vfp registers
295 #endif /* __ARM_VFP__ >= 3 */
296 ldr r1, [r1, VSS_FPSCR] // Get fpscr from the save state...
297 fmxr fpscr, r1 // ...and load it into the register
298 #endif /* __ARM_VFP__ */
299 bx lr // Return
300
301 #include "globals_asm.h"
302
303 LOAD_ADDR_GEN_DEF(thread_terminate)
304 LOAD_ADDR_GEN_DEF(cpu_doshutdown)
305 LOAD_ADDR_GEN_DEF(cpu_idle)
306
307 /* vim: set ts=4: */
308