// 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 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