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