Text file
src/runtime/sys_windows_arm.s
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "go_asm.h"
6 #include "go_tls.h"
7 #include "textflag.h"
8 #include "time_windows.h"
9
10 // Note: For system ABI, R0-R3 are args, R4-R11 are callee-save.
11
12 TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
13 B runtime·asmstdcall(SB)
14
15 // void runtime·asmstdcall(void *c);
16 TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
17 MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
18 MOVW R0, R4 // put libcall * in r4
19 MOVW R13, R5 // save stack pointer in r5
20
21 // SetLastError(0)
22 MOVW $0, R0
23 MRC 15, 0, R1, C13, C0, 2
24 MOVW R0, 0x34(R1)
25
26 MOVW 8(R4), R12 // libcall->args
27
28 // Do we have more than 4 arguments?
29 MOVW 4(R4), R0 // libcall->n
30 SUB.S $4, R0, R2
31 BLE loadregs
32
33 // Reserve stack space for remaining args
34 SUB R2<<2, R13
35 BIC $0x7, R13 // alignment for ABI
36
37 // R0: count of arguments
38 // R1:
39 // R2: loop counter, from 0 to (n-4)
40 // R3: scratch
41 // R4: pointer to libcall struct
42 // R12: libcall->args
43 MOVW $0, R2
44 stackargs:
45 ADD $4, R2, R3 // r3 = args[4 + i]
46 MOVW R3<<2(R12), R3
47 MOVW R3, R2<<2(R13) // stack[i] = r3
48
49 ADD $1, R2 // i++
50 SUB $4, R0, R3 // while (i < (n - 4))
51 CMP R3, R2
52 BLT stackargs
53
54 loadregs:
55 CMP $3, R0
56 MOVW.GT 12(R12), R3
57
58 CMP $2, R0
59 MOVW.GT 8(R12), R2
60
61 CMP $1, R0
62 MOVW.GT 4(R12), R1
63
64 CMP $0, R0
65 MOVW.GT 0(R12), R0
66
67 BIC $0x7, R13 // alignment for ABI
68 MOVW 0(R4), R12 // branch to libcall->fn
69 BL (R12)
70
71 MOVW R5, R13 // free stack space
72 MOVW R0, 12(R4) // save return value to libcall->r1
73 MOVW R1, 16(R4)
74
75 // GetLastError
76 MRC 15, 0, R1, C13, C0, 2
77 MOVW 0x34(R1), R0
78 MOVW R0, 20(R4) // store in libcall->err
79
80 MOVM.IA.W (R13), [R4, R5, R15]
81
82 TEXT runtime·getlasterror(SB),NOSPLIT,$0
83 MRC 15, 0, R0, C13, C0, 2
84 MOVW 0x34(R0), R0
85 MOVW R0, ret+0(FP)
86 RET
87
88 // Called by Windows as a Vectored Exception Handler (VEH).
89 // R0 is pointer to struct containing
90 // exception record and context pointers.
91 // R1 is the kind of sigtramp function.
92 // Return value of sigtrampgo is stored in R0.
93 TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
94 MOVM.DB.W [R4-R11, R14], (R13) // push {r4-r11, lr} (SP-=40)
95 SUB $(16), R13 // reserve space for parameters/retval to go call
96
97 MOVW R0, R6 // Save param0
98 MOVW R1, R7 // Save param1
99 BL runtime·load_g(SB) // Clobbers R0
100
101 MOVW $0, R4
102 MOVW R4, 0(R13) // No saved link register.
103 MOVW R6, 4(R13) // Move arg0 into position
104 MOVW R7, 8(R13) // Move arg1 into position
105 BL runtime·sigtrampgo(SB)
106 MOVW 12(R13), R0 // Fetch return value from stack
107
108 ADD $(16), R13 // free locals
109 MOVM.IA.W (R13), [R4-R11, R14] // pop {r4-r11, lr}
110
111 B (R14) // return
112
113 // Trampoline to resume execution from exception handler.
114 // This is part of the control flow guard workaround.
115 // It switches stacks and jumps to the continuation address.
116 // R0 and R1 are set above at the end of sigtrampgo
117 // in the context that starts executing at sigresume.
118 TEXT runtime·sigresume(SB),NOSPLIT|NOFRAME,$0
119 // Important: do not smash LR,
120 // which is set to a live value when handling
121 // a signal by pushing a call to sigpanic onto the stack.
122 MOVW R0, R13
123 B (R1)
124
125 TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
126 MOVW $const_callbackVEH, R1
127 B sigtramp<>(SB)
128
129 TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0
130 MOVW $const_callbackFirstVCH, R1
131 B sigtramp<>(SB)
132
133 TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0
134 MOVW $const_callbackLastVCH, R1
135 B sigtramp<>(SB)
136
137 TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0
138 // On entry, the trampoline in zcallback_windows_arm.s left
139 // the callback index in R12 (which is volatile in the C ABI).
140
141 // Push callback register arguments r0-r3. We do this first so
142 // they're contiguous with stack arguments.
143 MOVM.DB.W [R0-R3], (R13)
144 // Push C callee-save registers r4-r11 and lr.
145 MOVM.DB.W [R4-R11, R14], (R13)
146 SUB $(16 + callbackArgs__size), R13 // space for locals
147
148 // Create a struct callbackArgs on our stack.
149 MOVW R12, (16+callbackArgs_index)(R13) // callback index
150 MOVW $(16+callbackArgs__size+4*9)(R13), R0
151 MOVW R0, (16+callbackArgs_args)(R13) // address of args vector
152 MOVW $0, R0
153 MOVW R0, (16+callbackArgs_result)(R13) // result
154
155 // Prepare for entry to Go.
156 BL runtime·load_g(SB)
157
158 // Call cgocallback, which will call callbackWrap(frame).
159 MOVW $0, R0
160 MOVW R0, 12(R13) // context
161 MOVW $16(R13), R1 // R1 = &callbackArgs{...}
162 MOVW R1, 8(R13) // frame (address of callbackArgs)
163 MOVW $·callbackWrap(SB), R1
164 MOVW R1, 4(R13) // PC of function to call
165 BL runtime·cgocallback(SB)
166
167 // Get callback result.
168 MOVW (16+callbackArgs_result)(R13), R0
169
170 ADD $(16 + callbackArgs__size), R13 // free locals
171 MOVM.IA.W (R13), [R4-R11, R12] // pop {r4-r11, lr=>r12}
172 ADD $(4*4), R13 // skip r0-r3
173 B (R12) // return
174
175 // uint32 tstart_stdcall(M *newm);
176 TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
177 MOVM.DB.W [R4-R11, R14], (R13) // push {r4-r11, lr}
178
179 MOVW m_g0(R0), g
180 MOVW R0, g_m(g)
181 BL runtime·save_g(SB)
182
183 // Layout new m scheduler stack on os stack.
184 MOVW R13, R0
185 MOVW R0, g_stack+stack_hi(g)
186 SUB $(64*1024), R0
187 MOVW R0, (g_stack+stack_lo)(g)
188 MOVW R0, g_stackguard0(g)
189 MOVW R0, g_stackguard1(g)
190
191 BL runtime·emptyfunc(SB) // fault if stack check is wrong
192 BL runtime·mstart(SB)
193
194 // Exit the thread.
195 MOVW $0, R0
196 MOVM.IA.W (R13), [R4-R11, R15] // pop {r4-r11, pc}
197
198 TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
199 B runtime·armPublicationBarrier(SB)
200
201 // never called (this is a GOARM=7 platform)
202 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$0
203 MOVW $0xabcd, R0
204 MOVW R0, (R0)
205 RET
206
207 TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
208 MOVW $_INTERRUPT_TIME, R3
209 loop:
210 MOVW time_hi1(R3), R1
211 DMB MB_ISH
212 MOVW time_lo(R3), R0
213 DMB MB_ISH
214 MOVW time_hi2(R3), R2
215 CMP R1, R2
216 BNE loop
217
218 // wintime = R1:R0, multiply by 100
219 MOVW $100, R2
220 MULLU R0, R2, (R4, R3) // R4:R3 = R1:R0 * R2
221 MULA R1, R2, R4, R4
222
223 // wintime*100 = R4:R3
224 MOVW R3, ret_lo+0(FP)
225 MOVW R4, ret_hi+4(FP)
226 RET
227
228 // save_g saves the g register (R10) into thread local memory
229 // so that we can call externally compiled
230 // ARM code that will overwrite those registers.
231 // NOTE: runtime.gogo assumes that R1 is preserved by this function.
232 // runtime.mcall assumes this function only clobbers R0 and R11.
233 // Returns with g in R0.
234 // Save the value in the _TEB->TlsSlots array.
235 // Effectively implements TlsSetValue().
236 // tls_g stores the TLS slot allocated TlsAlloc().
237 TEXT runtime·save_g(SB),NOSPLIT,$0
238 MRC 15, 0, R0, C13, C0, 2
239 ADD $0xe10, R0
240 MOVW $runtime·tls_g(SB), R11
241 MOVW (R11), R11
242 MOVW g, R11<<2(R0)
243 MOVW g, R0 // preserve R0 across call to setg<>
244 RET
245
246 // load_g loads the g register from thread-local memory,
247 // for use after calling externally compiled
248 // ARM code that overwrote those registers.
249 // Get the value from the _TEB->TlsSlots array.
250 // Effectively implements TlsGetValue().
251 TEXT runtime·load_g(SB),NOSPLIT,$0
252 MRC 15, 0, R0, C13, C0, 2
253 ADD $0xe10, R0
254 MOVW $runtime·tls_g(SB), g
255 MOVW (g), g
256 MOVW g<<2(R0), g
257 RET
258
259 // This is called from rt0_go, which runs on the system stack
260 // using the initial stack allocated by the OS.
261 // It calls back into standard C using the BL below.
262 // To do that, the stack pointer must be 8-byte-aligned.
263 TEXT runtime·_initcgo(SB),NOSPLIT|NOFRAME,$0
264 MOVM.DB.W [R4, R14], (R13) // push {r4, lr}
265
266 // Ensure stack is 8-byte aligned before calling C code
267 MOVW R13, R4
268 BIC $0x7, R13
269
270 // Allocate a TLS slot to hold g across calls to external code
271 MOVW $runtime·_TlsAlloc(SB), R0
272 MOVW (R0), R0
273 BL (R0)
274
275 // Assert that slot is less than 64 so we can use _TEB->TlsSlots
276 CMP $64, R0
277 MOVW $runtime·abort(SB), R1
278 BL.GE (R1)
279
280 // Save Slot into tls_g
281 MOVW $runtime·tls_g(SB), R1
282 MOVW R0, (R1)
283
284 MOVW R4, R13
285 MOVM.IA.W (R13), [R4, R15] // pop {r4, pc}
286
287 // Holds the TLS Slot, which was allocated by TlsAlloc()
288 GLOBL runtime·tls_g+0(SB), NOPTR, $4
289
View as plain text