1// Copyright 2009 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// Offsets into Thread Environment Block (pointer in FS)
11#define TEB_TlsSlots 0xE10
12#define TEB_ArbitraryPtr 0x14
13
14TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
15	JMP	runtime·asmstdcall(SB)
16
17// void runtime·asmstdcall(void *c);
18TEXT runtime·asmstdcall(SB),NOSPLIT,$0
19	MOVL	fn+0(FP), BX
20	MOVL	SP, BP	// save stack pointer
21
22	// SetLastError(0).
23	MOVL	$0, 0x34(FS)
24
25	MOVL	libcall_n(BX), CX
26
27	// Fast version, do not store args on the stack.
28	CMPL	CX, $0
29	JE	docall
30
31	// Copy args to the stack.
32	MOVL	CX, AX
33	SALL	$2, AX
34	SUBL	AX, SP			// room for args
35	MOVL	SP, DI
36	MOVL	libcall_args(BX), SI
37	CLD
38	REP; MOVSL
39
40docall:
41	// Call stdcall or cdecl function.
42	// DI SI BP BX are preserved, SP is not
43	CALL	libcall_fn(BX)
44	MOVL	BP, SP
45
46	// Return result.
47	MOVL	fn+0(FP), BX
48	MOVL	AX, libcall_r1(BX)
49	MOVL	DX, libcall_r2(BX)
50
51	// GetLastError().
52	MOVL	0x34(FS), AX
53	MOVL	AX, libcall_err(BX)
54
55	RET
56
57// faster get/set last error
58TEXT runtime·getlasterror(SB),NOSPLIT,$0
59	MOVL	0x34(FS), AX
60	MOVL	AX, ret+0(FP)
61	RET
62
63TEXT runtime·sigFetchGSafe<ABIInternal>(SB),NOSPLIT,$0
64	get_tls(AX)
65	CMPL	AX, $0
66	JE	2(PC)
67	MOVL	g(AX), AX
68	MOVL	AX, ret+0(FP)
69	RET
70
71// Called by Windows as a Vectored Exception Handler (VEH).
72// AX is pointer to struct containing
73// exception record and context pointers.
74// CX is the kind of sigtramp function.
75// Return value of sigtrampgo is stored in AX.
76TEXT sigtramp<>(SB),NOSPLIT,$0-0
77	SUBL	$40, SP
78
79	// save callee-saved registers
80	MOVL	BX, 28(SP)
81	MOVL	BP, 16(SP)
82	MOVL	SI, 20(SP)
83	MOVL	DI, 24(SP)
84
85	MOVL	AX, 0(SP)
86	MOVL	CX, 4(SP)
87	CALL	runtime·sigtrampgo(SB)
88	MOVL	8(SP), AX
89
90	// restore callee-saved registers
91	MOVL	24(SP), DI
92	MOVL	20(SP), SI
93	MOVL	16(SP), BP
94	MOVL	28(SP), BX
95
96	ADDL	$40, SP
97	// RET 4 (return and pop 4 bytes parameters)
98	BYTE $0xC2; WORD $4
99	RET // unreached; make assembler happy
100
101// Trampoline to resume execution from exception handler.
102// This is part of the control flow guard workaround.
103// It switches stacks and jumps to the continuation address.
104// DX and CX are set above at the end of sigtrampgo
105// in the context that starts executing at sigresume.
106TEXT runtime·sigresume(SB),NOSPLIT,$0
107	MOVL	DX, SP
108	JMP	CX
109
110TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
111	MOVL	argframe+0(FP), AX
112	MOVL	$const_callbackVEH, CX
113	JMP	sigtramp<>(SB)
114
115TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
116	// is never called
117	INT	$3
118
119TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
120	MOVL	argframe+0(FP), AX
121	MOVL	$const_callbackLastVCH, CX
122	JMP	sigtramp<>(SB)
123
124TEXT runtime·callbackasm1(SB),NOSPLIT,$0
125	MOVL	0(SP), AX	// will use to find our callback context
126
127	// remove return address from stack, we are not returning to callbackasm, but to its caller.
128	ADDL	$4, SP
129
130	// address to callback parameters into CX
131	LEAL	4(SP), CX
132
133	// save registers as required for windows callback
134	PUSHL	DI
135	PUSHL	SI
136	PUSHL	BP
137	PUSHL	BX
138
139	// Go ABI requires DF flag to be cleared.
140	CLD
141
142	// determine index into runtime·cbs table
143	SUBL	$runtime·callbackasm(SB), AX
144	MOVL	$0, DX
145	MOVL	$5, BX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
146	DIVL	BX
147	SUBL	$1, AX	// subtract 1 because return PC is to the next slot
148
149	// Create a struct callbackArgs on our stack.
150	SUBL	$(12+callbackArgs__size), SP
151	MOVL	AX, (12+callbackArgs_index)(SP)		// callback index
152	MOVL	CX, (12+callbackArgs_args)(SP)		// address of args vector
153	MOVL	$0, (12+callbackArgs_result)(SP)	// result
154	LEAL	12(SP), AX	// AX = &callbackArgs{...}
155
156	// Call cgocallback, which will call callbackWrap(frame).
157	MOVL	$0, 8(SP)	// context
158	MOVL	AX, 4(SP)	// frame (address of callbackArgs)
159	LEAL	·callbackWrap(SB), AX
160	MOVL	AX, 0(SP)	// PC of function to call
161	CALL	runtime·cgocallback(SB)
162
163	// Get callback result.
164	MOVL	(12+callbackArgs_result)(SP), AX
165	// Get popRet.
166	MOVL	(12+callbackArgs_retPop)(SP), CX	// Can't use a callee-save register
167	ADDL	$(12+callbackArgs__size), SP
168
169	// restore registers as required for windows callback
170	POPL	BX
171	POPL	BP
172	POPL	SI
173	POPL	DI
174
175	// remove callback parameters before return (as per Windows spec)
176	POPL	DX
177	ADDL	CX, SP
178	PUSHL	DX
179
180	CLD
181
182	RET
183
184// void tstart(M *newm);
185TEXT tstart<>(SB),NOSPLIT,$8-4
186	MOVL	newm+0(FP), CX		// m
187	MOVL	m_g0(CX), DX		// g
188
189	// Layout new m scheduler stack on os stack.
190	MOVL	SP, AX
191	MOVL	AX, (g_stack+stack_hi)(DX)
192	SUBL	$(64*1024), AX		// initial stack size (adjusted later)
193	MOVL	AX, (g_stack+stack_lo)(DX)
194	ADDL	$const_stackGuard, AX
195	MOVL	AX, g_stackguard0(DX)
196	MOVL	AX, g_stackguard1(DX)
197
198	// Set up tls.
199	LEAL	m_tls(CX), DI
200	MOVL	CX, g_m(DX)
201	MOVL	DX, g(DI)
202	MOVL	DI, 4(SP)
203	CALL	runtime·setldt(SB) // clobbers CX and DX
204
205	// Someday the convention will be D is always cleared.
206	CLD
207
208	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
209	CALL	runtime·mstart(SB)
210
211	RET
212
213// uint32 tstart_stdcall(M *newm);
214TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
215	MOVL	newm+0(FP), BX
216
217	PUSHL	BX
218	CALL	tstart<>(SB)
219	POPL	BX
220
221	// Adjust stack for stdcall to return properly.
222	MOVL	(SP), AX		// save return address
223	ADDL	$4, SP			// remove single parameter
224	MOVL	AX, (SP)		// restore return address
225
226	XORL	AX, AX			// return 0 == success
227
228	RET
229
230// setldt(int slot, int base, int size)
231TEXT runtime·setldt(SB),NOSPLIT,$0-12
232	MOVL	base+4(FP), DX
233	MOVL	runtime·tls_g(SB), CX
234	MOVL	DX, 0(CX)(FS)
235	RET
236
237TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
238loop:
239	MOVL	(_INTERRUPT_TIME+time_hi1), AX
240	MOVL	(_INTERRUPT_TIME+time_lo), CX
241	MOVL	(_INTERRUPT_TIME+time_hi2), DI
242	CMPL	AX, DI
243	JNE	loop
244
245	// wintime = DI:CX, multiply by 100
246	MOVL	$100, AX
247	MULL	CX
248	IMULL	$100, DI
249	ADDL	DI, DX
250	// wintime*100 = DX:AX
251	MOVL	AX, ret_lo+0(FP)
252	MOVL	DX, ret_hi+4(FP)
253	RET
254
255// This is called from rt0_go, which runs on the system stack
256// using the initial stack allocated by the OS.
257TEXT runtime·wintls(SB),NOSPLIT,$0
258	// Allocate a TLS slot to hold g across calls to external code
259	MOVL	SP, BP
260	MOVL	runtime·_TlsAlloc(SB), AX
261	CALL	AX
262	MOVL	BP, SP
263
264	MOVL	AX, CX	// TLS index
265
266	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
267	CMPL	CX, $64
268	JB	ok
269	// Fallback to the TEB arbitrary pointer.
270	// TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
271	MOVL	$TEB_ArbitraryPtr, CX
272	JMP	settls
273ok:
274	// Convert the TLS index at CX into
275	// an offset from TEB_TlsSlots.
276	SHLL	$2, CX
277
278	// Save offset from TLS into tls_g.
279	ADDL	$TEB_TlsSlots, CX
280settls:
281	MOVL	CX, runtime·tls_g(SB)
282	RET
283