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,$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 
     49 	// Call stdcall function.
     50 	CALL	AX
     51 
     52 	ADDQ	$(maxargs*8), SP
     53 
     54 	// Return result.
     55 	POPQ	CX
     56 	MOVQ	AX, libcall_r1(CX)
     57 
     58 	// GetLastError().
     59 	MOVQ	0x30(GS), DI
     60 	MOVL	0x68(DI), AX
     61 	MOVQ	AX, libcall_err(CX)
     62 
     63 	RET
     64 
     65 TEXT runtimebadsignal2(SB),NOSPLIT,$48
     66 	// stderr
     67 	MOVQ	$-12, CX // stderr
     68 	MOVQ	CX, 0(SP)
     69 	MOVQ	runtime_GetStdHandle(SB), AX
     70 	CALL	AX
     71 
     72 	MOVQ	AX, CX	// handle
     73 	MOVQ	CX, 0(SP)
     74 	MOVQ	$runtimebadsignalmsg(SB), DX // pointer
     75 	MOVQ	DX, 8(SP)
     76 	MOVL	$runtimebadsignallen(SB), R8 // count
     77 	MOVQ	R8, 16(SP)
     78 	LEAQ	40(SP), R9  // written count
     79 	MOVQ	$0, 0(R9)
     80 	MOVQ	R9, 24(SP)
     81 	MOVQ	$0, 32(SP)	// overlapped
     82 	MOVQ	runtime_WriteFile(SB), AX
     83 	CALL	AX
     84 
     85 	RET
     86 
     87 // faster get/set last error
     88 TEXT runtimegetlasterror(SB),NOSPLIT,$0
     89 	MOVQ	0x30(GS), AX
     90 	MOVL	0x68(AX), AX
     91 	MOVL	AX, ret+0(FP)
     92 	RET
     93 
     94 TEXT runtimesetlasterror(SB),NOSPLIT,$0
     95 	MOVL	err+0(FP), AX
     96 	MOVQ	0x30(GS),	CX
     97 	MOVL	AX, 0x68(CX)
     98 	RET
     99 
    100 // Called by Windows as a Vectored Exception Handler (VEH).
    101 // First argument is pointer to struct containing
    102 // exception record and context pointers.
    103 // Handler function is stored in AX.
    104 // Return 0 for 'not handled', -1 for handled.
    105 TEXT runtimesigtramp(SB),NOSPLIT,$0-0
    106 	// CX: PEXCEPTION_POINTERS ExceptionInfo
    107 
    108 	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
    109 	// as required by windows callback convention.
    110 	PUSHFQ
    111 	SUBQ	$112, SP
    112 	MOVQ	DI, 80(SP)
    113 	MOVQ	SI, 72(SP)
    114 	MOVQ	BP, 64(SP)
    115 	MOVQ	BX, 56(SP)
    116 	MOVQ	R12, 48(SP)
    117 	MOVQ	R13, 40(SP)
    118 	MOVQ	R14, 32(SP)
    119 	MOVQ	R15, 88(SP)
    120 
    121 	MOVQ	AX, R15	// save handler address
    122 
    123 	// find g
    124 	get_tls(DX)
    125 	CMPQ	DX, $0
    126 	JNE	3(PC)
    127 	MOVQ	$0, AX // continue
    128 	JMP	done
    129 	MOVQ	g(DX), DX
    130 	CMPQ	DX, $0
    131 	JNE	2(PC)
    132 	CALL	runtimebadsignal2(SB)
    133 
    134 	// save g and SP in case of stack switch
    135 	MOVQ	DX, 96(SP) // g
    136 	MOVQ	SP, 104(SP)
    137 
    138 	// do we need to switch to the g0 stack?
    139 	MOVQ	g_m(DX), BX
    140 	MOVQ	m_g0(BX), BX
    141 	CMPQ	DX, BX
    142 	JEQ	g0
    143 
    144 	// switch to g0 stack
    145 	get_tls(BP)
    146 	MOVQ	BX, g(BP)
    147 	MOVQ	(g_sched+gobuf_sp)(BX), DI
    148 	// make it look like mstart called us on g0, to stop traceback
    149 	SUBQ	$8, DI
    150 	MOVQ	$runtimemstart(SB), SI
    151 	MOVQ	SI, 0(DI)
    152 	// traceback will think that we've done PUSHFQ and SUBQ
    153 	// on this stack, so subtract them here to match.
    154 	// (we need room for sighandler arguments anyway).
    155 	// and re-save old SP for restoring later.
    156 	SUBQ	$(112+8), DI
    157 	// save g, save old stack pointer.
    158 	MOVQ	SP, 104(DI)
    159 	MOVQ	DI, SP
    160 
    161 g0:
    162 	MOVQ	0(CX), BX // ExceptionRecord*
    163 	MOVQ	8(CX), CX // Context*
    164 	MOVQ	BX, 0(SP)
    165 	MOVQ	CX, 8(SP)
    166 	MOVQ	DX, 16(SP)
    167 	CALL	R15	// call handler
    168 	// AX is set to report result back to Windows
    169 	MOVL	24(SP), AX
    170 
    171 	// switch back to original stack and g
    172 	// no-op if we never left.
    173 	MOVQ	104(SP), SP
    174 	MOVQ	96(SP), DX
    175 	get_tls(BP)
    176 	MOVQ	DX, g(BP)
    177 
    178 done:
    179 	// restore registers as required for windows callback
    180 	MOVQ	88(SP), R15
    181 	MOVQ	32(SP), R14
    182 	MOVQ	40(SP), R13
    183 	MOVQ	48(SP), R12
    184 	MOVQ	56(SP), BX
    185 	MOVQ	64(SP), BP
    186 	MOVQ	72(SP), SI
    187 	MOVQ	80(SP), DI
    188 	ADDQ	$112, SP
    189 	POPFQ
    190 
    191 	RET
    192 
    193 TEXT runtimeexceptiontramp(SB),NOSPLIT,$0
    194 	MOVQ	$runtimeexceptionhandler(SB), AX
    195 	JMP	runtimesigtramp(SB)
    196 
    197 TEXT runtimefirstcontinuetramp(SB),NOSPLIT,$0-0
    198 	MOVQ	$runtimefirstcontinuehandler(SB), AX
    199 	JMP	runtimesigtramp(SB)
    200 
    201 TEXT runtimelastcontinuetramp(SB),NOSPLIT,$0-0
    202 	MOVQ	$runtimelastcontinuehandler(SB), AX
    203 	JMP	runtimesigtramp(SB)
    204 
    205 TEXT runtimectrlhandler(SB),NOSPLIT,$8
    206 	MOVQ	CX, 16(SP)		// spill
    207 	MOVQ	$runtimectrlhandler1(SB), CX
    208 	MOVQ	CX, 0(SP)
    209 	CALL	runtimeexternalthreadhandler(SB)
    210 	RET
    211 
    212 TEXT runtimeprofileloop(SB),NOSPLIT,$8
    213 	MOVQ	$runtimeprofileloop1(SB), CX
    214 	MOVQ	CX, 0(SP)
    215 	CALL	runtimeexternalthreadhandler(SB)
    216 	RET
    217 
    218 TEXT runtimeexternalthreadhandler(SB),NOSPLIT,$0
    219 	PUSHQ	BP
    220 	MOVQ	SP, BP
    221 	PUSHQ	BX
    222 	PUSHQ	SI
    223 	PUSHQ	DI
    224 	PUSHQ	0x28(GS)
    225 	MOVQ	SP, DX
    226 
    227 	// setup dummy m, g
    228 	SUBQ	$m__size, SP		// space for M
    229 	MOVQ	SP, 0(SP)
    230 	MOVQ	$m__size, 8(SP)
    231 	CALL	runtimememclr(SB)	// smashes AX,BX,CX
    232 
    233 	LEAQ	m_tls(SP), CX
    234 	MOVQ	CX, 0x28(GS)
    235 	MOVQ	SP, BX
    236 	SUBQ	$g__size, SP		// space for G
    237 	MOVQ	SP, g(CX)
    238 	MOVQ	SP, m_g0(BX)
    239 
    240 	MOVQ	SP, 0(SP)
    241 	MOVQ	$g__size, 8(SP)
    242 	CALL	runtimememclr(SB)	// smashes AX,BX,CX
    243 	LEAQ	g__size(SP), BX
    244 	MOVQ	BX, g_m(SP)
    245 
    246 	LEAQ	-8192(SP), CX
    247 	MOVQ	CX, (g_stack+stack_lo)(SP)
    248 	ADDQ	$const__StackGuard, CX
    249 	MOVQ	CX, g_stackguard0(SP)
    250 	MOVQ	CX, g_stackguard1(SP)
    251 	MOVQ	DX, (g_stack+stack_hi)(SP)
    252 
    253 	PUSHQ	AX			// room for return value
    254 	PUSHQ	32(BP)			// arg for handler
    255 	CALL	16(BP)
    256 	POPQ	CX
    257 	POPQ	AX			// pass return value to Windows in AX
    258 
    259 	get_tls(CX)
    260 	MOVQ	g(CX), CX
    261 	MOVQ	(g_stack+stack_hi)(CX), SP
    262 	POPQ	0x28(GS)
    263 	POPQ	DI
    264 	POPQ	SI
    265 	POPQ	BX
    266 	POPQ	BP
    267 	RET
    268 
    269 GLOBL runtimecbctxts(SB), NOPTR, $8
    270 
    271 TEXT runtimecallbackasm1(SB),NOSPLIT,$0
    272 	// Construct args vector for cgocallback().
    273 	// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
    274 	// args from the 5th on are on the stack.
    275 	// In any case, even if function has 0,1,2,3,4 args, there is reserved
    276 	// but uninitialized "shadow space" for the first 4 args.
    277 	// The values are in registers.
    278   	MOVQ	CX, (16+0)(SP)
    279   	MOVQ	DX, (16+8)(SP)
    280   	MOVQ	R8, (16+16)(SP)
    281   	MOVQ	R9, (16+24)(SP)
    282 
    283 	// remove return address from stack, we are not returning there
    284   	MOVQ	0(SP), AX
    285 	ADDQ	$8, SP
    286 
    287 	// determine index into runtimecbctxts table
    288 	MOVQ	$runtimecallbackasm(SB), DX
    289 	SUBQ	DX, AX
    290 	MOVQ	$0, DX
    291 	MOVQ	$5, CX	// divide by 5 because each call instruction in runtimecallbacks is 5 bytes long
    292 	DIVL	CX
    293 
    294 	// find correspondent runtimecbctxts table entry
    295 	MOVQ	runtimecbctxts(SB), CX
    296 	MOVQ	-8(CX)(AX*8), AX
    297 
    298 	// extract callback context
    299 	MOVQ	wincallbackcontext_argsize(AX), DX
    300 	MOVQ	wincallbackcontext_gobody(AX), AX
    301 
    302 	// preserve whatever's at the memory location that
    303 	// the callback will use to store the return value
    304 	LEAQ	8(SP), CX       // args vector, skip return address
    305 	PUSHQ	0(CX)(DX*1)     // store 8 bytes from just after the args array
    306 	ADDQ	$8, DX          // extend argsize by size of return value
    307 
    308 	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
    309 	// as required by windows callback convention.
    310 	PUSHFQ
    311 	SUBQ	$64, SP
    312 	MOVQ	DI, 56(SP)
    313 	MOVQ	SI, 48(SP)
    314 	MOVQ	BP, 40(SP)
    315 	MOVQ	BX, 32(SP)
    316 	MOVQ	R12, 24(SP)
    317 	MOVQ	R13, 16(SP)
    318 	MOVQ	R14, 8(SP)
    319 	MOVQ	R15, 0(SP)
    320 
    321 	// prepare call stack.  use SUBQ to hide from stack frame checks
    322 	// cgocallback(Go func, void *frame, uintptr framesize)
    323 	SUBQ	$24, SP
    324 	MOVQ	DX, 16(SP)	// argsize (including return value)
    325 	MOVQ	CX, 8(SP)	// callback parameters
    326 	MOVQ	AX, 0(SP)	// address of target Go function
    327 	CLD
    328 	CALL	runtimecgocallback_gofunc(SB)
    329 	MOVQ	0(SP), AX
    330 	MOVQ	8(SP), CX
    331 	MOVQ	16(SP), DX
    332 	ADDQ	$24, SP
    333 
    334 	// restore registers as required for windows callback
    335 	MOVQ	0(SP), R15
    336 	MOVQ	8(SP), R14
    337 	MOVQ	16(SP), R13
    338 	MOVQ	24(SP), R12
    339 	MOVQ	32(SP), BX
    340 	MOVQ	40(SP), BP
    341 	MOVQ	48(SP), SI
    342 	MOVQ	56(SP), DI
    343 	ADDQ	$64, SP
    344 	POPFQ
    345 
    346 	MOVL	-8(CX)(DX*1), AX  // return value
    347 	POPQ	-8(CX)(DX*1)      // restore bytes just after the args
    348 	RET
    349 
    350 // uint32 tstart_stdcall(M *newm);
    351 TEXT runtimetstart_stdcall(SB),NOSPLIT,$0
    352 	// CX contains first arg newm
    353 	MOVQ	m_g0(CX), DX		// g
    354 
    355 	// Layout new m scheduler stack on os stack.
    356 	MOVQ	SP, AX
    357 	MOVQ	AX, (g_stack+stack_hi)(DX)
    358 	SUBQ	$(64*1024), AX		// stack size
    359 	MOVQ	AX, (g_stack+stack_lo)(DX)
    360 	ADDQ	$const__StackGuard, AX
    361 	MOVQ	AX, g_stackguard0(DX)
    362 	MOVQ	AX, g_stackguard1(DX)
    363 
    364 	// Set up tls.
    365 	LEAQ	m_tls(CX), SI
    366 	MOVQ	SI, 0x28(GS)
    367 	MOVQ	CX, g_m(DX)
    368 	MOVQ	DX, g(SI)
    369 
    370 	// Someday the convention will be D is always cleared.
    371 	CLD
    372 
    373 	CALL	runtimestackcheck(SB)	// clobbers AX,CX
    374 	CALL	runtimemstart(SB)
    375 
    376 	XORL	AX, AX			// return 0 == success
    377 	RET
    378 
    379 // set tls base to DI
    380 TEXT runtimesettls(SB),NOSPLIT,$0
    381 	MOVQ	DI, 0x28(GS)
    382 	RET
    383 
    384 // Sleep duration is in 100ns units.
    385 TEXT runtimeusleep1(SB),NOSPLIT,$0
    386 	MOVL	usec+0(FP), BX
    387 	MOVQ	$runtimeusleep2(SB), AX // to hide from 6l
    388 
    389 	// Execute call on m->g0 stack, in case we are not actually
    390 	// calling a system call wrapper, like when running under WINE.
    391 	get_tls(R15)
    392 	CMPQ	R15, $0
    393 	JNE	3(PC)
    394 	// Not a Go-managed thread. Do not switch stack.
    395 	CALL	AX
    396 	RET
    397 
    398 	MOVQ	g(R15), R13
    399 	MOVQ	g_m(R13), R13
    400 
    401 	// leave pc/sp for cpu profiler
    402 	MOVQ	(SP), R12
    403 	MOVQ	R12, m_libcallpc(R13)
    404 	MOVQ	g(R15), R12
    405 	MOVQ	R12, m_libcallg(R13)
    406 	// sp must be the last, because once async cpu profiler finds
    407 	// all three values to be non-zero, it will use them
    408 	LEAQ	usec+0(FP), R12
    409 	MOVQ	R12, m_libcallsp(R13)
    410 
    411 	MOVQ	m_g0(R13), R14
    412 	CMPQ	g(R15), R14
    413 	JNE	switch
    414 	// executing on m->g0 already
    415 	CALL	AX
    416 	JMP	ret
    417 
    418 switch:
    419 	// Switch to m->g0 stack and back.
    420 	MOVQ	(g_sched+gobuf_sp)(R14), R14
    421 	MOVQ	SP, -8(R14)
    422 	LEAQ	-8(R14), SP
    423 	CALL	AX
    424 	MOVQ	0(SP), SP
    425 
    426 ret:
    427 	MOVQ	$0, m_libcallsp(R13)
    428 	RET
    429 
    430 // Runs on OS stack. duration (in 100ns units) is in BX.
    431 TEXT runtimeusleep2(SB),NOSPLIT,$16
    432 	MOVQ	SP, AX
    433 	ANDQ	$~15, SP	// alignment as per Windows requirement
    434 	MOVQ	AX, 8(SP)
    435 	// Want negative 100ns units.
    436 	NEGQ	BX
    437 	MOVQ	SP, R8 // ptime
    438 	MOVQ	BX, (R8)
    439 	MOVQ	$-1, CX // handle
    440 	MOVQ	$0, DX // alertable
    441 	MOVQ	runtime_NtWaitForSingleObject(SB), AX
    442 	CALL	AX
    443 	MOVQ	8(SP), SP
    444 	RET
    445 
    446 // func now() (sec int64, nsec int32)
    447 TEXT timenow(SB),NOSPLIT,$8-12
    448 	CALL	runtimeunixnano(SB)
    449 	MOVQ	0(SP), AX
    450 
    451 	// generated code for
    452 	//	func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
    453 	// adapted to reduce duplication
    454 	MOVQ	AX, CX
    455 	MOVQ	$1360296554856532783, AX
    456 	MULQ	CX
    457 	ADDQ	CX, DX
    458 	RCRQ	$1, DX
    459 	SHRQ	$29, DX
    460 	MOVQ	DX, sec+0(FP)
    461 	IMULQ	$1000000000, DX
    462 	SUBQ	DX, CX
    463 	MOVL	CX, nsec+8(FP)
    464 	RET
    465 
    466