]> git.saurik.com Git - apple/xnu.git/blob - osfmk/arm64/cswitch.s
xnu-4903.221.2.tar.gz
[apple/xnu.git] / osfmk / arm64 / 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 <arm64/machine_machdep.h>
30 #include <arm64/proc_reg.h>
31 #include "assym.s"
32
33 /*
34 * save_general_registers
35 *
36 * Saves variable registers to kernel PCB.
37 * arg0 - thread_kernel_state pointer
38 * arg1 - Scratch register
39 */
40
41 .macro save_general_registers
42 /* AAPCS-64 Page 14
43 *
44 * A subroutine invocation must preserve the contents of the registers r19-r29
45 * and SP. We also save IP0 and IP1, as machine_idle uses IP0 for saving the LR.
46 */
47 stp x16, x17, [$0, SS64_X16]
48 stp x19, x20, [$0, SS64_X19]
49 stp x21, x22, [$0, SS64_X21]
50 stp x23, x24, [$0, SS64_X23]
51 stp x25, x26, [$0, SS64_X25]
52 stp x27, x28, [$0, SS64_X27]
53 stp fp, lr, [$0, SS64_FP]
54 mov $1, sp
55 str $1, [$0, SS64_SP]
56
57 /* AAPCS-64 Page 14
58 *
59 * Registers d8-d15 (s8-s15) must be preserved by a callee across subroutine
60 * calls; the remaining registers (v0-v7, v16-v31) do not need to be preserved
61 * (or should be preserved by the caller).
62 */
63 str d8, [$0, NS64_D8]
64 str d9, [$0, NS64_D9]
65 str d10,[$0, NS64_D10]
66 str d11,[$0, NS64_D11]
67 str d12,[$0, NS64_D12]
68 str d13,[$0, NS64_D13]
69 str d14,[$0, NS64_D14]
70 str d15,[$0, NS64_D15]
71 .endmacro
72
73 /*
74 * load_general_registers
75 *
76 * Loads variable registers from kernel PCB.
77 * arg0 - thread_kernel_state pointer
78 * arg1 - Scratch register
79 */
80 .macro load_general_registers
81
82 ldp x16, x17, [$0, SS64_X16]
83 ldp x19, x20, [$0, SS64_X19]
84 ldp x21, x22, [$0, SS64_X21]
85 ldp x23, x24, [$0, SS64_X23]
86 ldp x25, x26, [$0, SS64_X25]
87 ldp x27, x28, [$0, SS64_X27]
88 ldp fp, lr, [$0, SS64_FP]
89 ldr $1, [$0, SS64_SP]
90 mov sp, $1
91
92 ldr d8, [$0, NS64_D8]
93 ldr d9, [$0, NS64_D9]
94 ldr d10,[$0, NS64_D10]
95 ldr d11,[$0, NS64_D11]
96 ldr d12,[$0, NS64_D12]
97 ldr d13,[$0, NS64_D13]
98 ldr d14,[$0, NS64_D14]
99 ldr d15,[$0, NS64_D15]
100 .endmacro
101
102 /*
103 * set_thread_registers
104 *
105 * Updates thread registers during context switch
106 * arg0 - New thread pointer
107 * arg1 - Scratch register
108 * arg2 - Scratch register
109 */
110 .macro set_thread_registers
111 msr TPIDR_EL1, $0 // Write new thread pointer to TPIDR_EL1
112 ldr $1, [$0, TH_CTH_SELF] // Get cthread pointer
113 mrs $2, TPIDRRO_EL0 // Extract cpu number from TPIDRRO_EL0
114 and $2, $2, #(MACHDEP_CPUNUM_MASK)
115 orr $2, $1, $2 // Save new cthread/cpu to TPIDRRO_EL0
116 msr TPIDRRO_EL0, $2
117 ldr $1, [$0, TH_CTH_DATA] // Get new cthread data pointer
118 msr TPIDR_EL0, $1 // Save data pointer to TPIDRRW_EL0
119 /* ARM64_TODO Reserve x18 until we decide what to do with it */
120 mov x18, $1 // ... and trash reserved x18
121 .endmacro
122
123
124 /*
125 * void machine_load_context(thread_t thread)
126 *
127 * Load the context for the first thread to run on a
128 * cpu, and go.
129 */
130 .text
131 .align 2
132 .globl EXT(machine_load_context)
133
134 LEXT(machine_load_context)
135 set_thread_registers x0, x1, x2
136 ldr x1, [x0, TH_KSTACKPTR] // Get top of kernel stack
137 load_general_registers x1, x2
138 mov x0, #0 // Clear argument to thread_continue
139 ret
140
141 /*
142 * typedef void (*thread_continue_t)(void *param, wait_result_t)
143 *
144 * void Call_continuation( thread_continue_t continuation,
145 * void *param,
146 * wait_result_t wresult,
147 * bool enable interrupts)
148 */
149 .text
150 .align 5
151 .globl EXT(Call_continuation)
152
153 LEXT(Call_continuation)
154 mrs x4, TPIDR_EL1 // Get the current thread pointer
155
156 /* ARM64_TODO arm loads the kstack top instead of arg4. What should we use? */
157 ldr x5, [x4, TH_KSTACKPTR] // Get the top of the kernel stack
158 mov sp, x5 // Set stack pointer
159 mov fp, #0 // Clear the frame pointer
160
161
162 mov x20, x0 //continuation
163 mov x21, x1 //continuation parameter
164 mov x22, x2 //wait result
165
166 cbz x3, 1f
167 mov x0, #1
168 bl _ml_set_interrupts_enabled
169 1:
170
171 mov x0, x21 // Set the first parameter
172 mov x1, x22 // Set the wait result arg
173 blr x20 // Branch to the continuation
174 mrs x0, TPIDR_EL1 // Get the current thread pointer
175 b EXT(thread_terminate) // Kill the thread
176
177
178 /*
179 * thread_t Switch_context(thread_t old,
180 * void (*cont)(void),
181 * thread_t new)
182 */
183 .text
184 .align 5
185 .globl EXT(Switch_context)
186
187 LEXT(Switch_context)
188 cbnz x1, Lswitch_threads // Skip saving old state if blocking on continuation
189 ldr x3, [x0, TH_KSTACKPTR] // Get the old kernel stack top
190 save_general_registers x3, x4
191 Lswitch_threads:
192 set_thread_registers x2, x3, x4
193 ldr x3, [x2, TH_KSTACKPTR]
194 load_general_registers x3, x4
195 ret
196
197 /*
198 * thread_t Shutdown_context(void (*doshutdown)(processor_t), processor_t processor)
199 *
200 */
201 .text
202 .align 5
203 .globl EXT(Shutdown_context)
204
205 LEXT(Shutdown_context)
206 mrs x10, TPIDR_EL1 // Get thread pointer
207 ldr x11, [x10, TH_KSTACKPTR] // Get the top of the kernel stack
208 save_general_registers x11, x12
209 msr DAIFSet, #(DAIFSC_FIQF | DAIFSC_IRQF) // Disable interrupts
210 ldr x11, [x10, ACT_CPUDATAP] // Get current cpu
211 ldr x12, [x11, CPU_ISTACKPTR] // Switch to interrupt stack
212 mov sp, x12
213 b EXT(cpu_doshutdown)
214
215
216 /*
217 * thread_t Idle_context(void)
218 *
219 */
220 .text
221 .align 5
222 .globl EXT(Idle_context)
223
224 LEXT(Idle_context)
225 mrs x0, TPIDR_EL1 // Get thread pointer
226 ldr x1, [x0, TH_KSTACKPTR] // Get the top of the kernel stack
227 save_general_registers x1, x2
228 ldr x1, [x0, ACT_CPUDATAP] // Get current cpu
229 ldr x2, [x1, CPU_ISTACKPTR] // Switch to interrupt stack
230 mov sp, x2
231 b EXT(cpu_idle)
232
233 /*
234 * thread_t Idle_context(void)
235 *
236 */
237 .text
238 .align 5
239 .globl EXT(Idle_load_context)
240
241 LEXT(Idle_load_context)
242 mrs x0, TPIDR_EL1 // Get thread pointer
243 ldr x1, [x0, TH_KSTACKPTR] // Get the top of the kernel stack
244 load_general_registers x1, x2
245 ret
246
247 .align 2
248 .globl EXT(machine_set_current_thread)
249 LEXT(machine_set_current_thread)
250 set_thread_registers x0, x1, x2
251 ret