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	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 timenow(SB),NOSPLIT,$0
    216 	CALL	runtimenow(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 runtimenanotime(SB),NOSPLIT,$0
    226 	CALL	runtimenow(SB)
    227 	MOVL	AX, ret_lo+0(FP)
    228 	MOVL	DX, ret_hi+4(FP)
    229 	RET
    230 
    231 TEXT runtimesigprocmask(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 runtimesigaction(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 runtimesigtramp(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	$runtimebadsignal(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 runtimesigaltstack(SB),NOSPLIT,$0
    304 	MOVL	$53, AX
    305 	INT	$0x80
    306 	JAE	2(PC)
    307 	MOVL	$0xf1, 0xf1  // crash
    308 	RET
    309 
    310 TEXT runtimeusleep(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 runtimebsdthread_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 runtimebsdthread_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	runtimesetldt(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	runtimestackcheck(SB)		// smashes AX
    387 	CALL	CX	// fn()
    388 	CALL	runtimeexit1(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 runtimebsdthread_register(SB),NOSPLIT,$40
    395 	MOVL	$366, AX
    396 	// 0(SP) is where kernel expects caller PC; ignored
    397 	MOVL	$runtimebsdthread_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 runtimesysenter(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 runtimemach_msg_trap(SB),NOSPLIT,$0
    430 	MOVL	$-31, AX
    431 	CALL	runtimesysenter(SB)
    432 	MOVL	AX, ret+28(FP)
    433 	RET
    434 
    435 TEXT runtimemach_reply_port(SB),NOSPLIT,$0
    436 	MOVL	$-26, AX
    437 	CALL	runtimesysenter(SB)
    438 	MOVL	AX, ret+0(FP)
    439 	RET
    440 
    441 TEXT runtimemach_task_self(SB),NOSPLIT,$0
    442 	MOVL	$-28, AX
    443 	CALL	runtimesysenter(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 runtimemach_semaphore_wait(SB),NOSPLIT,$0
    452 	MOVL	$-36, AX
    453 	CALL	runtimesysenter(SB)
    454 	MOVL	AX, ret+4(FP)
    455 	RET
    456 
    457 // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
    458 TEXT runtimemach_semaphore_timedwait(SB),NOSPLIT,$0
    459 	MOVL	$-38, AX
    460 	CALL	runtimesysenter(SB)
    461 	MOVL	AX, ret+12(FP)
    462 	RET
    463 
    464 // func mach_semaphore_signal(sema uint32) int32
    465 TEXT runtimemach_semaphore_signal(SB),NOSPLIT,$0
    466 	MOVL	$-33, AX
    467 	CALL	runtimesysenter(SB)
    468 	MOVL	AX, ret+4(FP)
    469 	RET
    470 
    471 // func mach_semaphore_signal_all(sema uint32) int32
    472 TEXT runtimemach_semaphore_signal_all(SB),NOSPLIT,$0
    473 	MOVL	$-34, AX
    474 	CALL	runtimesysenter(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 runtimesetldt(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 runtimesysctl(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 runtimekqueue(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 runtimekevent(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 runtimecloseonexec(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
    555