rsc.io/go@v0.0.0-20150416155037-e040fd465409/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	12(SP), AX	// must be non-nil, unused
   200  	MOVL	AX, 4(SP)
   201  	MOVL	$0, 8(SP)	// time zone pointer
   202  	MOVL	$116, AX
   203  	INT	$0x80
   204  	// sec is in AX, usec in DX
   205  	// convert to DX:AX nsec
   206  	MOVL	DX, BX
   207  	MOVL	$1000000000, CX
   208  	MULL	CX
   209  	IMULL	$1000, BX
   210  	ADDL	BX, AX
   211  	ADCL	$0, DX
   212  	RET
   213  
   214  // func now() (sec int64, nsec int32)
   215  TEXT time·now(SB),NOSPLIT,$0
   216  	CALL	runtime·now(SB)
   217  	MOVL	$1000000000, CX
   218  	DIVL	CX
   219  	MOVL	AX, sec+0(FP)
   220  	MOVL	$0, sec+4(FP)
   221  	MOVL	DX, nsec+8(FP)
   222  	RET
   223  
   224  // func nanotime() int64
   225  TEXT runtime·nanotime(SB),NOSPLIT,$0
   226  	CALL	runtime·now(SB)
   227  	MOVL	AX, ret_lo+0(FP)
   228  	MOVL	DX, ret_hi+4(FP)
   229  	RET
   230  
   231  TEXT runtime·sigprocmask(SB),NOSPLIT,$0
   232  	MOVL	$329, AX  // pthread_sigmask (on OS X, sigprocmask==entire process)
   233  	INT	$0x80
   234  	JAE	2(PC)
   235  	MOVL	$0xf1, 0xf1  // crash
   236  	RET
   237  
   238  TEXT runtime·sigaction(SB),NOSPLIT,$0
   239  	MOVL	$46, AX
   240  	INT	$0x80
   241  	JAE	2(PC)
   242  	MOVL	$0xf1, 0xf1  // crash
   243  	RET
   244  
   245  // Sigtramp's job is to call the actual signal handler.
   246  // It is called with the following arguments on the stack:
   247  //	0(FP)	"return address" - ignored
   248  //	4(FP)	actual handler
   249  //	8(FP)	signal number
   250  //	12(FP)	siginfo style
   251  //	16(FP)	siginfo
   252  //	20(FP)	context
   253  TEXT runtime·sigtramp(SB),NOSPLIT,$40
   254  	get_tls(CX)
   255  	
   256  	// check that g exists
   257  	MOVL	g(CX), DI
   258  	CMPL	DI, $0
   259  	JNE	6(PC)
   260  	MOVL	sig+8(FP), BX
   261  	MOVL	BX, 0(SP)
   262  	MOVL	$runtime·badsignal(SB), AX
   263  	CALL	AX
   264  	JMP 	ret
   265  
   266  	// save g
   267  	MOVL	DI, 20(SP)
   268  
   269  	// g = m->gsignal
   270  	MOVL	g_m(DI), BP
   271  	MOVL	m_gsignal(BP), BP
   272  	MOVL	BP, g(CX)
   273  
   274  	// copy arguments to sighandler
   275  	MOVL	sig+8(FP), BX
   276  	MOVL	BX, 0(SP)
   277  	MOVL	info+12(FP), BX
   278  	MOVL	BX, 4(SP)
   279  	MOVL	context+16(FP), BX
   280  	MOVL	BX, 8(SP)
   281  	MOVL	DI, 12(SP)
   282  
   283  	MOVL	handler+0(FP), BX
   284  	CALL	BX
   285  
   286  	// restore g
   287  	get_tls(CX)
   288  	MOVL	20(SP), DI
   289  	MOVL	DI, g(CX)
   290  
   291  ret:
   292  	// call sigreturn
   293  	MOVL	context+16(FP), CX
   294  	MOVL	style+4(FP), BX
   295  	MOVL	$0, 0(SP)	// "caller PC" - ignored
   296  	MOVL	CX, 4(SP)
   297  	MOVL	BX, 8(SP)
   298  	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
   299  	INT	$0x80
   300  	MOVL	$0xf1, 0xf1  // crash
   301  	RET
   302  
   303  TEXT runtime·sigaltstack(SB),NOSPLIT,$0
   304  	MOVL	$53, AX
   305  	INT	$0x80
   306  	JAE	2(PC)
   307  	MOVL	$0xf1, 0xf1  // crash
   308  	RET
   309  
   310  TEXT runtime·usleep(SB),NOSPLIT,$32
   311  	MOVL	$0, DX
   312  	MOVL	usec+0(FP), AX
   313  	MOVL	$1000000, CX
   314  	DIVL	CX
   315  	MOVL	AX, 24(SP)  // sec
   316  	MOVL	DX, 28(SP)  // usec
   317  
   318  	// select(0, 0, 0, 0, &tv)
   319  	MOVL	$0, 0(SP)  // "return PC" - ignored
   320  	MOVL	$0, 4(SP)
   321  	MOVL	$0, 8(SP)
   322  	MOVL	$0, 12(SP)
   323  	MOVL	$0, 16(SP)
   324  	LEAL	24(SP), AX
   325  	MOVL	AX, 20(SP)
   326  	MOVL	$93, AX
   327  	INT	$0x80
   328  	RET
   329  
   330  // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
   331  // System call args are: func arg stack pthread flags.
   332  TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
   333  	MOVL	$360, AX
   334  	// 0(SP) is where the caller PC would be; kernel skips it
   335  	MOVL	fn+8(FP), BX
   336  	MOVL	BX, 4(SP)	// func
   337  	MOVL	arg+4(FP), BX
   338  	MOVL	BX, 8(SP)	// arg
   339  	MOVL	stk+0(FP), BX
   340  	MOVL	BX, 12(SP)	// stack
   341  	MOVL    $0, 16(SP)      // pthread
   342  	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
   343  	INT	$0x80
   344  	JAE	4(PC)
   345  	NEGL	AX
   346  	MOVL	AX, ret+12(FP)
   347  	RET
   348  	MOVL	$0, AX
   349  	MOVL	AX, ret+12(FP)
   350  	RET
   351  
   352  // The thread that bsdthread_create creates starts executing here,
   353  // because we registered this function using bsdthread_register
   354  // at startup.
   355  //	AX = "pthread" (= 0x0)
   356  //	BX = mach thread port
   357  //	CX = "func" (= fn)
   358  //	DX = "arg" (= m)
   359  //	DI = stack top
   360  //	SI = flags (= 0x1000000)
   361  //	SP = stack - C_32_STK_ALIGN
   362  TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
   363  	// set up ldt 7+id to point at m->tls.
   364  	// m->tls is at m+40.  newosproc left
   365  	// the m->id in tls[0].
   366  	LEAL	m_tls(DX), BP
   367  	MOVL	0(BP), DI
   368  	ADDL	$7, DI	// m0 is LDT#7. count up.
   369  	// setldt(tls#, &tls, sizeof tls)
   370  	PUSHAL	// save registers
   371  	PUSHL	$32	// sizeof tls
   372  	PUSHL	BP	// &tls
   373  	PUSHL	DI	// tls #
   374  	CALL	runtime·setldt(SB)
   375  	POPL	AX
   376  	POPL	AX
   377  	POPL	AX
   378  	POPAL
   379  
   380  	// Now segment is established.  Initialize m, g.
   381  	get_tls(BP)
   382  	MOVL    m_g0(DX), AX
   383  	MOVL	AX, g(BP)
   384  	MOVL	DX, g_m(AX)
   385  	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
   386  	CALL	runtime·stackcheck(SB)		// smashes AX
   387  	CALL	CX	// fn()
   388  	CALL	runtime·exit1(SB)
   389  	RET
   390  
   391  // func bsdthread_register() int32
   392  // registers callbacks for threadstart (see bsdthread_create above
   393  // and wqthread and pthsize (not used).  returns 0 on success.
   394  TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
   395  	MOVL	$366, AX
   396  	// 0(SP) is where kernel expects caller PC; ignored
   397  	MOVL	$runtime·bsdthread_start(SB), 4(SP)	// threadstart
   398  	MOVL	$0, 8(SP)	// wqthread, not used by us
   399  	MOVL	$0, 12(SP)	// pthsize, not used by us
   400  	MOVL	$0, 16(SP)	// dummy_value [sic]
   401  	MOVL	$0, 20(SP)	// targetconc_ptr
   402  	MOVL	$0, 24(SP)	// dispatchqueue_offset
   403  	INT	$0x80
   404  	JAE	4(PC)
   405  	NEGL	AX
   406  	MOVL	AX, ret+0(FP)
   407  	RET
   408  	MOVL	$0, AX
   409  	MOVL	AX, ret+0(FP)
   410  	RET
   411  
   412  // Invoke Mach system call.
   413  // Assumes system call number in AX,
   414  // caller PC on stack, caller's caller PC next,
   415  // and then the system call arguments.
   416  //
   417  // Can be used for BSD too, but we don't,
   418  // because if you use this interface the BSD
   419  // system call numbers need an extra field
   420  // in the high 16 bits that seems to be the
   421  // argument count in bytes but is not always.
   422  // INT $0x80 works fine for those.
   423  TEXT runtime·sysenter(SB),NOSPLIT,$0
   424  	POPL	DX
   425  	MOVL	SP, CX
   426  	BYTE $0x0F; BYTE $0x34;  // SYSENTER
   427  	// returns to DX with SP set to CX
   428  
   429  TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
   430  	MOVL	$-31, AX
   431  	CALL	runtime·sysenter(SB)
   432  	MOVL	AX, ret+28(FP)
   433  	RET
   434  
   435  TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
   436  	MOVL	$-26, AX
   437  	CALL	runtime·sysenter(SB)
   438  	MOVL	AX, ret+0(FP)
   439  	RET
   440  
   441  TEXT runtime·mach_task_self(SB),NOSPLIT,$0
   442  	MOVL	$-28, AX
   443  	CALL	runtime·sysenter(SB)
   444  	MOVL	AX, ret+0(FP)
   445  	RET
   446  
   447  // Mach provides trap versions of the semaphore ops,
   448  // instead of requiring the use of RPC.
   449  
   450  // func mach_semaphore_wait(sema uint32) int32
   451  TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
   452  	MOVL	$-36, AX
   453  	CALL	runtime·sysenter(SB)
   454  	MOVL	AX, ret+4(FP)
   455  	RET
   456  
   457  // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
   458  TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
   459  	MOVL	$-38, AX
   460  	CALL	runtime·sysenter(SB)
   461  	MOVL	AX, ret+12(FP)
   462  	RET
   463  
   464  // func mach_semaphore_signal(sema uint32) int32
   465  TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
   466  	MOVL	$-33, AX
   467  	CALL	runtime·sysenter(SB)
   468  	MOVL	AX, ret+4(FP)
   469  	RET
   470  
   471  // func mach_semaphore_signal_all(sema uint32) int32
   472  TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
   473  	MOVL	$-34, AX
   474  	CALL	runtime·sysenter(SB)
   475  	MOVL	AX, ret+4(FP)
   476  	RET
   477  
   478  // func setldt(entry int, address int, limit int)
   479  // entry and limit are ignored.
   480  TEXT runtime·setldt(SB),NOSPLIT,$32
   481  	MOVL	address+4(FP), BX	// aka base
   482  
   483  	/*
   484  	 * When linking against the system libraries,
   485  	 * we use its pthread_create and let it set up %gs
   486  	 * for us.  When we do that, the private storage
   487  	 * we get is not at 0(GS) but at 0x468(GS).
   488  	 * 8l rewrites 0(TLS) into 0x468(GS) for us.
   489  	 * To accommodate that rewrite, we translate the
   490  	 * address and limit here so that 0x468(GS) maps to 0(address).
   491  	 *
   492  	 * See cgo/gcc_darwin_386.c:/468 for the derivation
   493  	 * of the constant.
   494  	 */
   495  	SUBL	$0x468, BX
   496  
   497  	/*
   498  	 * Must set up as USER_CTHREAD segment because
   499  	 * Darwin forces that value into %gs for signal handlers,
   500  	 * and if we don't set one up, we'll get a recursive
   501  	 * fault trying to get into the signal handler.
   502  	 * Since we have to set one up anyway, it might as
   503  	 * well be the value we want.  So don't bother with
   504  	 * i386_set_ldt.
   505  	 */
   506  	MOVL	BX, 4(SP)
   507  	MOVL	$3, AX	// thread_fast_set_cthread_self - machdep call #3
   508  	INT	$0x82	// sic: 0x82, not 0x80, for machdep call
   509  
   510  	XORL	AX, AX
   511  	MOVW	GS, AX
   512  	RET
   513  
   514  TEXT runtime·sysctl(SB),NOSPLIT,$0
   515  	MOVL	$202, AX
   516  	INT	$0x80
   517  	JAE	4(PC)
   518  	NEGL	AX
   519  	MOVL	AX, ret+24(FP)
   520  	RET
   521  	MOVL	$0, AX
   522  	MOVL	AX, ret+24(FP)
   523  	RET
   524  
   525  // func kqueue() int32
   526  TEXT runtime·kqueue(SB),NOSPLIT,$0
   527  	MOVL	$362, AX
   528  	INT	$0x80
   529  	JAE	2(PC)
   530  	NEGL	AX
   531  	MOVL	AX, ret+0(FP)
   532  	RET
   533  
   534  // func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
   535  TEXT runtime·kevent(SB),NOSPLIT,$0
   536  	MOVL	$363, AX
   537  	INT	$0x80
   538  	JAE	2(PC)
   539  	NEGL	AX
   540  	MOVL	AX, ret+24(FP)
   541  	RET
   542  
   543  // func closeonexec(fd int32)
   544  TEXT runtime·closeonexec(SB),NOSPLIT,$32
   545  	MOVL	$92, AX  // fcntl
   546  	// 0(SP) is where the caller PC would be; kernel skips it
   547  	MOVL	fd+0(FP), BX
   548  	MOVL	BX, 4(SP)  // fd
   549  	MOVL	$2, 8(SP)  // F_SETFD
   550  	MOVL	$1, 12(SP)  // FD_CLOEXEC
   551  	INT	$0x80
   552  	JAE	2(PC)
   553  	NEGL	AX
   554  	RET