Home | History | Annotate | Download | only in runtime
      1 // Copyright 2011 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 // maxargs should be divisible by 2, as Windows stack
     10 // must be kept 16-byte aligned on syscall entry.
     11 #define maxargs 16
     12 
     13 // void runtimeasmstdcall(void *c);
     14 TEXT runtimeasmstdcall(SB),NOSPLIT|NOFRAME,$0
     15 	// asmcgocall will put first argument into CX.
     16 	PUSHQ	CX			// save for later
     17 	MOVQ	libcall_fn(CX), AX
     18 	MOVQ	libcall_args(CX), SI
     19 	MOVQ	libcall_n(CX), CX
     20 
     21 	// SetLastError(0).
     22 	MOVQ	0x30(GS), DI
     23 	MOVL	$0, 0x68(DI)
     24 
     25 	SUBQ	$(maxargs*8), SP	// room for args
     26 
     27 	// Fast version, do not store args on the stack.
     28 	CMPL	CX, $4
     29 	JLE	loadregs
     30 
     31 	// Check we have enough room for args.
     32 	CMPL	CX, $maxargs
     33 	JLE	2(PC)
     34 	INT	$3			// not enough room -> crash
     35 
     36 	// Copy args to the stack.
     37 	MOVQ	SP, DI
     38 	CLD
     39 	REP; MOVSQ
     40 	MOVQ	SP, SI
     41 
     42 loadregs:
     43 	// Load first 4 args into correspondent registers.
     44 	MOVQ	0(SI), CX
     45 	MOVQ	8(SI), DX
     46 	MOVQ	16(SI), R8
     47 	MOVQ	24(SI), R9
     48 	// Floating point arguments are passed in the XMM
     49 	// registers. Set them here in case any of the arguments
     50 	// are floating point values. For details see
     51 	//	https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
     52 	MOVQ	CX, X0
     53 	MOVQ	DX, X1
     54 	MOVQ	R8, X2
     55 	MOVQ	R9, X3
     56 
     57 	// Call stdcall function.
     58 	CALL	AX
     59 
     60 	ADDQ	$(maxargs*8), SP
     61 
     62 	// Return result.
     63 	POPQ	CX
     64 	MOVQ	AX, libcall_r1(CX)
     65 
     66 	// GetLastError().
     67 	MOVQ	0x30(GS), DI
     68 	MOVL	0x68(DI), AX
     69 	MOVQ	AX, libcall_err(CX)
     70 
     71 	RET
     72 
     73 TEXT runtimebadsignal2(SB),NOSPLIT|NOFRAME,$48
     74 	// stderr
     75 	MOVQ	$-12, CX // stderr
     76 	MOVQ	CX, 0(SP)
     77 	MOVQ	runtime_GetStdHandle(SB), AX
     78 	CALL	AX
     79 
     80 	MOVQ	AX, CX	// handle
     81 	MOVQ	CX, 0(SP)
     82 	MOVQ	$runtimebadsignalmsg(SB), DX // pointer
     83 	MOVQ	DX, 8(SP)
     84 	MOVL	$runtimebadsignallen(SB), R8 // count
     85 	MOVQ	R8, 16(SP)
     86 	LEAQ	40(SP), R9  // written count
     87 	MOVQ	$0, 0(R9)
     88 	MOVQ	R9, 24(SP)
     89 	MOVQ	$0, 32(SP)	// overlapped
     90 	MOVQ	runtime_WriteFile(SB), AX
     91 	CALL	AX
     92 
     93 	RET
     94 
     95 // faster get/set last error
     96 TEXT runtimegetlasterror(SB),NOSPLIT,$0
     97 	MOVQ	0x30(GS), AX
     98 	MOVL	0x68(AX), AX
     99 	MOVL	AX, ret+0(FP)
    100 	RET
    101 
    102 TEXT runtimesetlasterror(SB),NOSPLIT,$0
    103 	MOVL	err+0(FP), AX
    104 	MOVQ	0x30(GS),	CX
    105 	MOVL	AX, 0x68(CX)
    106 	RET
    107 
    108 // Called by Windows as a Vectored Exception Handler (VEH).
    109 // First argument is pointer to struct containing
    110 // exception record and context pointers.
    111 // Handler function is stored in AX.
    112 // Return 0 for 'not handled', -1 for handled.
    113 TEXT runtimesigtramp(SB),NOSPLIT|NOFRAME,$0-0
    114 	// CX: PEXCEPTION_POINTERS ExceptionInfo
    115 
    116 	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
    117 	// as required by windows callback convention.
    118 	PUSHFQ
    119 	SUBQ	$112, SP
    120 	MOVQ	DI, 80(SP)
    121 	MOVQ	SI, 72(SP)
    122 	MOVQ	BP, 64(SP)
    123 	MOVQ	BX, 56(SP)
    124 	MOVQ	R12, 48(SP)
    125 	MOVQ	R13, 40(SP)
    126 	MOVQ	R14, 32(SP)
    127 	MOVQ	R15, 88(SP)
    128 
    129 	MOVQ	AX, R15	// save handler address
    130 
    131 	// find g
    132 	get_tls(DX)
    133 	CMPQ	DX, $0
    134 	JNE	3(PC)
    135 	MOVQ	$0, AX // continue
    136 	JMP	done
    137 	MOVQ	g(DX), DX
    138 	CMPQ	DX, $0
    139 	JNE	2(PC)
    140 	CALL	runtimebadsignal2(SB)
    141 
    142 	// save g and SP in case of stack switch
    143 	MOVQ	DX, 96(SP) // g
    144 	MOVQ	SP, 104(SP)
    145 
    146 	// do we need to switch to the g0 stack?
    147 	MOVQ	g_m(DX), BX
    148 	MOVQ	m_g0(BX), BX
    149 	CMPQ	DX, BX
    150 	JEQ	g0
    151 
    152 	// switch to g0 stack
    153 	get_tls(BP)
    154 	MOVQ	BX, g(BP)
    155 	MOVQ	(g_sched+gobuf_sp)(BX), DI
    156 	// make it look like mstart called us on g0, to stop traceback
    157 	SUBQ	$8, DI
    158 	MOVQ	$runtimemstart(SB), SI
    159 	MOVQ	SI, 0(DI)
    160 	// traceback will think that we've done PUSHFQ and SUBQ
    161 	// on this stack, so subtract them here to match.
    162 	// (we need room for sighandler arguments anyway).
    163 	// and re-save old SP for restoring later.
    164 	SUBQ	$(112+8), DI
    165 	// save g, save old stack pointer.
    166 	MOVQ	SP, 104(DI)
    167 	MOVQ	DI, SP
    168 
    169 g0:
    170 	MOVQ	0(CX), BX // ExceptionRecord*
    171 	MOVQ	8(CX), CX // Context*
    172 	MOVQ	BX, 0(SP)
    173 	MOVQ	CX, 8(SP)
    174 	MOVQ	DX, 16(SP)
    175 	CALL	R15	// call handler
    176 	// AX is set to report result back to Windows
    177 	MOVL	24(SP), AX
    178 
    179 	// switch back to original stack and g
    180 	// no-op if we never left.
    181 	MOVQ	104(SP), SP
    182 	MOVQ	96(SP), DX
    183 	get_tls(BP)
    184 	MOVQ	DX, g(BP)
    185 
    186 done:
    187 	// restore registers as required for windows callback
    188 	MOVQ	88(SP), R15
    189 	MOVQ	32(SP), R14
    190 	MOVQ	40(SP), R13
    191 	MOVQ	48(SP), R12
    192 	MOVQ	56(SP), BX
    193 	MOVQ	64(SP), BP
    194 	MOVQ	72(SP), SI
    195 	MOVQ	80(SP), DI
    196 	ADDQ	$112, SP
    197 	POPFQ
    198 
    199 	RET
    200 
    201 TEXT runtimeexceptiontramp(SB),NOSPLIT|NOFRAME,$0
    202 	MOVQ	$runtimeexceptionhandler(SB), AX
    203 	JMP	runtimesigtramp(SB)
    204 
    205 TEXT runtimefirstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
    206 	MOVQ	$runtimefirstcontinuehandler(SB), AX
    207 	JMP	runtimesigtramp(SB)
    208 
    209 TEXT runtimelastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
    210 	MOVQ	$runtimelastcontinuehandler(SB), AX
    211 	JMP	runtimesigtramp(SB)
    212 
    213 TEXT runtimectrlhandler(SB),NOSPLIT|NOFRAME,$8
    214 	MOVQ	CX, 16(SP)		// spill
    215 	MOVQ	$runtimectrlhandler1(SB), CX
    216 	MOVQ	CX, 0(SP)
    217 	CALL	runtimeexternalthreadhandler(SB)
    218 	RET
    219 
    220 TEXT runtimeprofileloop(SB),NOSPLIT|NOFRAME,$8
    221 	MOVQ	$runtimeprofileloop1(SB), CX
    222 	MOVQ	CX, 0(SP)
    223 	CALL	runtimeexternalthreadhandler(SB)
    224 	RET
    225 
    226 TEXT runtimeexternalthreadhandler(SB),NOSPLIT|NOFRAME,$0
    227 	PUSHQ	BP
    228 	MOVQ	SP, BP
    229 	PUSHQ	BX
    230 	PUSHQ	SI
    231 	PUSHQ	DI
    232 	PUSHQ	0x28(GS)
    233 	MOVQ	SP, DX
    234 
    235 	// setup dummy m, g
    236 	SUBQ	$m__size, SP		// space for M
    237 	MOVQ	SP, 0(SP)
    238 	MOVQ	$m__size, 8(SP)
    239 	CALL	runtimememclrNoHeapPointers(SB)	// smashes AX,BX,CX, maybe BP
    240 
    241 	LEAQ	m_tls(SP), CX
    242 	MOVQ	CX, 0x28(GS)
    243 	MOVQ	SP, BX
    244 	SUBQ	$g__size, SP		// space for G
    245 	MOVQ	SP, g(CX)
    246 	MOVQ	SP, m_g0(BX)
    247 
    248 	MOVQ	SP, 0(SP)
    249 	MOVQ	$g__size, 8(SP)
    250 	CALL	runtimememclrNoHeapPointers(SB)	// smashes AX,BX,CX, maybe BP
    251 	LEAQ	g__size(SP), BX
    252 	MOVQ	BX, g_m(SP)
    253 
    254 	LEAQ	-32768(SP), CX		// must be less than SizeOfStackReserve set by linker
    255 	MOVQ	CX, (g_stack+stack_lo)(SP)
    256 	ADDQ	$const__StackGuard, CX
    257 	MOVQ	CX, g_stackguard0(SP)
    258 	MOVQ	CX, g_stackguard1(SP)
    259 	MOVQ	DX, (g_stack+stack_hi)(SP)
    260 
    261 	PUSHQ	AX			// room for return value
    262 	PUSHQ	32(BP)			// arg for handler
    263 	CALL	16(BP)
    264 	POPQ	CX
    265 	POPQ	AX			// pass return value to Windows in AX
    266 
    267 	get_tls(CX)
    268 	MOVQ	g(CX), CX
    269 	MOVQ	(g_stack+stack_hi)(CX), SP
    270 	POPQ	0x28(GS)
    271 	POPQ	DI
    272 	POPQ	SI
    273 	POPQ	BX
    274 	POPQ	BP
    275 	RET
    276 
    277 GLOBL runtimecbctxts(SB), NOPTR, $8
    278 
    279 TEXT runtimecallbackasm1(SB),NOSPLIT,$0
    280 	// Construct args vector for cgocallback().
    281 	// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
    282 	// args from the 5th on are on the stack.
    283 	// In any case, even if function has 0,1,2,3,4 args, there is reserved
    284 	// but uninitialized "shadow space" for the first 4 args.
    285 	// The values are in registers.
    286   	MOVQ	CX, (16+0)(SP)
    287   	MOVQ	DX, (16+8)(SP)
    288   	MOVQ	R8, (16+16)(SP)
    289   	MOVQ	R9, (16+24)(SP)
    290 
    291 	// remove return address from stack, we are not returning there
    292   	MOVQ	0(SP), AX
    293 	ADDQ	$8, SP
    294 
    295 	// determine index into runtimecbctxts table
    296 	MOVQ	$runtimecallbackasm(SB), DX
    297 	SUBQ	DX, AX
    298 	MOVQ	$0, DX
    299 	MOVQ	$5, CX	// divide by 5 because each call instruction in runtimecallbacks is 5 bytes long
    300 	DIVL	CX
    301 
    302 	// find correspondent runtimecbctxts table entry
    303 	MOVQ	runtimecbctxts(SB), CX
    304 	MOVQ	-8(CX)(AX*8), AX
    305 
    306 	// extract callback context
    307 	MOVQ	wincallbackcontext_argsize(AX), DX
    308 	MOVQ	wincallbackcontext_gobody(AX), AX
    309 
    310 	// preserve whatever's at the memory location that
    311 	// the callback will use to store the return value
    312 	LEAQ	8(SP), CX       // args vector, skip return address
    313 	PUSHQ	0(CX)(DX*1)     // store 8 bytes from just after the args array
    314 	ADDQ	$8, DX          // extend argsize by size of return value
    315 
    316 	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
    317 	// as required by windows callback convention.
    318 	PUSHFQ
    319 	SUBQ	$64, SP
    320 	MOVQ	DI, 56(SP)
    321 	MOVQ	SI, 48(SP)
    322 	MOVQ	BP, 40(SP)
    323 	MOVQ	BX, 32(SP)
    324 	MOVQ	R12, 24(SP)
    325 	MOVQ	R13, 16(SP)
    326 	MOVQ	R14, 8(SP)
    327 	MOVQ	R15, 0(SP)
    328 
    329 	// prepare call stack.  use SUBQ to hide from stack frame checks
    330 	// cgocallback(Go func, void *frame, uintptr framesize)
    331 	SUBQ	$24, SP
    332 	MOVQ	DX, 16(SP)	// argsize (including return value)
    333 	MOVQ	CX, 8(SP)	// callback parameters
    334 	MOVQ	AX, 0(SP)	// address of target Go function
    335 	CLD
    336 	CALL	runtimecgocallback_gofunc(SB)
    337 	MOVQ	0(SP), AX
    338 	MOVQ	8(SP), CX
    339 	MOVQ	16(SP), DX
    340 	ADDQ	$24, SP
    341 
    342 	// restore registers as required for windows callback
    343 	MOVQ	0(SP), R15
    344 	MOVQ	8(SP), R14
    345 	MOVQ	16(SP), R13
    346 	MOVQ	24(SP), R12
    347 	MOVQ	32(SP), BX
    348 	MOVQ	40(SP), BP
    349 	MOVQ	48(SP), SI
    350 	MOVQ	56(SP), DI
    351 	ADDQ	$64, SP
    352 	POPFQ
    353 
    354 	MOVL	-8(CX)(DX*1), AX  // return value
    355 	POPQ	-8(CX)(DX*1)      // restore bytes just after the args
    356 	RET
    357 
    358 // uint32 tstart_stdcall(M *newm);
    359 TEXT runtimetstart_stdcall(SB),NOSPLIT,$0
    360 	// CX contains first arg newm
    361 	MOVQ	m_g0(CX), DX		// g
    362 
    363 	// Layout new m scheduler stack on os stack.
    364 	MOVQ	SP, AX
    365 	MOVQ	AX, (g_stack+stack_hi)(DX)
    366 	SUBQ	$(64*1024), AX		// stack size
    367 	MOVQ	AX, (g_stack+stack_lo)(DX)
    368 	ADDQ	$const__StackGuard, AX
    369 	MOVQ	AX, g_stackguard0(DX)
    370 	MOVQ	AX, g_stackguard1(DX)
    371 
    372 	// Set up tls.
    373 	LEAQ	m_tls(CX), SI
    374 	MOVQ	SI, 0x28(GS)
    375 	MOVQ	CX, g_m(DX)
    376 	MOVQ	DX, g(SI)
    377 
    378 	// Someday the convention will be D is always cleared.
    379 	CLD
    380 
    381 	CALL	runtimestackcheck(SB)	// clobbers AX,CX
    382 	CALL	runtimemstart(SB)
    383 
    384 	XORL	AX, AX			// return 0 == success
    385 	RET
    386 
    387 // set tls base to DI
    388 TEXT runtimesettls(SB),NOSPLIT,$0
    389 	MOVQ	DI, 0x28(GS)
    390 	RET
    391 
    392 // func onosstack(fn unsafe.Pointer, arg uint32)
    393 TEXT runtimeonosstack(SB),NOSPLIT,$0
    394 	MOVQ	fn+0(FP), AX		// to hide from 6l
    395 	MOVL	arg+8(FP), BX
    396 
    397 	// Execute call on m->g0 stack, in case we are not actually
    398 	// calling a system call wrapper, like when running under WINE.
    399 	get_tls(R15)
    400 	CMPQ	R15, $0
    401 	JNE	3(PC)
    402 	// Not a Go-managed thread. Do not switch stack.
    403 	CALL	AX
    404 	RET
    405 
    406 	MOVQ	g(R15), R13
    407 	MOVQ	g_m(R13), R13
    408 
    409 	// leave pc/sp for cpu profiler
    410 	MOVQ	(SP), R12
    411 	MOVQ	R12, m_libcallpc(R13)
    412 	MOVQ	g(R15), R12
    413 	MOVQ	R12, m_libcallg(R13)
    414 	// sp must be the last, because once async cpu profiler finds
    415 	// all three values to be non-zero, it will use them
    416 	LEAQ	usec+0(FP), R12
    417 	MOVQ	R12, m_libcallsp(R13)
    418 
    419 	MOVQ	m_g0(R13), R14
    420 	CMPQ	g(R15), R14
    421 	JNE	switch
    422 	// executing on m->g0 already
    423 	CALL	AX
    424 	JMP	ret
    425 
    426 switch:
    427 	// Switch to m->g0 stack and back.
    428 	MOVQ	(g_sched+gobuf_sp)(R14), R14
    429 	MOVQ	SP, -8(R14)
    430 	LEAQ	-8(R14), SP
    431 	CALL	AX
    432 	MOVQ	0(SP), SP
    433 
    434 ret:
    435 	MOVQ	$0, m_libcallsp(R13)
    436 	RET
    437 
    438 // Runs on OS stack. duration (in 100ns units) is in BX.
    439 // The function leaves room for 4 syscall parameters
    440 // (as per windows amd64 calling convention).
    441 TEXT runtimeusleep2(SB),NOSPLIT|NOFRAME,$48
    442 	MOVQ	SP, AX
    443 	ANDQ	$~15, SP	// alignment as per Windows requirement
    444 	MOVQ	AX, 40(SP)
    445 	// Want negative 100ns units.
    446 	NEGQ	BX
    447 	LEAQ	32(SP), R8  // ptime
    448 	MOVQ	BX, (R8)
    449 	MOVQ	$-1, CX // handle
    450 	MOVQ	$0, DX // alertable
    451 	MOVQ	runtime_NtWaitForSingleObject(SB), AX
    452 	CALL	AX
    453 	MOVQ	40(SP), SP
    454 	RET
    455 
    456 // Runs on OS stack.
    457 TEXT runtimeswitchtothread(SB),NOSPLIT|NOFRAME,$0
    458 	MOVQ	SP, AX
    459 	ANDQ	$~15, SP	// alignment as per Windows requirement
    460 	SUBQ	$(48), SP	// room for SP and 4 args as per Windows requirement
    461 				// plus one extra word to keep stack 16 bytes aligned
    462 	MOVQ	AX, 32(SP)
    463 	MOVQ	runtime_SwitchToThread(SB), AX
    464 	CALL	AX
    465 	MOVQ	32(SP), SP
    466 	RET
    467 
    468 // See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
    469 // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
    470 #define _INTERRUPT_TIME 0x7ffe0008
    471 #define _SYSTEM_TIME 0x7ffe0014
    472 #define time_lo 0
    473 #define time_hi1 4
    474 #define time_hi2 8
    475 
    476 TEXT runtimenanotime(SB),NOSPLIT,$0-8
    477 	CMPB	runtimeuseQPCTime(SB), $0
    478 	JNE	useQPC
    479 	MOVQ	$_INTERRUPT_TIME, DI
    480 loop:
    481 	MOVL	time_hi1(DI), AX
    482 	MOVL	time_lo(DI), BX
    483 	MOVL	time_hi2(DI), CX
    484 	CMPL	AX, CX
    485 	JNE	loop
    486 	SHLQ	$32, CX
    487 	ORQ	BX, CX
    488 	IMULQ	$100, CX
    489 	SUBQ	runtimestartNano(SB), CX
    490 	MOVQ	CX, ret+0(FP)
    491 	RET
    492 useQPC:
    493 	JMP	runtimenanotimeQPC(SB)
    494 	RET
    495 
    496 TEXT timenow(SB),NOSPLIT,$0-24
    497 	CMPB	runtimeuseQPCTime(SB), $0
    498 	JNE	useQPC
    499 	MOVQ	$_INTERRUPT_TIME, DI
    500 loop:
    501 	MOVL	time_hi1(DI), AX
    502 	MOVL	time_lo(DI), BX
    503 	MOVL	time_hi2(DI), CX
    504 	CMPL	AX, CX
    505 	JNE	loop
    506 	SHLQ	$32, AX
    507 	ORQ	BX, AX
    508 	IMULQ	$100, AX
    509 	SUBQ	runtimestartNano(SB), AX
    510 	MOVQ	AX, mono+16(FP)
    511 
    512 	MOVQ	$_SYSTEM_TIME, DI
    513 wall:
    514 	MOVL	time_hi1(DI), AX
    515 	MOVL	time_lo(DI), BX
    516 	MOVL	time_hi2(DI), CX
    517 	CMPL	AX, CX
    518 	JNE	wall
    519 	SHLQ	$32, AX
    520 	ORQ	BX, AX
    521 	MOVQ	$116444736000000000, DI
    522 	SUBQ	DI, AX
    523 	IMULQ	$100, AX
    524 
    525 	// generated code for
    526 	//	func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
    527 	// adapted to reduce duplication
    528 	MOVQ	AX, CX
    529 	MOVQ	$1360296554856532783, AX
    530 	MULQ	CX
    531 	ADDQ	CX, DX
    532 	RCRQ	$1, DX
    533 	SHRQ	$29, DX
    534 	MOVQ	DX, sec+0(FP)
    535 	IMULQ	$1000000000, DX
    536 	SUBQ	DX, CX
    537 	MOVL	CX, nsec+8(FP)
    538 	RET
    539 useQPC:
    540 	JMP	runtimenowQPC(SB)
    541 	RET
    542