| // Copyright 2014 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. | 
 | // | 
 | // System calls and other sys.stuff for AMD64, SunOS | 
 | // /usr/include/sys/syscall.h for syscall numbers. | 
 | // | 
 |  | 
 | #include "go_asm.h" | 
 | #include "go_tls.h" | 
 | #include "textflag.h" | 
 |  | 
 | // This is needed by asm_amd64.s | 
 | TEXT runtime·settls(SB),NOSPLIT,$8 | 
 | 	RET | 
 |  | 
 | // void libc_miniterrno(void *(*___errno)(void)); | 
 | // | 
 | // Set the TLS errno pointer in M. | 
 | // | 
 | // Called using runtime·asmcgocall from os_solaris.c:/minit. | 
 | // NOT USING GO CALLING CONVENTION. | 
 | TEXT runtime·miniterrno(SB),NOSPLIT,$0 | 
 | 	// asmcgocall will put first argument into DI. | 
 | 	CALL	DI	// SysV ABI so returns in AX | 
 | 	get_tls(CX) | 
 | 	MOVQ	g(CX), BX | 
 | 	MOVQ	g_m(BX), BX | 
 | 	MOVQ	AX,	(m_mOS+mOS_perrno)(BX) | 
 | 	RET | 
 |  | 
 | // int64 runtime·nanotime1(void); | 
 | // | 
 | // clock_gettime(3c) wrapper because Timespec is too large for | 
 | // runtime·nanotime stack. | 
 | // | 
 | // Called using runtime·sysvicall6 from os_solaris.c:/nanotime. | 
 | // NOT USING GO CALLING CONVENTION. | 
 | TEXT runtime·nanotime1(SB),NOSPLIT,$0 | 
 | 	// need space for the timespec argument. | 
 | 	SUBQ	$64, SP	// 16 bytes will do, but who knows in the future? | 
 | 	MOVQ	$3, DI	// CLOCK_REALTIME from <sys/time_impl.h> | 
 | 	MOVQ	SP, SI | 
 | 	LEAQ	libc_clock_gettime(SB), AX | 
 | 	CALL	AX | 
 | 	MOVQ	(SP), AX	// tv_sec from struct timespec | 
 | 	IMULQ	$1000000000, AX	// multiply into nanoseconds | 
 | 	ADDQ	8(SP), AX	// tv_nsec, offset should be stable. | 
 | 	ADDQ	$64, SP | 
 | 	RET | 
 |  | 
 | // pipe(3c) wrapper that returns fds in AX, DX. | 
 | // NOT USING GO CALLING CONVENTION. | 
 | TEXT runtime·pipe1(SB),NOSPLIT,$0 | 
 | 	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte aligned | 
 | 	MOVQ	SP, DI | 
 | 	LEAQ	libc_pipe(SB), AX | 
 | 	CALL	AX | 
 | 	MOVL	0(SP), AX | 
 | 	MOVL	4(SP), DX | 
 | 	ADDQ	$16, SP | 
 | 	RET | 
 |  | 
 | // Call a library function with SysV calling conventions. | 
 | // The called function can take a maximum of 6 INTEGER class arguments, | 
 | // see  | 
 | //   Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell | 
 | //   System V Application Binary Interface  | 
 | //   AMD64 Architecture Processor Supplement | 
 | // section 3.2.3. | 
 | // | 
 | // Called by runtime·asmcgocall or runtime·cgocall. | 
 | // NOT USING GO CALLING CONVENTION. | 
 | TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0 | 
 | 	// asmcgocall will put first argument into DI. | 
 | 	PUSHQ	DI			// save for later | 
 | 	MOVQ	libcall_fn(DI), AX | 
 | 	MOVQ	libcall_args(DI), R11 | 
 | 	MOVQ	libcall_n(DI), R10 | 
 |  | 
 | 	get_tls(CX) | 
 | 	MOVQ	g(CX), BX | 
 | 	CMPQ	BX, $0 | 
 | 	JEQ	skiperrno1 | 
 | 	MOVQ	g_m(BX), BX | 
 | 	MOVQ	(m_mOS+mOS_perrno)(BX), DX | 
 | 	CMPQ	DX, $0 | 
 | 	JEQ	skiperrno1 | 
 | 	MOVL	$0, 0(DX) | 
 |  | 
 | skiperrno1: | 
 | 	CMPQ	R11, $0 | 
 | 	JEQ	skipargs | 
 | 	// Load 6 args into correspondent registers. | 
 | 	MOVQ	0(R11), DI | 
 | 	MOVQ	8(R11), SI | 
 | 	MOVQ	16(R11), DX | 
 | 	MOVQ	24(R11), CX | 
 | 	MOVQ	32(R11), R8 | 
 | 	MOVQ	40(R11), R9 | 
 | skipargs: | 
 |  | 
 | 	// Call SysV function | 
 | 	CALL	AX | 
 |  | 
 | 	// Return result | 
 | 	POPQ	DI | 
 | 	MOVQ	AX, libcall_r1(DI) | 
 | 	MOVQ	DX, libcall_r2(DI) | 
 |  | 
 | 	get_tls(CX) | 
 | 	MOVQ	g(CX), BX | 
 | 	CMPQ	BX, $0 | 
 | 	JEQ	skiperrno2 | 
 | 	MOVQ	g_m(BX), BX | 
 | 	MOVQ	(m_mOS+mOS_perrno)(BX), AX | 
 | 	CMPQ	AX, $0 | 
 | 	JEQ	skiperrno2 | 
 | 	MOVL	0(AX), AX | 
 | 	MOVQ	AX, libcall_err(DI) | 
 |  | 
 | skiperrno2:	 | 
 | 	RET | 
 |  | 
 | // uint32 tstart_sysvicall(M *newm); | 
 | TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0 | 
 | 	// DI contains first arg newm | 
 | 	MOVQ	m_g0(DI), DX		// g | 
 |  | 
 | 	// Make TLS entries point at g and m. | 
 | 	get_tls(BX) | 
 | 	MOVQ	DX, g(BX) | 
 | 	MOVQ	DI, g_m(DX) | 
 |  | 
 | 	// Layout new m scheduler stack on os stack. | 
 | 	MOVQ	SP, AX | 
 | 	MOVQ	AX, (g_stack+stack_hi)(DX) | 
 | 	SUBQ	$(0x100000), AX		// stack size | 
 | 	MOVQ	AX, (g_stack+stack_lo)(DX) | 
 | 	ADDQ	$const__StackGuard, AX | 
 | 	MOVQ	AX, g_stackguard0(DX) | 
 | 	MOVQ	AX, g_stackguard1(DX) | 
 |  | 
 | 	// Someday the convention will be D is always cleared. | 
 | 	CLD | 
 |  | 
 | 	CALL	runtime·stackcheck(SB)	// clobbers AX,CX | 
 | 	CALL	runtime·mstart(SB) | 
 |  | 
 | 	XORL	AX, AX			// return 0 == success | 
 | 	MOVL	AX, ret+8(FP) | 
 | 	RET | 
 |  | 
 | // Careful, this is called by __sighndlr, a libc function. We must preserve | 
 | // registers as per AMD 64 ABI. | 
 | TEXT runtime·sigtramp(SB),NOSPLIT,$0 | 
 | 	// Note that we are executing on altsigstack here, so we have | 
 | 	// more stack available than NOSPLIT would have us believe. | 
 | 	// To defeat the linker, we make our own stack frame with | 
 | 	// more space: | 
 | 	SUBQ    $184, SP | 
 |  | 
 | 	// save registers | 
 | 	MOVQ    BX, 32(SP) | 
 | 	MOVQ    BP, 40(SP) | 
 | 	MOVQ	R12, 48(SP) | 
 | 	MOVQ	R13, 56(SP) | 
 | 	MOVQ	R14, 64(SP) | 
 | 	MOVQ	R15, 72(SP) | 
 |  | 
 | 	get_tls(BX) | 
 | 	// check that g exists | 
 | 	MOVQ	g(BX), R10 | 
 | 	CMPQ	R10, $0 | 
 | 	JNE	allgood | 
 | 	MOVQ	SI, 80(SP) | 
 | 	MOVQ	DX, 88(SP) | 
 | 	LEAQ	80(SP), AX | 
 | 	MOVQ	DI, 0(SP) | 
 | 	MOVQ	AX, 8(SP) | 
 | 	MOVQ	$runtime·badsignal(SB), AX | 
 | 	CALL	AX | 
 | 	JMP	exit | 
 |  | 
 | allgood: | 
 | 	// Save m->libcall and m->scratch. We need to do this because we | 
 | 	// might get interrupted by a signal in runtime·asmcgocall. | 
 |  | 
 | 	// save m->libcall  | 
 | 	MOVQ	g_m(R10), BP | 
 | 	LEAQ	m_libcall(BP), R11 | 
 | 	MOVQ	libcall_fn(R11), R10 | 
 | 	MOVQ	R10, 88(SP) | 
 | 	MOVQ	libcall_args(R11), R10 | 
 | 	MOVQ	R10, 96(SP) | 
 | 	MOVQ	libcall_n(R11), R10 | 
 | 	MOVQ	R10, 104(SP) | 
 | 	MOVQ    libcall_r1(R11), R10 | 
 | 	MOVQ    R10, 168(SP) | 
 | 	MOVQ    libcall_r2(R11), R10 | 
 | 	MOVQ    R10, 176(SP) | 
 |  | 
 | 	// save m->scratch | 
 | 	LEAQ	(m_mOS+mOS_scratch)(BP), R11 | 
 | 	MOVQ	0(R11), R10 | 
 | 	MOVQ	R10, 112(SP) | 
 | 	MOVQ	8(R11), R10 | 
 | 	MOVQ	R10, 120(SP) | 
 | 	MOVQ	16(R11), R10 | 
 | 	MOVQ	R10, 128(SP) | 
 | 	MOVQ	24(R11), R10 | 
 | 	MOVQ	R10, 136(SP) | 
 | 	MOVQ	32(R11), R10 | 
 | 	MOVQ	R10, 144(SP) | 
 | 	MOVQ	40(R11), R10 | 
 | 	MOVQ	R10, 152(SP) | 
 |  | 
 | 	// save errno, it might be EINTR; stuff we do here might reset it. | 
 | 	MOVQ	(m_mOS+mOS_perrno)(BP), R10 | 
 | 	MOVL	0(R10), R10 | 
 | 	MOVQ	R10, 160(SP) | 
 |  | 
 | 	// prepare call | 
 | 	MOVQ	DI, 0(SP) | 
 | 	MOVQ	SI, 8(SP) | 
 | 	MOVQ	DX, 16(SP) | 
 | 	CALL	runtime·sigtrampgo(SB) | 
 |  | 
 | 	get_tls(BX) | 
 | 	MOVQ	g(BX), BP | 
 | 	MOVQ	g_m(BP), BP | 
 | 	// restore libcall | 
 | 	LEAQ	m_libcall(BP), R11 | 
 | 	MOVQ	88(SP), R10 | 
 | 	MOVQ	R10, libcall_fn(R11) | 
 | 	MOVQ	96(SP), R10 | 
 | 	MOVQ	R10, libcall_args(R11) | 
 | 	MOVQ	104(SP), R10 | 
 | 	MOVQ	R10, libcall_n(R11) | 
 | 	MOVQ    168(SP), R10 | 
 | 	MOVQ    R10, libcall_r1(R11) | 
 | 	MOVQ    176(SP), R10 | 
 | 	MOVQ    R10, libcall_r2(R11) | 
 |  | 
 | 	// restore scratch | 
 | 	LEAQ	(m_mOS+mOS_scratch)(BP), R11 | 
 | 	MOVQ	112(SP), R10 | 
 | 	MOVQ	R10, 0(R11) | 
 | 	MOVQ	120(SP), R10 | 
 | 	MOVQ	R10, 8(R11) | 
 | 	MOVQ	128(SP), R10 | 
 | 	MOVQ	R10, 16(R11) | 
 | 	MOVQ	136(SP), R10 | 
 | 	MOVQ	R10, 24(R11) | 
 | 	MOVQ	144(SP), R10 | 
 | 	MOVQ	R10, 32(R11) | 
 | 	MOVQ	152(SP), R10 | 
 | 	MOVQ	R10, 40(R11) | 
 |  | 
 | 	// restore errno | 
 | 	MOVQ	(m_mOS+mOS_perrno)(BP), R11 | 
 | 	MOVQ	160(SP), R10 | 
 | 	MOVL	R10, 0(R11) | 
 |  | 
 | exit: | 
 | 	// restore registers | 
 | 	MOVQ	32(SP), BX | 
 | 	MOVQ	40(SP), BP | 
 | 	MOVQ	48(SP), R12 | 
 | 	MOVQ	56(SP), R13 | 
 | 	MOVQ	64(SP), R14 | 
 | 	MOVQ	72(SP), R15 | 
 |  | 
 | 	ADDQ    $184, SP | 
 | 	RET | 
 |  | 
 | TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 | 
 | 	MOVQ	fn+0(FP),    AX | 
 | 	MOVL	sig+8(FP),   DI | 
 | 	MOVQ	info+16(FP), SI | 
 | 	MOVQ	ctx+24(FP),  DX | 
 | 	PUSHQ	BP | 
 | 	MOVQ	SP, BP | 
 | 	ANDQ	$~15, SP     // alignment for x86_64 ABI | 
 | 	CALL	AX | 
 | 	MOVQ	BP, SP | 
 | 	POPQ	BP | 
 | 	RET | 
 |  | 
 | // Called from runtime·usleep (Go). Can be called on Go stack, on OS stack, | 
 | // can also be called in cgo callback path without a g->m. | 
 | TEXT runtime·usleep1(SB),NOSPLIT,$0 | 
 | 	MOVL	usec+0(FP), DI | 
 | 	MOVQ	$runtime·usleep2(SB), AX // to hide from 6l | 
 |  | 
 | 	// Execute call on m->g0. | 
 | 	get_tls(R15) | 
 | 	CMPQ	R15, $0 | 
 | 	JE	noswitch | 
 |  | 
 | 	MOVQ	g(R15), R13 | 
 | 	CMPQ	R13, $0 | 
 | 	JE	noswitch | 
 | 	MOVQ	g_m(R13), R13 | 
 | 	CMPQ	R13, $0 | 
 | 	JE	noswitch | 
 | 	// TODO(aram): do something about the cpu profiler here. | 
 |  | 
 | 	MOVQ	m_g0(R13), R14 | 
 | 	CMPQ	g(R15), R14 | 
 | 	JNE	switch | 
 | 	// executing on m->g0 already | 
 | 	CALL	AX | 
 | 	RET | 
 |  | 
 | switch: | 
 | 	// Switch to m->g0 stack and back. | 
 | 	MOVQ	(g_sched+gobuf_sp)(R14), R14 | 
 | 	MOVQ	SP, -8(R14) | 
 | 	LEAQ	-8(R14), SP | 
 | 	CALL	AX | 
 | 	MOVQ	0(SP), SP | 
 | 	RET | 
 |  | 
 | noswitch: | 
 | 	// Not a Go-managed thread. Do not switch stack. | 
 | 	CALL	AX | 
 | 	RET | 
 |  | 
 | // Runs on OS stack. duration (in µs units) is in DI. | 
 | TEXT runtime·usleep2(SB),NOSPLIT,$0 | 
 | 	LEAQ	libc_usleep(SB), AX | 
 | 	CALL	AX | 
 | 	RET | 
 |  | 
 | // Runs on OS stack, called from runtime·osyield. | 
 | TEXT runtime·osyield1(SB),NOSPLIT,$0 | 
 | 	LEAQ	libc_sched_yield(SB), AX | 
 | 	CALL	AX | 
 | 	RET | 
 |  | 
 | // func walltime() (sec int64, nsec int32) | 
 | TEXT runtime·walltime(SB),NOSPLIT,$8-12 | 
 | 	CALL	runtime·nanotime(SB) | 
 | 	MOVQ	0(SP), 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 |