blob: a9a7dfdd494bb90dbfe9af9e25e37128285bcaec [file] [log] [blame]
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
#include "cgo/abi_amd64.h"
// maxargs should be divisible by 2, as Windows stack
// must be kept 16-byte aligned on syscall entry.
#define maxargs 18
// void runtime·asmstdcall(void *c);
TEXT runtime·asmstdcall<ABIInternal>(SB),NOSPLIT|NOFRAME,$0
// asmcgocall will put first argument into CX.
PUSHQ CX // save for later
MOVQ libcall_fn(CX), AX
MOVQ libcall_args(CX), SI
MOVQ libcall_n(CX), CX
// SetLastError(0).
MOVQ 0x30(GS), DI
MOVL $0, 0x68(DI)
SUBQ $(maxargs*8), SP // room for args
// Fast version, do not store args on the stack.
CMPL CX, $4
JLE loadregs
// Check we have enough room for args.
CMPL CX, $maxargs
JLE 2(PC)
INT $3 // not enough room -> crash
// Copy args to the stack.
MOVQ SP, DI
CLD
REP; MOVSQ
MOVQ SP, SI
loadregs:
// Load first 4 args into correspondent registers.
MOVQ 0(SI), CX
MOVQ 8(SI), DX
MOVQ 16(SI), R8
MOVQ 24(SI), R9
// Floating point arguments are passed in the XMM
// registers. Set them here in case any of the arguments
// are floating point values. For details see
// https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
MOVQ CX, X0
MOVQ DX, X1
MOVQ R8, X2
MOVQ R9, X3
// Call stdcall function.
CALL AX
ADDQ $(maxargs*8), SP
// Return result.
POPQ CX
MOVQ AX, libcall_r1(CX)
// Floating point return values are returned in XMM0. Setting r2 to this
// value in case this call returned a floating point value. For details,
// see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
MOVQ X0, libcall_r2(CX)
// GetLastError().
MOVQ 0x30(GS), DI
MOVL 0x68(DI), AX
MOVQ AX, libcall_err(CX)
RET
TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$48
// stderr
MOVQ $-12, CX // stderr
MOVQ CX, 0(SP)
MOVQ runtime·_GetStdHandle(SB), AX
CALL AX
MOVQ AX, CX // handle
MOVQ CX, 0(SP)
MOVQ $runtime·badsignalmsg(SB), DX // pointer
MOVQ DX, 8(SP)
MOVL $runtime·badsignallen(SB), R8 // count
MOVQ R8, 16(SP)
LEAQ 40(SP), R9 // written count
MOVQ $0, 0(R9)
MOVQ R9, 24(SP)
MOVQ $0, 32(SP) // overlapped
MOVQ runtime·_WriteFile(SB), AX
CALL AX
RET
// faster get/set last error
TEXT runtime·getlasterror(SB),NOSPLIT,$0
MOVQ 0x30(GS), AX
MOVL 0x68(AX), AX
MOVL AX, ret+0(FP)
RET
// Called by Windows as a Vectored Exception Handler (VEH).
// First argument is pointer to struct containing
// exception record and context pointers.
// Handler function is stored in AX.
// Return 0 for 'not handled', -1 for handled.
TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
// CX: PEXCEPTION_POINTERS ExceptionInfo
// Switch from the host ABI to the Go ABI.
PUSH_REGS_HOST_TO_ABI0()
// Make stack space for the rest of the function.
ADJSP $48
MOVQ AX, R15 // save handler address
// find g
get_tls(DX)
CMPQ DX, $0
JNE 3(PC)
MOVQ $0, AX // continue
JMP done
MOVQ g(DX), DX
CMPQ DX, $0
JNE 2(PC)
CALL runtime·badsignal2(SB)
// save g and SP in case of stack switch
MOVQ DX, 32(SP) // g
MOVQ SP, 40(SP)
// do we need to switch to the g0 stack?
MOVQ g_m(DX), BX
MOVQ m_g0(BX), BX
CMPQ DX, BX
JEQ g0
// switch to g0 stack
get_tls(BP)
MOVQ BX, g(BP)
MOVQ (g_sched+gobuf_sp)(BX), DI
// make room for sighandler arguments
// and re-save old SP for restoring later.
// Adjust g0 stack by the space we're using and
// save SP at the same place on the g0 stack.
// The 32(DI) here must match the 32(SP) above.
SUBQ $(REGS_HOST_TO_ABI0_STACK + 48), DI
MOVQ SP, 40(DI)
MOVQ DI, SP
g0:
MOVQ 0(CX), BX // ExceptionRecord*
MOVQ 8(CX), CX // Context*
MOVQ BX, 0(SP)
MOVQ CX, 8(SP)
MOVQ DX, 16(SP)
CALL R15 // call handler
// AX is set to report result back to Windows
MOVL 24(SP), AX
// switch back to original stack and g
// no-op if we never left.
MOVQ 40(SP), SP
MOVQ 32(SP), DX
get_tls(BP)
MOVQ DX, g(BP)
done:
ADJSP $-48
POP_REGS_HOST_TO_ABI0()
RET
TEXT runtime·exceptiontramp<ABIInternal>(SB),NOSPLIT|NOFRAME,$0
MOVQ $runtime·exceptionhandler(SB), AX
JMP sigtramp<>(SB)
TEXT runtime·firstcontinuetramp<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-0
MOVQ $runtime·firstcontinuehandler(SB), AX
JMP sigtramp<>(SB)
TEXT runtime·lastcontinuetramp<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-0
MOVQ $runtime·lastcontinuehandler(SB), AX
JMP sigtramp<>(SB)
GLOBL runtime·cbctxts(SB), NOPTR, $8
TEXT runtime·callbackasm1(SB),NOSPLIT,$0
// Construct args vector for cgocallback().
// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
// args from the 5th on are on the stack.
// In any case, even if function has 0,1,2,3,4 args, there is reserved
// but uninitialized "shadow space" for the first 4 args.
// The values are in registers.
MOVQ CX, (16+0)(SP)
MOVQ DX, (16+8)(SP)
MOVQ R8, (16+16)(SP)
MOVQ R9, (16+24)(SP)
// R8 = address of args vector
LEAQ (16+0)(SP), R8
// remove return address from stack, we are not returning to callbackasm, but to its caller.
MOVQ 0(SP), AX
ADDQ $8, SP
// determine index into runtime·cbs table
MOVQ $runtime·callbackasm<ABIInternal>(SB), DX
SUBQ DX, AX
MOVQ $0, DX
MOVQ $5, CX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
DIVL CX
SUBQ $1, AX // subtract 1 because return PC is to the next slot
// Switch from the host ABI to the Go ABI.
PUSH_REGS_HOST_TO_ABI0()
// Create a struct callbackArgs on our stack to be passed as
// the "frame" to cgocallback and on to callbackWrap.
SUBQ $(24+callbackArgs__size), SP
MOVQ AX, (24+callbackArgs_index)(SP) // callback index
MOVQ R8, (24+callbackArgs_args)(SP) // address of args vector
MOVQ $0, (24+callbackArgs_result)(SP) // result
LEAQ 24(SP), AX
// Call cgocallback, which will call callbackWrap(frame).
MOVQ $0, 16(SP) // context
MOVQ AX, 8(SP) // frame (address of callbackArgs)
LEAQ ·callbackWrap<ABIInternal>(SB), BX // cgocallback takes an ABIInternal entry-point
MOVQ BX, 0(SP) // PC of function value to call (callbackWrap)
CALL ·cgocallback(SB)
// Get callback result.
MOVQ (24+callbackArgs_result)(SP), AX
ADDQ $(24+callbackArgs__size), SP
POP_REGS_HOST_TO_ABI0()
// The return value was placed in AX above.
RET
// uint32 tstart_stdcall(M *newm);
TEXT runtime·tstart_stdcall<ABIInternal>(SB),NOSPLIT,$0
// Switch from the host ABI to the Go ABI.
PUSH_REGS_HOST_TO_ABI0()
// CX contains first arg newm
MOVQ m_g0(CX), DX // g
// Layout new m scheduler stack on os stack.
MOVQ SP, AX
MOVQ AX, (g_stack+stack_hi)(DX)
SUBQ $(64*1024), AX // initial stack size (adjusted later)
MOVQ AX, (g_stack+stack_lo)(DX)
ADDQ $const__StackGuard, AX
MOVQ AX, g_stackguard0(DX)
MOVQ AX, g_stackguard1(DX)
// Set up tls.
LEAQ m_tls(CX), SI
MOVQ SI, 0x28(GS)
MOVQ CX, g_m(DX)
MOVQ DX, g(SI)
CALL runtime·stackcheck(SB) // clobbers AX,CX
CALL runtime·mstart(SB)
POP_REGS_HOST_TO_ABI0()
XORL AX, AX // return 0 == success
RET
// set tls base to DI
TEXT runtime·settls(SB),NOSPLIT,$0
MOVQ DI, 0x28(GS)
RET
// Runs on OS stack.
// duration (in -100ns units) is in dt+0(FP).
// g may be nil.
// The function leaves room for 4 syscall parameters
// (as per windows amd64 calling convention).
TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48-4
MOVLQSX dt+0(FP), BX
MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
MOVQ AX, 40(SP)
LEAQ 32(SP), R8 // ptime
MOVQ BX, (R8)
MOVQ $-1, CX // handle
MOVQ $0, DX // alertable
MOVQ runtime·_NtWaitForSingleObject(SB), AX
CALL AX
MOVQ 40(SP), SP
RET
// Runs on OS stack. duration (in -100ns units) is in dt+0(FP).
// g is valid.
TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72-4
MOVLQSX dt+0(FP), BX
get_tls(CX)
MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
MOVQ AX, 64(SP)
MOVQ g(CX), CX
MOVQ g_m(CX), CX
MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer
MOVQ CX, 48(SP) // save hTimer for later
LEAQ 56(SP), DX // lpDueTime
MOVQ BX, (DX)
MOVQ $0, R8 // lPeriod
MOVQ $0, R9 // pfnCompletionRoutine
MOVQ $0, AX
MOVQ AX, 32(SP) // lpArgToCompletionRoutine
MOVQ AX, 40(SP) // fResume
MOVQ runtime·_SetWaitableTimer(SB), AX
CALL AX
MOVQ 48(SP), CX // handle
MOVQ $0, DX // alertable
MOVQ $0, R8 // ptime
MOVQ runtime·_NtWaitForSingleObject(SB), AX
CALL AX
MOVQ 64(SP), SP
RET
// Runs on OS stack.
TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
SUBQ $(48), SP // room for SP and 4 args as per Windows requirement
// plus one extra word to keep stack 16 bytes aligned
MOVQ AX, 32(SP)
MOVQ runtime·_SwitchToThread(SB), AX
CALL AX
MOVQ 32(SP), SP
RET
// See https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/
// Archived copy at:
// http://web.archive.org/web/20210411000829/https://wrkhpi.wordpress.com/2007/08/09/getting-os-information-the-kuser_shared_data-structure/
// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
#define _INTERRUPT_TIME 0x7ffe0008
#define _SYSTEM_TIME 0x7ffe0014
#define time_lo 0
#define time_hi1 4
#define time_hi2 8
TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
CMPB runtime·useQPCTime(SB), $0
JNE useQPC
MOVQ $_INTERRUPT_TIME, DI
loop:
MOVL time_hi1(DI), AX
MOVL time_lo(DI), BX
MOVL time_hi2(DI), CX
CMPL AX, CX
JNE loop
SHLQ $32, CX
ORQ BX, CX
IMULQ $100, CX
MOVQ CX, ret+0(FP)
RET
useQPC:
// Call with ABIInternal because we could be
// very deep in a nosplit context and the wrapper
// adds stack space.
// TODO(#40724): The result from nanotimeQPC will
// be passed in a register, so store that to the
// stack so we can return through a wrapper.
JMP runtime·nanotimeQPC<ABIInternal>(SB)
RET
TEXT time·now(SB),NOSPLIT,$0-24
CMPB runtime·useQPCTime(SB), $0
JNE useQPC
MOVQ $_INTERRUPT_TIME, DI
loop:
MOVL time_hi1(DI), AX
MOVL time_lo(DI), BX
MOVL time_hi2(DI), CX
CMPL AX, CX
JNE loop
SHLQ $32, AX
ORQ BX, AX
IMULQ $100, AX
MOVQ AX, mono+16(FP)
MOVQ $_SYSTEM_TIME, DI
wall:
MOVL time_hi1(DI), AX
MOVL time_lo(DI), BX
MOVL time_hi2(DI), CX
CMPL AX, CX
JNE wall
SHLQ $32, AX
ORQ BX, AX
MOVQ $116444736000000000, DI
SUBQ DI, AX
IMULQ $100, AX
// generated code for
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
// adapted to reduce duplication
MOVQ AX, CX
MOVQ $1360296554856532783, AX
MULQ CX
ADDQ CX, DX
RCRQ $1, DX
SHRQ $29, DX
MOVQ DX, sec+0(FP)
IMULQ $1000000000, DX
SUBQ DX, CX
MOVL CX, nsec+8(FP)
RET
useQPC:
JMP runtime·nowQPC(SB)
RET
// func osSetupTLS(mp *m)
// Setup TLS. for use by needm on Windows.
TEXT runtime·osSetupTLS(SB),NOSPLIT,$0-8
MOVQ mp+0(FP), AX
LEAQ m_tls(AX), DI
CALL runtime·settls(SB)
RET