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
9// void runtime·asmstdcall(void *c);
10TEXT runtime·asmstdcall(SB),NOSPLIT,$0
11	MOVL	fn+0(FP), BX
12
13	// SetLastError(0).
14	MOVL	$0, 0x34(FS)
15
16	// Copy args to the stack.
17	MOVL	SP, BP
18	MOVL	libcall_n(BX), CX	// words
19	MOVL	CX, AX
20	SALL	$2, AX
21	SUBL	AX, SP			// room for args
22	MOVL	SP, DI
23	MOVL	libcall_args(BX), SI
24	CLD
25	REP; MOVSL
26
27	// Call stdcall or cdecl function.
28	// DI SI BP BX are preserved, SP is not
29	CALL	libcall_fn(BX)
30	MOVL	BP, SP
31
32	// Return result.
33	MOVL	fn+0(FP), BX
34	MOVL	AX, libcall_r1(BX)
35	MOVL	DX, libcall_r2(BX)
36
37	// GetLastError().
38	MOVL	0x34(FS), AX
39	MOVL	AX, libcall_err(BX)
40
41	RET
42
43TEXT	runtime·badsignal2(SB),NOSPLIT,$24
44	// stderr
45	MOVL	$-12, 0(SP)
46	MOVL	SP, BP
47	CALL	*runtime·_GetStdHandle(SB)
48	MOVL	BP, SP
49
50	MOVL	AX, 0(SP)	// handle
51	MOVL	$runtime·badsignalmsg(SB), DX // pointer
52	MOVL	DX, 4(SP)
53	MOVL	runtime·badsignallen(SB), DX // count
54	MOVL	DX, 8(SP)
55	LEAL	20(SP), DX  // written count
56	MOVL	$0, 0(DX)
57	MOVL	DX, 12(SP)
58	MOVL	$0, 16(SP) // overlapped
59	CALL	*runtime·_WriteFile(SB)
60	MOVL	BP, SI
61	RET
62
63// faster get/set last error
64TEXT runtime·getlasterror(SB),NOSPLIT,$0
65	MOVL	0x34(FS), AX
66	MOVL	AX, ret+0(FP)
67	RET
68
69TEXT runtime·setlasterror(SB),NOSPLIT,$0
70	MOVL	err+0(FP), AX
71	MOVL	AX, 0x34(FS)
72	RET
73
74// Called by Windows as a Vectored Exception Handler (VEH).
75// First argument is pointer to struct containing
76// exception record and context pointers.
77// Handler function is stored in AX.
78// Return 0 for 'not handled', -1 for handled.
79TEXT sigtramp<>(SB),NOSPLIT,$0-0
80	MOVL	ptrs+0(FP), CX
81	SUBL	$40, SP
82
83	// save callee-saved registers
84	MOVL	BX, 28(SP)
85	MOVL	BP, 16(SP)
86	MOVL	SI, 20(SP)
87	MOVL	DI, 24(SP)
88
89	MOVL	AX, SI	// save handler address
90
91	// find g
92	get_tls(DX)
93	CMPL	DX, $0
94	JNE	3(PC)
95	MOVL	$0, AX // continue
96	JMP	done
97	MOVL	g(DX), DX
98	CMPL	DX, $0
99	JNE	2(PC)
100	CALL	runtime·badsignal2(SB)
101
102	// save g and SP in case of stack switch
103	MOVL	DX, 32(SP)	// g
104	MOVL	SP, 36(SP)
105
106	// do we need to switch to the g0 stack?
107	MOVL	g_m(DX), BX
108	MOVL	m_g0(BX), BX
109	CMPL	DX, BX
110	JEQ	g0
111
112	// switch to the g0 stack
113	get_tls(BP)
114	MOVL	BX, g(BP)
115	MOVL	(g_sched+gobuf_sp)(BX), DI
116	// make it look like mstart called us on g0, to stop traceback
117	SUBL	$4, DI
118	MOVL	$runtime·mstart(SB), 0(DI)
119	// traceback will think that we've done SUBL
120	// on this stack, so subtract them here to match.
121	// (we need room for sighandler arguments anyway).
122	// and re-save old SP for restoring later.
123	SUBL	$40, DI
124	MOVL	SP, 36(DI)
125	MOVL	DI, SP
126
127g0:
128	MOVL	0(CX), BX // ExceptionRecord*
129	MOVL	4(CX), CX // Context*
130	MOVL	BX, 0(SP)
131	MOVL	CX, 4(SP)
132	MOVL	DX, 8(SP)
133	CALL	SI	// call handler
134	// AX is set to report result back to Windows
135	MOVL	12(SP), AX
136
137	// switch back to original stack and g
138	// no-op if we never left.
139	MOVL	36(SP), SP
140	MOVL	32(SP), DX
141	get_tls(BP)
142	MOVL	DX, g(BP)
143
144done:
145	// restore callee-saved registers
146	MOVL	24(SP), DI
147	MOVL	20(SP), SI
148	MOVL	16(SP), BP
149	MOVL	28(SP), BX
150
151	ADDL	$40, SP
152	// RET 4 (return and pop 4 bytes parameters)
153	BYTE $0xC2; WORD $4
154	RET // unreached; make assembler happy
155
156TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
157	MOVL	$runtime·exceptionhandler(SB), AX
158	JMP	sigtramp<>(SB)
159
160TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
161	// is never called
162	INT	$3
163
164TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
165	MOVL	$runtime·lastcontinuehandler(SB), AX
166	JMP	sigtramp<>(SB)
167
168// Called by OS using stdcall ABI: bool ctrlhandler(uint32).
169TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
170	PUSHL	$runtime·ctrlhandler1(SB)
171	NOP	SP	// tell vet SP changed - stop checking offsets
172	CALL	runtime·externalthreadhandler(SB)
173	MOVL	4(SP), CX
174	ADDL	$12, SP
175	JMP	CX
176
177// Called by OS using stdcall ABI: uint32 profileloop(void*).
178TEXT runtime·profileloop(SB),NOSPLIT,$0
179	PUSHL	$runtime·profileloop1(SB)
180	NOP	SP	// tell vet SP changed - stop checking offsets
181	CALL	runtime·externalthreadhandler(SB)
182	MOVL	4(SP), CX
183	ADDL	$12, SP
184	JMP	CX
185
186TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
187	PUSHL	BP
188	MOVL	SP, BP
189	PUSHL	BX
190	PUSHL	SI
191	PUSHL	DI
192	PUSHL	0x14(FS)
193	MOVL	SP, DX
194
195	// setup dummy m, g
196	SUBL	$m__size, SP		// space for M
197	MOVL	SP, 0(SP)
198	MOVL	$m__size, 4(SP)
199	CALL	runtime·memclrNoHeapPointers(SB)	// smashes AX,BX,CX
200
201	LEAL	m_tls(SP), CX
202	MOVL	CX, 0x14(FS)
203	MOVL	SP, BX
204	SUBL	$g__size, SP		// space for G
205	MOVL	SP, g(CX)
206	MOVL	SP, m_g0(BX)
207
208	MOVL	SP, 0(SP)
209	MOVL	$g__size, 4(SP)
210	CALL	runtime·memclrNoHeapPointers(SB)	// smashes AX,BX,CX
211	LEAL	g__size(SP), BX
212	MOVL	BX, g_m(SP)
213
214	LEAL	-32768(SP), CX		// must be less than SizeOfStackReserve set by linker
215	MOVL	CX, (g_stack+stack_lo)(SP)
216	ADDL	$const__StackGuard, CX
217	MOVL	CX, g_stackguard0(SP)
218	MOVL	CX, g_stackguard1(SP)
219	MOVL	DX, (g_stack+stack_hi)(SP)
220
221	PUSHL	AX			// room for return value
222	PUSHL	16(BP)			// arg for handler
223	CALL	8(BP)
224	POPL	CX
225	POPL	AX			// pass return value to Windows in AX
226
227	get_tls(CX)
228	MOVL	g(CX), CX
229	MOVL	(g_stack+stack_hi)(CX), SP
230	POPL	0x14(FS)
231	POPL	DI
232	POPL	SI
233	POPL	BX
234	POPL	BP
235	RET
236
237GLOBL runtime·cbctxts(SB), NOPTR, $4
238
239TEXT runtime·callbackasm1(SB),NOSPLIT,$0
240  	MOVL	0(SP), AX	// will use to find our callback context
241
242	// remove return address from stack, we are not returning there
243	ADDL	$4, SP
244
245	// address to callback parameters into CX
246	LEAL	4(SP), CX
247
248	// save registers as required for windows callback
249	PUSHL	DI
250	PUSHL	SI
251	PUSHL	BP
252	PUSHL	BX
253
254	// determine index into runtime·cbctxts table
255	SUBL	$runtime·callbackasm(SB), AX
256	MOVL	$0, DX
257	MOVL	$5, BX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
258	DIVL	BX
259
260	// find correspondent runtime·cbctxts table entry
261	MOVL	runtime·cbctxts(SB), BX
262	MOVL	-4(BX)(AX*4), BX
263
264	// extract callback context
265	MOVL	wincallbackcontext_gobody(BX), AX
266	MOVL	wincallbackcontext_argsize(BX), DX
267
268	// preserve whatever's at the memory location that
269	// the callback will use to store the return value
270	PUSHL	0(CX)(DX*1)
271
272	// extend argsize by size of return value
273	ADDL	$4, DX
274
275	// remember how to restore stack on return
276	MOVL	wincallbackcontext_restorestack(BX), BX
277	PUSHL	BX
278
279	// call target Go function
280	PUSHL	DX			// argsize (including return value)
281	PUSHL	CX			// callback parameters
282	PUSHL	AX			// address of target Go function
283	CLD
284	CALL	runtime·cgocallback_gofunc(SB)
285	POPL	AX
286	POPL	CX
287	POPL	DX
288
289	// how to restore stack on return
290	POPL	BX
291
292	// return value into AX (as per Windows spec)
293	// and restore previously preserved value
294	MOVL	-4(CX)(DX*1), AX
295	POPL	-4(CX)(DX*1)
296
297	MOVL	BX, CX			// cannot use BX anymore
298
299	// restore registers as required for windows callback
300	POPL	BX
301	POPL	BP
302	POPL	SI
303	POPL	DI
304
305	// remove callback parameters before return (as per Windows spec)
306	POPL	DX
307	ADDL	CX, SP
308	PUSHL	DX
309
310	CLD
311
312	RET
313
314// void tstart(M *newm);
315TEXT tstart<>(SB),NOSPLIT,$0
316	MOVL	newm+0(FP), CX		// m
317	MOVL	m_g0(CX), DX		// g
318
319	// Layout new m scheduler stack on os stack.
320	MOVL	SP, AX
321	MOVL	AX, (g_stack+stack_hi)(DX)
322	SUBL	$(64*1024), AX		// initial stack size (adjusted later)
323	MOVL	AX, (g_stack+stack_lo)(DX)
324	ADDL	$const__StackGuard, AX
325	MOVL	AX, g_stackguard0(DX)
326	MOVL	AX, g_stackguard1(DX)
327
328	// Set up tls.
329	LEAL	m_tls(CX), SI
330	MOVL	SI, 0x14(FS)
331	MOVL	CX, g_m(DX)
332	MOVL	DX, g(SI)
333
334	// Someday the convention will be D is always cleared.
335	CLD
336
337	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
338	CALL	runtime·mstart(SB)
339
340	RET
341
342// uint32 tstart_stdcall(M *newm);
343TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
344	MOVL	newm+0(FP), BX
345
346	PUSHL	BX
347	CALL	tstart<>(SB)
348	POPL	BX
349
350	// Adjust stack for stdcall to return properly.
351	MOVL	(SP), AX		// save return address
352	ADDL	$4, SP			// remove single parameter
353	MOVL	AX, (SP)		// restore return address
354
355	XORL	AX, AX			// return 0 == success
356
357	RET
358
359// setldt(int entry, int address, int limit)
360TEXT runtime·setldt(SB),NOSPLIT,$0
361	MOVL	base+4(FP), CX
362	MOVL	CX, 0x14(FS)
363	RET
364
365// onosstack calls fn on OS stack.
366// func onosstack(fn unsafe.Pointer, arg uint32)
367TEXT runtime·onosstack(SB),NOSPLIT,$0
368	MOVL	fn+0(FP), AX		// to hide from 8l
369	MOVL	arg+4(FP), BX
370
371	// Execute call on m->g0 stack, in case we are not actually
372	// calling a system call wrapper, like when running under WINE.
373	get_tls(CX)
374	CMPL	CX, $0
375	JNE	3(PC)
376	// Not a Go-managed thread. Do not switch stack.
377	CALL	AX
378	RET
379
380	MOVL	g(CX), BP
381	MOVL	g_m(BP), BP
382
383	// leave pc/sp for cpu profiler
384	MOVL	(SP), SI
385	MOVL	SI, m_libcallpc(BP)
386	MOVL	g(CX), SI
387	MOVL	SI, m_libcallg(BP)
388	// sp must be the last, because once async cpu profiler finds
389	// all three values to be non-zero, it will use them
390	LEAL	fn+0(FP), SI
391	MOVL	SI, m_libcallsp(BP)
392
393	MOVL	m_g0(BP), SI
394	CMPL	g(CX), SI
395	JNE	switch
396	// executing on m->g0 already
397	CALL	AX
398	JMP	ret
399
400switch:
401	// Switch to m->g0 stack and back.
402	MOVL	(g_sched+gobuf_sp)(SI), SI
403	MOVL	SP, -4(SI)
404	LEAL	-4(SI), SP
405	CALL	AX
406	MOVL	0(SP), SP
407
408ret:
409	get_tls(CX)
410	MOVL	g(CX), BP
411	MOVL	g_m(BP), BP
412	MOVL	$0, m_libcallsp(BP)
413	RET
414
415// Runs on OS stack. duration (in 100ns units) is in BX.
416TEXT runtime·usleep2(SB),NOSPLIT,$20
417	// Want negative 100ns units.
418	NEGL	BX
419	MOVL	$-1, hi-4(SP)
420	MOVL	BX, lo-8(SP)
421	LEAL	lo-8(SP), BX
422	MOVL	BX, ptime-12(SP)
423	MOVL	$0, alertable-16(SP)
424	MOVL	$-1, handle-20(SP)
425	MOVL	SP, BP
426	MOVL	runtime·_NtWaitForSingleObject(SB), AX
427	CALL	AX
428	MOVL	BP, SP
429	RET
430
431// Runs on OS stack.
432TEXT runtime·switchtothread(SB),NOSPLIT,$0
433	MOVL	SP, BP
434	MOVL	runtime·_SwitchToThread(SB), AX
435	CALL	AX
436	MOVL	BP, SP
437	RET
438
439// See https://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
440// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
441#define _INTERRUPT_TIME 0x7ffe0008
442#define _SYSTEM_TIME 0x7ffe0014
443#define time_lo 0
444#define time_hi1 4
445#define time_hi2 8
446
447TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
448	CMPB	runtime·useQPCTime(SB), $0
449	JNE	useQPC
450loop:
451	MOVL	(_INTERRUPT_TIME+time_hi1), AX
452	MOVL	(_INTERRUPT_TIME+time_lo), CX
453	MOVL	(_INTERRUPT_TIME+time_hi2), DI
454	CMPL	AX, DI
455	JNE	loop
456
457	// wintime = DI:CX, multiply by 100
458	MOVL	$100, AX
459	MULL	CX
460	IMULL	$100, DI
461	ADDL	DI, DX
462	// wintime*100 = DX:AX
463	MOVL	AX, ret_lo+0(FP)
464	MOVL	DX, ret_hi+4(FP)
465	RET
466useQPC:
467	JMP	runtime·nanotimeQPC(SB)
468	RET
469
470TEXT time·now(SB),NOSPLIT,$0-20
471	CMPB	runtime·useQPCTime(SB), $0
472	JNE	useQPC
473loop:
474	MOVL	(_INTERRUPT_TIME+time_hi1), AX
475	MOVL	(_INTERRUPT_TIME+time_lo), CX
476	MOVL	(_INTERRUPT_TIME+time_hi2), DI
477	CMPL	AX, DI
478	JNE	loop
479
480	// w = DI:CX
481	// multiply by 100
482	MOVL	$100, AX
483	MULL	CX
484	IMULL	$100, DI
485	ADDL	DI, DX
486	// w*100 = DX:AX
487	MOVL	AX, mono+12(FP)
488	MOVL	DX, mono+16(FP)
489
490wall:
491	MOVL	(_SYSTEM_TIME+time_hi1), CX
492	MOVL	(_SYSTEM_TIME+time_lo), AX
493	MOVL	(_SYSTEM_TIME+time_hi2), DX
494	CMPL	CX, DX
495	JNE	wall
496
497	// w = DX:AX
498	// convert to Unix epoch (but still 100ns units)
499	#define delta 116444736000000000
500	SUBL	$(delta & 0xFFFFFFFF), AX
501	SBBL $(delta >> 32), DX
502
503	// nano/100 = DX:AX
504	// split into two decimal halves by div 1e9.
505	// (decimal point is two spots over from correct place,
506	// but we avoid overflow in the high word.)
507	MOVL	$1000000000, CX
508	DIVL	CX
509	MOVL	AX, DI
510	MOVL	DX, SI
511
512	// DI = nano/100/1e9 = nano/1e11 = sec/100, DX = SI = nano/100%1e9
513	// split DX into seconds and nanoseconds by div 1e7 magic multiply.
514	MOVL	DX, AX
515	MOVL	$1801439851, CX
516	MULL	CX
517	SHRL	$22, DX
518	MOVL	DX, BX
519	IMULL	$10000000, DX
520	MOVL	SI, CX
521	SUBL	DX, CX
522
523	// DI = sec/100 (still)
524	// BX = (nano/100%1e9)/1e7 = (nano/1e9)%100 = sec%100
525	// CX = (nano/100%1e9)%1e7 = (nano%1e9)/100 = nsec/100
526	// store nsec for return
527	IMULL	$100, CX
528	MOVL	CX, nsec+8(FP)
529
530	// DI = sec/100 (still)
531	// BX = sec%100
532	// construct DX:AX = 64-bit sec and store for return
533	MOVL	$0, DX
534	MOVL	$100, AX
535	MULL	DI
536	ADDL	BX, AX
537	ADCL	$0, DX
538	MOVL	AX, sec+0(FP)
539	MOVL	DX, sec+4(FP)
540	RET
541useQPC:
542	JMP	runtime·nowQPC(SB)
543	RET
544