github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/runtime/sys_darwin_386.s (about)

     1  // Copyright 2009 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  // System calls and other sys.stuff for 386, Darwin
     6  // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
     7  // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
     8  
     9  #include "go_asm.h"
    10  #include "go_tls.h"
    11  #include "textflag.h"
    12  
    13  // Exit the entire program (like C exit)
    14  TEXT runtime·exit(SB),NOSPLIT,$0
    15  	MOVL	$1, AX
    16  	INT	$0x80
    17  	MOVL	$0xf1, 0xf1  // crash
    18  	RET
    19  
    20  // Exit this OS thread (like pthread_exit, which eventually
    21  // calls __bsdthread_terminate).
    22  TEXT runtime·exit1(SB),NOSPLIT,$0
    23  	MOVL	$361, AX
    24  	INT	$0x80
    25  	JAE 2(PC)
    26  	MOVL	$0xf1, 0xf1  // crash
    27  	RET
    28  
    29  TEXT runtime·open(SB),NOSPLIT,$0
    30  	MOVL	$5, AX
    31  	INT	$0x80
    32  	JAE	2(PC)
    33  	MOVL	$-1, AX
    34  	MOVL	AX, ret+12(FP)
    35  	RET
    36  
    37  TEXT runtime·closefd(SB),NOSPLIT,$0
    38  	MOVL	$6, AX
    39  	INT	$0x80
    40  	JAE	2(PC)
    41  	MOVL	$-1, AX
    42  	MOVL	AX, ret+4(FP)
    43  	RET
    44  
    45  TEXT runtime·read(SB),NOSPLIT,$0
    46  	MOVL	$3, AX
    47  	INT	$0x80
    48  	JAE	2(PC)
    49  	MOVL	$-1, AX
    50  	MOVL	AX, ret+12(FP)
    51  	RET
    52  
    53  TEXT runtime·write(SB),NOSPLIT,$0
    54  	MOVL	$4, AX
    55  	INT	$0x80
    56  	JAE	2(PC)
    57  	MOVL	$-1, AX
    58  	MOVL	AX, ret+12(FP)
    59  	RET
    60  
    61  TEXT runtime·raise(SB),NOSPLIT,$0
    62  	// Ideally we'd send the signal to the current thread,
    63  	// not the whole process, but that's too hard on OS X.
    64  	JMP	runtime·raiseproc(SB)
    65  
    66  TEXT runtime·raiseproc(SB),NOSPLIT,$16
    67  	MOVL	$20, AX // getpid
    68  	INT	$0x80
    69  	MOVL	AX, 4(SP)	// pid
    70  	MOVL	sig+0(FP), AX
    71  	MOVL	AX, 8(SP)	// signal
    72  	MOVL	$1, 12(SP)	// posix
    73  	MOVL	$37, AX // kill
    74  	INT	$0x80
    75  	RET
    76  
    77  TEXT runtime·mmap(SB),NOSPLIT,$0
    78  	MOVL	$197, AX
    79  	INT	$0x80
    80  	MOVL	AX, ret+24(FP)
    81  	RET
    82  
    83  TEXT runtime·madvise(SB),NOSPLIT,$0
    84  	MOVL	$75, AX
    85  	INT	$0x80
    86  	// ignore failure - maybe pages are locked
    87  	RET
    88  
    89  TEXT runtime·munmap(SB),NOSPLIT,$0
    90  	MOVL	$73, AX
    91  	INT	$0x80
    92  	JAE	2(PC)
    93  	MOVL	$0xf1, 0xf1  // crash
    94  	RET
    95  
    96  TEXT runtime·setitimer(SB),NOSPLIT,$0
    97  	MOVL	$83, AX
    98  	INT	$0x80
    99  	RET
   100  
   101  // OS X comm page time offsets
   102  // http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h
   103  #define	cpu_capabilities	0x20
   104  #define	nt_tsc_base	0x50
   105  #define	nt_scale	0x58
   106  #define	nt_shift	0x5c
   107  #define	nt_ns_base	0x60
   108  #define	nt_generation	0x68
   109  #define	gtod_generation	0x6c
   110  #define	gtod_ns_base	0x70
   111  #define	gtod_sec_base	0x78
   112  
   113  // called from assembly
   114  // 64-bit unix nanoseconds returned in DX:AX.
   115  // I'd much rather write this in C but we need
   116  // assembly for the 96-bit multiply and RDTSC.
   117  TEXT runtime·now(SB),NOSPLIT,$40
   118  	MOVL	$0xffff0000, BP /* comm page base */
   119  	
   120  	// Test for slow CPU. If so, the math is completely
   121  	// different, and unimplemented here, so use the
   122  	// system call.
   123  	MOVL	cpu_capabilities(BP), AX
   124  	TESTL	$0x4000, AX
   125  	JNZ	systime
   126  
   127  	// Loop trying to take a consistent snapshot
   128  	// of the time parameters.
   129  timeloop:
   130  	MOVL	gtod_generation(BP), BX
   131  	TESTL	BX, BX
   132  	JZ	systime
   133  	MOVL	nt_generation(BP), CX
   134  	TESTL	CX, CX
   135  	JZ	timeloop
   136  	RDTSC
   137  	MOVL	nt_tsc_base(BP), SI
   138  	MOVL	(nt_tsc_base+4)(BP), DI
   139  	MOVL	SI, 0(SP)
   140  	MOVL	DI, 4(SP)
   141  	MOVL	nt_scale(BP), SI
   142  	MOVL	SI, 8(SP)
   143  	MOVL	nt_ns_base(BP), SI
   144  	MOVL	(nt_ns_base+4)(BP), DI
   145  	MOVL	SI, 12(SP)
   146  	MOVL	DI, 16(SP)
   147  	CMPL	nt_generation(BP), CX
   148  	JNE	timeloop
   149  	MOVL	gtod_ns_base(BP), SI
   150  	MOVL	(gtod_ns_base+4)(BP), DI
   151  	MOVL	SI, 20(SP)
   152  	MOVL	DI, 24(SP)
   153  	MOVL	gtod_sec_base(BP), SI
   154  	MOVL	(gtod_sec_base+4)(BP), DI
   155  	MOVL	SI, 28(SP)
   156  	MOVL	DI, 32(SP)
   157  	CMPL	gtod_generation(BP), BX
   158  	JNE	timeloop
   159  
   160  	// Gathered all the data we need. Compute time.
   161  	//	((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9
   162  	// The multiply and shift extracts the top 64 bits of the 96-bit product.
   163  	SUBL	0(SP), AX // DX:AX = (tsc - nt_tsc_base)
   164  	SBBL	4(SP), DX
   165  
   166  	// We have x = tsc - nt_tsc_base - DX:AX to be
   167  	// multiplied by y = nt_scale = 8(SP), keeping the top 64 bits of the 96-bit product.
   168  	// x*y = (x&0xffffffff)*y + (x&0xffffffff00000000)*y
   169  	// (x*y)>>32 = ((x&0xffffffff)*y)>>32 + (x>>32)*y
   170  	MOVL	DX, CX // SI = (x&0xffffffff)*y >> 32
   171  	MOVL	$0, DX
   172  	MULL	8(SP)
   173  	MOVL	DX, SI
   174  
   175  	MOVL	CX, AX // DX:AX = (x>>32)*y
   176  	MOVL	$0, DX
   177  	MULL	8(SP)
   178  
   179  	ADDL	SI, AX	// DX:AX += (x&0xffffffff)*y >> 32
   180  	ADCL	$0, DX
   181  	
   182  	// DX:AX is now ((tsc - nt_tsc_base) * nt_scale) >> 32.
   183  	ADDL	12(SP), AX	// DX:AX += nt_ns_base
   184  	ADCL	16(SP), DX
   185  	SUBL	20(SP), AX	// DX:AX -= gtod_ns_base
   186  	SBBL	24(SP), DX
   187  	MOVL	AX, SI	// DI:SI = DX:AX
   188  	MOVL	DX, DI
   189  	MOVL	28(SP), AX	// DX:AX = gtod_sec_base*1e9
   190  	MOVL	32(SP), DX
   191  	MOVL	$1000000000, CX
   192  	MULL	CX
   193  	ADDL	SI, AX	// DX:AX += DI:SI
   194  	ADCL	DI, DX
   195  	RET
   196  
   197  systime:
   198  	// Fall back to system call (usually first call in this thread)
   199  	LEAL	16(SP), AX	// must be non-nil, unused
   200  	MOVL	AX, 4(SP)
   201  	MOVL	$0, 8(SP)	// time zone pointer
   202  	MOVL	$0, 12(SP)	// required as of Sierra; Issue 16570
   203  	MOVL	$116, AX // SYS_GETTIMEOFDAY
   204  	INT	$0x80
   205  	CMPL	AX, $0
   206  	JNE	inreg
   207  	MOVL	16(SP), AX
   208  	MOVL	20(SP), DX
   209  inreg:
   210  	// sec is in AX, usec in DX
   211  	// convert to DX:AX nsec
   212  	MOVL	DX, BX
   213  	MOVL	$1000000000, CX
   214  	MULL	CX
   215  	IMULL	$1000, BX
   216  	ADDL	BX, AX
   217  	ADCL	$0, DX
   218  	RET
   219  
   220  // func now() (sec int64, nsec int32)
   221  TEXT time·now(SB),NOSPLIT,$0
   222  	CALL	runtime·now(SB)
   223  	MOVL	$1000000000, CX
   224  	DIVL	CX
   225  	MOVL	AX, sec+0(FP)
   226  	MOVL	$0, sec+4(FP)
   227  	MOVL	DX, nsec+8(FP)
   228  	RET
   229  
   230  // func nanotime() int64
   231  TEXT runtime·nanotime(SB),NOSPLIT,$0
   232  	CALL	runtime·now(SB)
   233  	MOVL	AX, ret_lo+0(FP)
   234  	MOVL	DX, ret_hi+4(FP)
   235  	RET
   236  
   237  TEXT runtime·sigprocmask(SB),NOSPLIT,$0
   238  	MOVL	$329, AX  // pthread_sigmask (on OS X, sigprocmask==entire process)
   239  	INT	$0x80
   240  	JAE	2(PC)
   241  	MOVL	$0xf1, 0xf1  // crash
   242  	RET
   243  
   244  TEXT runtime·sigaction(SB),NOSPLIT,$0
   245  	MOVL	$46, AX
   246  	INT	$0x80
   247  	JAE	2(PC)
   248  	MOVL	$0xf1, 0xf1  // crash
   249  	RET
   250  
   251  TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
   252  	MOVL	fn+0(FP), AX
   253  	MOVL	sig+4(FP), BX
   254  	MOVL	info+8(FP), CX
   255  	MOVL	ctx+12(FP), DX
   256  	MOVL	SP, SI
   257  	SUBL	$32, SP		// align stack; handler might be C code
   258  	ANDL	$~15, SP
   259  	MOVL	BX, 0(SP)
   260  	MOVL	CX, 4(SP)
   261  	MOVL	DX, 8(SP)
   262  	MOVL	SI, 12(SP)
   263  	CALL	AX
   264  	MOVL	12(SP), AX
   265  	MOVL	AX, SP
   266  	RET
   267  
   268  // Sigtramp's job is to call the actual signal handler.
   269  // It is called with the following arguments on the stack:
   270  //	0(SP)	"return address" - ignored
   271  //	4(SP)	actual handler
   272  //	8(SP)	siginfo style
   273  //	12(SP)	signal number
   274  //	16(SP)	siginfo
   275  //	20(SP)	context
   276  TEXT runtime·sigtramp(SB),NOSPLIT,$20
   277  	MOVL	sig+8(FP), BX
   278  	MOVL	BX, 0(SP)
   279  	MOVL	info+12(FP), BX
   280  	MOVL	BX, 4(SP)
   281  	MOVL	ctx+16(FP), BX
   282  	MOVL	BX, 8(SP)
   283  	CALL	runtime·sigtrampgo(SB)
   284  
   285  	// call sigreturn
   286  	MOVL	ctx+16(FP), CX
   287  	MOVL	infostyle+4(FP), BX
   288  	MOVL	$0, 0(SP)	// "caller PC" - ignored
   289  	MOVL	CX, 4(SP)
   290  	MOVL	BX, 8(SP)
   291  	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
   292  	INT	$0x80
   293  	MOVL	$0xf1, 0xf1  // crash
   294  	RET
   295  
   296  TEXT runtime·sigaltstack(SB),NOSPLIT,$0
   297  	MOVL	$53, AX
   298  	INT	$0x80
   299  	JAE	2(PC)
   300  	MOVL	$0xf1, 0xf1  // crash
   301  	RET
   302  
   303  TEXT runtime·usleep(SB),NOSPLIT,$32
   304  	MOVL	$0, DX
   305  	MOVL	usec+0(FP), AX
   306  	MOVL	$1000000, CX
   307  	DIVL	CX
   308  	MOVL	AX, 24(SP)  // sec
   309  	MOVL	DX, 28(SP)  // usec
   310  
   311  	// select(0, 0, 0, 0, &tv)
   312  	MOVL	$0, 0(SP)  // "return PC" - ignored
   313  	MOVL	$0, 4(SP)
   314  	MOVL	$0, 8(SP)
   315  	MOVL	$0, 12(SP)
   316  	MOVL	$0, 16(SP)
   317  	LEAL	24(SP), AX
   318  	MOVL	AX, 20(SP)
   319  	MOVL	$93, AX
   320  	INT	$0x80
   321  	RET
   322  
   323  // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
   324  // System call args are: func arg stack pthread flags.
   325  TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
   326  	MOVL	$360, AX
   327  	// 0(SP) is where the caller PC would be; kernel skips it
   328  	MOVL	fn+8(FP), BX
   329  	MOVL	BX, 4(SP)	// func
   330  	MOVL	arg+4(FP), BX
   331  	MOVL	BX, 8(SP)	// arg
   332  	MOVL	stk+0(FP), BX
   333  	MOVL	BX, 12(SP)	// stack
   334  	MOVL    $0, 16(SP)      // pthread
   335  	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
   336  	INT	$0x80
   337  	JAE	4(PC)
   338  	NEGL	AX
   339  	MOVL	AX, ret+12(FP)
   340  	RET
   341  	MOVL	$0, AX
   342  	MOVL	AX, ret+12(FP)
   343  	RET
   344  
   345  // The thread that bsdthread_create creates starts executing here,
   346  // because we registered this function using bsdthread_register
   347  // at startup.
   348  //	AX = "pthread" (= 0x0)
   349  //	BX = mach thread port
   350  //	CX = "func" (= fn)
   351  //	DX = "arg" (= m)
   352  //	DI = stack top
   353  //	SI = flags (= 0x1000000)
   354  //	SP = stack - C_32_STK_ALIGN
   355  TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
   356  	// set up ldt 7+id to point at m->tls.
   357  	LEAL	m_tls(DX), BP
   358  	MOVL	m_id(DX), DI
   359  	ADDL	$7, DI	// m0 is LDT#7. count up.
   360  	// setldt(tls#, &tls, sizeof tls)
   361  	PUSHAL	// save registers
   362  	PUSHL	$32	// sizeof tls
   363  	PUSHL	BP	// &tls
   364  	PUSHL	DI	// tls #
   365  	CALL	runtime·setldt(SB)
   366  	POPL	AX
   367  	POPL	AX
   368  	POPL	AX
   369  	POPAL
   370  
   371  	// Now segment is established. Initialize m, g.
   372  	get_tls(BP)
   373  	MOVL    m_g0(DX), AX
   374  	MOVL	AX, g(BP)
   375  	MOVL	DX, g_m(AX)
   376  	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
   377  	CALL	runtime·stackcheck(SB)		// smashes AX
   378  	CALL	CX	// fn()
   379  	CALL	runtime·exit1(SB)
   380  	RET
   381  
   382  // func bsdthread_register() int32
   383  // registers callbacks for threadstart (see bsdthread_create above
   384  // and wqthread and pthsize (not used).  returns 0 on success.
   385  TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
   386  	MOVL	$366, AX
   387  	// 0(SP) is where kernel expects caller PC; ignored
   388  	MOVL	$runtime·bsdthread_start(SB), 4(SP)	// threadstart
   389  	MOVL	$0, 8(SP)	// wqthread, not used by us
   390  	MOVL	$0, 12(SP)	// pthsize, not used by us
   391  	MOVL	$0, 16(SP)	// dummy_value [sic]
   392  	MOVL	$0, 20(SP)	// targetconc_ptr
   393  	MOVL	$0, 24(SP)	// dispatchqueue_offset
   394  	INT	$0x80
   395  	JAE	4(PC)
   396  	NEGL	AX
   397  	MOVL	AX, ret+0(FP)
   398  	RET
   399  	MOVL	$0, AX
   400  	MOVL	AX, ret+0(FP)
   401  	RET
   402  
   403  // Invoke Mach system call.
   404  // Assumes system call number in AX,
   405  // caller PC on stack, caller's caller PC next,
   406  // and then the system call arguments.
   407  //
   408  // Can be used for BSD too, but we don't,
   409  // because if you use this interface the BSD
   410  // system call numbers need an extra field
   411  // in the high 16 bits that seems to be the
   412  // argument count in bytes but is not always.
   413  // INT $0x80 works fine for those.
   414  TEXT runtime·sysenter(SB),NOSPLIT,$0
   415  	POPL	DX
   416  	MOVL	SP, CX
   417  	BYTE $0x0F; BYTE $0x34;  // SYSENTER
   418  	// returns to DX with SP set to CX
   419  
   420  TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
   421  	MOVL	$-31, AX
   422  	CALL	runtime·sysenter(SB)
   423  	MOVL	AX, ret+28(FP)
   424  	RET
   425  
   426  TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
   427  	MOVL	$-26, AX
   428  	CALL	runtime·sysenter(SB)
   429  	MOVL	AX, ret+0(FP)
   430  	RET
   431  
   432  TEXT runtime·mach_task_self(SB),NOSPLIT,$0
   433  	MOVL	$-28, AX
   434  	CALL	runtime·sysenter(SB)
   435  	MOVL	AX, ret+0(FP)
   436  	RET
   437  
   438  // Mach provides trap versions of the semaphore ops,
   439  // instead of requiring the use of RPC.
   440  
   441  // func mach_semaphore_wait(sema uint32) int32
   442  TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
   443  	MOVL	$-36, AX
   444  	CALL	runtime·sysenter(SB)
   445  	MOVL	AX, ret+4(FP)
   446  	RET
   447  
   448  // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
   449  TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
   450  	MOVL	$-38, AX
   451  	CALL	runtime·sysenter(SB)
   452  	MOVL	AX, ret+12(FP)
   453  	RET
   454  
   455  // func mach_semaphore_signal(sema uint32) int32
   456  TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
   457  	MOVL	$-33, AX
   458  	CALL	runtime·sysenter(SB)
   459  	MOVL	AX, ret+4(FP)
   460  	RET
   461  
   462  // func mach_semaphore_signal_all(sema uint32) int32
   463  TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
   464  	MOVL	$-34, AX
   465  	CALL	runtime·sysenter(SB)
   466  	MOVL	AX, ret+4(FP)
   467  	RET
   468  
   469  // func setldt(entry int, address int, limit int)
   470  // entry and limit are ignored.
   471  TEXT runtime·setldt(SB),NOSPLIT,$32
   472  	MOVL	address+4(FP), BX	// aka base
   473  
   474  	/*
   475  	 * When linking against the system libraries,
   476  	 * we use its pthread_create and let it set up %gs
   477  	 * for us.  When we do that, the private storage
   478  	 * we get is not at 0(GS) but at 0x468(GS).
   479  	 * 8l rewrites 0(TLS) into 0x468(GS) for us.
   480  	 * To accommodate that rewrite, we translate the
   481  	 * address and limit here so that 0x468(GS) maps to 0(address).
   482  	 *
   483  	 * See cgo/gcc_darwin_386.c:/468 for the derivation
   484  	 * of the constant.
   485  	 */
   486  	SUBL	$0x468, BX
   487  
   488  	/*
   489  	 * Must set up as USER_CTHREAD segment because
   490  	 * Darwin forces that value into %gs for signal handlers,
   491  	 * and if we don't set one up, we'll get a recursive
   492  	 * fault trying to get into the signal handler.
   493  	 * Since we have to set one up anyway, it might as
   494  	 * well be the value we want.  So don't bother with
   495  	 * i386_set_ldt.
   496  	 */
   497  	MOVL	BX, 4(SP)
   498  	MOVL	$3, AX	// thread_fast_set_cthread_self - machdep call #3
   499  	INT	$0x82	// sic: 0x82, not 0x80, for machdep call
   500  
   501  	XORL	AX, AX
   502  	MOVW	GS, AX
   503  	RET
   504  
   505  TEXT runtime·sysctl(SB),NOSPLIT,$0
   506  	MOVL	$202, AX
   507  	INT	$0x80
   508  	JAE	4(PC)
   509  	NEGL	AX
   510  	MOVL	AX, ret+24(FP)
   511  	RET
   512  	MOVL	$0, AX
   513  	MOVL	AX, ret+24(FP)
   514  	RET
   515  
   516  // func kqueue() int32
   517  TEXT runtime·kqueue(SB),NOSPLIT,$0
   518  	MOVL	$362, AX
   519  	INT	$0x80
   520  	JAE	2(PC)
   521  	NEGL	AX
   522  	MOVL	AX, ret+0(FP)
   523  	RET
   524  
   525  // func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
   526  TEXT runtime·kevent(SB),NOSPLIT,$0
   527  	MOVL	$363, AX
   528  	INT	$0x80
   529  	JAE	2(PC)
   530  	NEGL	AX
   531  	MOVL	AX, ret+24(FP)
   532  	RET
   533  
   534  // func closeonexec(fd int32)
   535  TEXT runtime·closeonexec(SB),NOSPLIT,$32
   536  	MOVL	$92, AX  // fcntl
   537  	// 0(SP) is where the caller PC would be; kernel skips it
   538  	MOVL	fd+0(FP), BX
   539  	MOVL	BX, 4(SP)  // fd
   540  	MOVL	$2, 8(SP)  // F_SETFD
   541  	MOVL	$1, 12(SP)  // FD_CLOEXEC
   542  	INT	$0x80
   543  	JAE	2(PC)
   544  	NEGL	AX
   545  	RET