github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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  TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
   246  	MOVL	fn+0(FP), AX
   247  	MOVL	sig+4(FP), BX
   248  	MOVL	info+8(FP), CX
   249  	MOVL	ctx+12(FP), DX
   250  	MOVL	SP, SI
   251  	SUBL	$32, SP		// align stack; handler might be C code
   252  	ANDL	$~15, SP
   253  	MOVL	BX, 0(SP)
   254  	MOVL	CX, 4(SP)
   255  	MOVL	DX, 8(SP)
   256  	MOVL	SI, 12(SP)
   257  	CALL	AX
   258  	MOVL	12(SP), AX
   259  	MOVL	AX, SP
   260  	RET
   261  
   262  TEXT runtime·sigreturn(SB),NOSPLIT,$12-8
   263  	MOVL	ctx+0(FP), CX
   264  	MOVL	infostyle+4(FP), BX
   265  	MOVL	$0, 0(SP)	// "caller PC" - ignored
   266  	MOVL	CX, 4(SP)
   267  	MOVL	BX, 8(SP)
   268  	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
   269  	INT	$0x80
   270  	MOVL	$0xf1, 0xf1  // crash
   271  	RET
   272  
   273  // Sigtramp's job is to call the actual signal handler.
   274  // It is called with the following arguments on the stack:
   275  //	0(SP)	"return address" - ignored
   276  //	4(SP)	actual handler
   277  //	8(SP)	signal number
   278  //	12(SP)	siginfo style
   279  //	16(SP)	siginfo
   280  //	20(SP)	context
   281  TEXT runtime·sigtramp(SB),NOSPLIT,$20
   282  	MOVL	fn+0(FP), BX
   283  	MOVL	BX, 0(SP)
   284  	MOVL	style+4(FP), BX
   285  	MOVL	BX, 4(SP)
   286  	MOVL	sig+8(FP), BX
   287  	MOVL	BX, 8(SP)
   288  	MOVL	info+12(FP), BX
   289  	MOVL	BX, 12(SP)
   290  	MOVL	context+16(FP), BX
   291  	MOVL	BX, 16(SP)
   292  	CALL	runtime·sigtrampgo(SB)
   293  
   294  	// call sigreturn
   295  	MOVL	context+16(FP), CX
   296  	MOVL	style+4(FP), BX
   297  	MOVL	$0, 0(SP)	// "caller PC" - ignored
   298  	MOVL	CX, 4(SP)
   299  	MOVL	BX, 8(SP)
   300  	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
   301  	INT	$0x80
   302  	MOVL	$0xf1, 0xf1  // crash
   303  	RET
   304  
   305  TEXT runtime·sigaltstack(SB),NOSPLIT,$0
   306  	MOVL	$53, AX
   307  	INT	$0x80
   308  	JAE	2(PC)
   309  	MOVL	$0xf1, 0xf1  // crash
   310  	RET
   311  
   312  TEXT runtime·usleep(SB),NOSPLIT,$32
   313  	MOVL	$0, DX
   314  	MOVL	usec+0(FP), AX
   315  	MOVL	$1000000, CX
   316  	DIVL	CX
   317  	MOVL	AX, 24(SP)  // sec
   318  	MOVL	DX, 28(SP)  // usec
   319  
   320  	// select(0, 0, 0, 0, &tv)
   321  	MOVL	$0, 0(SP)  // "return PC" - ignored
   322  	MOVL	$0, 4(SP)
   323  	MOVL	$0, 8(SP)
   324  	MOVL	$0, 12(SP)
   325  	MOVL	$0, 16(SP)
   326  	LEAL	24(SP), AX
   327  	MOVL	AX, 20(SP)
   328  	MOVL	$93, AX
   329  	INT	$0x80
   330  	RET
   331  
   332  // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
   333  // System call args are: func arg stack pthread flags.
   334  TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
   335  	MOVL	$360, AX
   336  	// 0(SP) is where the caller PC would be; kernel skips it
   337  	MOVL	fn+8(FP), BX
   338  	MOVL	BX, 4(SP)	// func
   339  	MOVL	arg+4(FP), BX
   340  	MOVL	BX, 8(SP)	// arg
   341  	MOVL	stk+0(FP), BX
   342  	MOVL	BX, 12(SP)	// stack
   343  	MOVL    $0, 16(SP)      // pthread
   344  	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
   345  	INT	$0x80
   346  	JAE	4(PC)
   347  	NEGL	AX
   348  	MOVL	AX, ret+12(FP)
   349  	RET
   350  	MOVL	$0, AX
   351  	MOVL	AX, ret+12(FP)
   352  	RET
   353  
   354  // The thread that bsdthread_create creates starts executing here,
   355  // because we registered this function using bsdthread_register
   356  // at startup.
   357  //	AX = "pthread" (= 0x0)
   358  //	BX = mach thread port
   359  //	CX = "func" (= fn)
   360  //	DX = "arg" (= m)
   361  //	DI = stack top
   362  //	SI = flags (= 0x1000000)
   363  //	SP = stack - C_32_STK_ALIGN
   364  TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
   365  	// set up ldt 7+id to point at m->tls.
   366  	LEAL	m_tls(DX), BP
   367  	MOVL	m_id(DX), 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