Home | History | Annotate | Download | only in runtime
      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 runtimeexit(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 runtimeexit1(SB),NOSPLIT,$0
     23 	MOVL	$361, AX
     24 	INT	$0x80
     25 	JAE 2(PC)
     26 	MOVL	$0xf1, 0xf1  // crash
     27 	RET
     28 
     29 TEXT runtimeopen(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 runtimeclosefd(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 runtimeread(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 runtimewrite(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 runtimeraise(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	runtimeraiseproc(SB)
     65 
     66 TEXT runtimeraiseproc(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 runtimemmap(SB),NOSPLIT,$0
     78 	MOVL	$197, AX
     79 	INT	$0x80
     80 	MOVL	AX, ret+24(FP)
     81 	RET
     82 
     83 TEXT runtimemadvise(SB),NOSPLIT,$0
     84 	MOVL	$75, AX
     85 	INT	$0x80
     86 	// ignore failure - maybe pages are locked
     87 	RET
     88 
     89 TEXT runtimemunmap(SB),NOSPLIT,$0
     90 	MOVL	$73, AX
     91 	INT	$0x80
     92 	JAE	2(PC)
     93 	MOVL	$0xf1, 0xf1  // crash
     94 	RET
     95 
     96 TEXT runtimesetitimer(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 runtimenow(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 timenow(SB),NOSPLIT,$0
    222 	CALL	runtimenow(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 runtimenanotime(SB),NOSPLIT,$0
    232 	CALL	runtimenow(SB)
    233 	MOVL	AX, ret_lo+0(FP)
    234 	MOVL	DX, ret_hi+4(FP)
    235 	RET
    236 
    237 TEXT runtimesigprocmask(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 runtimesigaction(SB),NOSPLIT,$0
    245 	MOVL	$46, AX
    246 	INT	$0x80
    247 	JAE	2(PC)
    248 	MOVL	$0xf1, 0xf1  // crash
    249 	RET
    250 
    251 TEXT runtimesigfwd(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
    258 	ANDL	$~15, SP	// align stack: handler might be a C function
    259 	MOVL	BX, 0(SP)
    260 	MOVL	CX, 4(SP)
    261 	MOVL	DX, 8(SP)
    262 	MOVL	SI, 12(SP)	// save SI: handler might be a Go function
    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 runtimesigtramp(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	runtimesigtrampgo(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 runtimesigaltstack(SB),NOSPLIT,$0
    297 	MOVL	$53, AX
    298 	INT	$0x80
    299 	JAE	2(PC)
    300 	MOVL	$0xf1, 0xf1  // crash
    301 	RET
    302 
    303 TEXT runtimeusleep(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 runtimebsdthread_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 runtimebsdthread_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	runtimesetldt(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	runtimestackcheck(SB)		// smashes AX
    378 	CALL	CX	// fn()
    379 	CALL	runtimeexit1(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 runtimebsdthread_register(SB),NOSPLIT,$40
    386 	MOVL	$366, AX
    387 	// 0(SP) is where kernel expects caller PC; ignored
    388 	MOVL	$runtimebsdthread_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 runtimesysenter(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 runtimemach_msg_trap(SB),NOSPLIT,$0
    421 	MOVL	$-31, AX
    422 	CALL	runtimesysenter(SB)
    423 	MOVL	AX, ret+28(FP)
    424 	RET
    425 
    426 TEXT runtimemach_reply_port(SB),NOSPLIT,$0
    427 	MOVL	$-26, AX
    428 	CALL	runtimesysenter(SB)
    429 	MOVL	AX, ret+0(FP)
    430 	RET
    431 
    432 TEXT runtimemach_task_self(SB),NOSPLIT,$0
    433 	MOVL	$-28, AX
    434 	CALL	runtimesysenter(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 runtimemach_semaphore_wait(SB),NOSPLIT,$0
    443 	MOVL	$-36, AX
    444 	CALL	runtimesysenter(SB)
    445 	MOVL	AX, ret+4(FP)
    446 	RET
    447 
    448 // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
    449 TEXT runtimemach_semaphore_timedwait(SB),NOSPLIT,$0
    450 	MOVL	$-38, AX
    451 	CALL	runtimesysenter(SB)
    452 	MOVL	AX, ret+12(FP)
    453 	RET
    454 
    455 // func mach_semaphore_signal(sema uint32) int32
    456 TEXT runtimemach_semaphore_signal(SB),NOSPLIT,$0
    457 	MOVL	$-33, AX
    458 	CALL	runtimesysenter(SB)
    459 	MOVL	AX, ret+4(FP)
    460 	RET
    461 
    462 // func mach_semaphore_signal_all(sema uint32) int32
    463 TEXT runtimemach_semaphore_signal_all(SB),NOSPLIT,$0
    464 	MOVL	$-34, AX
    465 	CALL	runtimesysenter(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 runtimesetldt(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 runtimesysctl(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 runtimekqueue(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 runtimekevent(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 runtimecloseonexec(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
    546