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 exit1<>(SB),NOSPLIT,$16-0
     23 	// __bsdthread_terminate takes 4 word-size arguments.
     24 	// Set them all to 0. (None are an exit status.)
     25 	MOVL	$0, 0(SP)
     26 	MOVL	$0, 4(SP)
     27 	MOVL	$0, 8(SP)
     28 	MOVL	$0, 12(SP)
     29 	MOVL	$361, AX
     30 	INT	$0x80
     31 	JAE 2(PC)
     32 	MOVL	$0xf1, 0xf1  // crash
     33 	RET
     34 
     35 GLOBL exitStack<>(SB),RODATA,$(4*4)
     36 DATA exitStack<>+0x00(SB)/4, $0
     37 DATA exitStack<>+0x04(SB)/4, $0
     38 DATA exitStack<>+0x08(SB)/4, $0
     39 DATA exitStack<>+0x0c(SB)/4, $0
     40 
     41 // func exitThread(wait *uint32)
     42 TEXT runtimeexitThread(SB),NOSPLIT,$0-4
     43 	MOVL	wait+0(FP), AX
     44 	// We're done using the stack.
     45 	MOVL	$0, (AX)
     46 	// __bsdthread_terminate takes 4 arguments, which it expects
     47 	// on the stack. They should all be 0, so switch over to a
     48 	// fake stack of 0s. It won't write to the stack.
     49 	MOVL	$exitStack<>(SB), SP
     50 	MOVL	$361, AX	// __bsdthread_terminate
     51 	INT	$0x80
     52 	MOVL	$0xf1, 0xf1  // crash
     53 	JMP	0(PC)
     54 
     55 TEXT runtimeopen(SB),NOSPLIT,$0
     56 	MOVL	$5, AX
     57 	INT	$0x80
     58 	JAE	2(PC)
     59 	MOVL	$-1, AX
     60 	MOVL	AX, ret+12(FP)
     61 	RET
     62 
     63 TEXT runtimeclosefd(SB),NOSPLIT,$0
     64 	MOVL	$6, AX
     65 	INT	$0x80
     66 	JAE	2(PC)
     67 	MOVL	$-1, AX
     68 	MOVL	AX, ret+4(FP)
     69 	RET
     70 
     71 TEXT runtimeread(SB),NOSPLIT,$0
     72 	MOVL	$3, AX
     73 	INT	$0x80
     74 	JAE	2(PC)
     75 	MOVL	$-1, AX
     76 	MOVL	AX, ret+12(FP)
     77 	RET
     78 
     79 TEXT runtimewrite(SB),NOSPLIT,$0
     80 	MOVL	$4, AX
     81 	INT	$0x80
     82 	JAE	2(PC)
     83 	MOVL	$-1, AX
     84 	MOVL	AX, ret+12(FP)
     85 	RET
     86 
     87 TEXT runtimeraise(SB),NOSPLIT,$0
     88 	// Ideally we'd send the signal to the current thread,
     89 	// not the whole process, but that's too hard on OS X.
     90 	JMP	runtimeraiseproc(SB)
     91 
     92 TEXT runtimeraiseproc(SB),NOSPLIT,$16
     93 	MOVL	$20, AX // getpid
     94 	INT	$0x80
     95 	MOVL	AX, 4(SP)	// pid
     96 	MOVL	sig+0(FP), AX
     97 	MOVL	AX, 8(SP)	// signal
     98 	MOVL	$1, 12(SP)	// posix
     99 	MOVL	$37, AX // kill
    100 	INT	$0x80
    101 	RET
    102 
    103 TEXT runtimemmap(SB),NOSPLIT,$0
    104 	MOVL	$197, AX
    105 	INT	$0x80
    106 	JAE	ok
    107 	MOVL	$0, p+24(FP)
    108 	MOVL	AX, err+28(FP)
    109 	RET
    110 ok:
    111 	MOVL	AX, p+24(FP)
    112 	MOVL	$0, err+28(FP)
    113 	RET
    114 
    115 TEXT runtimemadvise(SB),NOSPLIT,$0
    116 	MOVL	$75, AX
    117 	INT	$0x80
    118 	// ignore failure - maybe pages are locked
    119 	RET
    120 
    121 TEXT runtimemunmap(SB),NOSPLIT,$0
    122 	MOVL	$73, AX
    123 	INT	$0x80
    124 	JAE	2(PC)
    125 	MOVL	$0xf1, 0xf1  // crash
    126 	RET
    127 
    128 TEXT runtimesetitimer(SB),NOSPLIT,$0
    129 	MOVL	$83, AX
    130 	INT	$0x80
    131 	RET
    132 
    133 // OS X comm page time offsets
    134 // http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h
    135 #define	cpu_capabilities	0x20
    136 #define	nt_tsc_base	0x50
    137 #define	nt_scale	0x58
    138 #define	nt_shift	0x5c
    139 #define	nt_ns_base	0x60
    140 #define	nt_generation	0x68
    141 #define	gtod_generation	0x6c
    142 #define	gtod_ns_base	0x70
    143 #define	gtod_sec_base	0x78
    144 
    145 // called from assembly
    146 // 64-bit unix nanoseconds returned in DX:AX.
    147 // I'd much rather write this in C but we need
    148 // assembly for the 96-bit multiply and RDTSC.
    149 //
    150 // Note that we could arrange to return monotonic time here
    151 // as well, but we don't bother, for two reasons:
    152 // 1. macOS only supports 64-bit systems, so no one should
    153 // be using the 32-bit code in production.
    154 // This code is only maintained to make it easier for developers
    155 // using Macs to test the 32-bit compiler.
    156 // 2. On some (probably now unsupported) CPUs,
    157 // the code falls back to the system call always,
    158 // so it can't even use the comm page at all.
    159 TEXT runtimenow(SB),NOSPLIT,$40
    160 	MOVL	$0xffff0000, BP /* comm page base */
    161 
    162 	// Test for slow CPU. If so, the math is completely
    163 	// different, and unimplemented here, so use the
    164 	// system call.
    165 	MOVL	cpu_capabilities(BP), AX
    166 	TESTL	$0x4000, AX
    167 	JNZ	systime
    168 
    169 	// Loop trying to take a consistent snapshot
    170 	// of the time parameters.
    171 timeloop:
    172 	MOVL	gtod_generation(BP), BX
    173 	TESTL	BX, BX
    174 	JZ	systime
    175 	MOVL	nt_generation(BP), CX
    176 	TESTL	CX, CX
    177 	JZ	timeloop
    178 	RDTSC
    179 	MOVL	nt_tsc_base(BP), SI
    180 	MOVL	(nt_tsc_base+4)(BP), DI
    181 	MOVL	SI, 0(SP)
    182 	MOVL	DI, 4(SP)
    183 	MOVL	nt_scale(BP), SI
    184 	MOVL	SI, 8(SP)
    185 	MOVL	nt_ns_base(BP), SI
    186 	MOVL	(nt_ns_base+4)(BP), DI
    187 	MOVL	SI, 12(SP)
    188 	MOVL	DI, 16(SP)
    189 	CMPL	nt_generation(BP), CX
    190 	JNE	timeloop
    191 	MOVL	gtod_ns_base(BP), SI
    192 	MOVL	(gtod_ns_base+4)(BP), DI
    193 	MOVL	SI, 20(SP)
    194 	MOVL	DI, 24(SP)
    195 	MOVL	gtod_sec_base(BP), SI
    196 	MOVL	(gtod_sec_base+4)(BP), DI
    197 	MOVL	SI, 28(SP)
    198 	MOVL	DI, 32(SP)
    199 	CMPL	gtod_generation(BP), BX
    200 	JNE	timeloop
    201 
    202 	// Gathered all the data we need. Compute time.
    203 	//	((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9
    204 	// The multiply and shift extracts the top 64 bits of the 96-bit product.
    205 	SUBL	0(SP), AX // DX:AX = (tsc - nt_tsc_base)
    206 	SBBL	4(SP), DX
    207 
    208 	// We have x = tsc - nt_tsc_base - DX:AX to be
    209 	// multiplied by y = nt_scale = 8(SP), keeping the top 64 bits of the 96-bit product.
    210 	// x*y = (x&0xffffffff)*y + (x&0xffffffff00000000)*y
    211 	// (x*y)>>32 = ((x&0xffffffff)*y)>>32 + (x>>32)*y
    212 	MOVL	DX, CX // SI = (x&0xffffffff)*y >> 32
    213 	MOVL	$0, DX
    214 	MULL	8(SP)
    215 	MOVL	DX, SI
    216 
    217 	MOVL	CX, AX // DX:AX = (x>>32)*y
    218 	MOVL	$0, DX
    219 	MULL	8(SP)
    220 
    221 	ADDL	SI, AX	// DX:AX += (x&0xffffffff)*y >> 32
    222 	ADCL	$0, DX
    223 
    224 	// DX:AX is now ((tsc - nt_tsc_base) * nt_scale) >> 32.
    225 	ADDL	12(SP), AX	// DX:AX += nt_ns_base
    226 	ADCL	16(SP), DX
    227 	SUBL	20(SP), AX	// DX:AX -= gtod_ns_base
    228 	SBBL	24(SP), DX
    229 	MOVL	AX, SI	// DI:SI = DX:AX
    230 	MOVL	DX, DI
    231 	MOVL	28(SP), AX	// DX:AX = gtod_sec_base*1e9
    232 	MOVL	32(SP), DX
    233 	MOVL	$1000000000, CX
    234 	MULL	CX
    235 	ADDL	SI, AX	// DX:AX += DI:SI
    236 	ADCL	DI, DX
    237 	RET
    238 
    239 systime:
    240 	// Fall back to system call (usually first call in this thread)
    241 	LEAL	16(SP), AX	// must be non-nil, unused
    242 	MOVL	AX, 4(SP)
    243 	MOVL	$0, 8(SP)	// time zone pointer
    244 	MOVL	$0, 12(SP)	// required as of Sierra; Issue 16570
    245 	MOVL	$116, AX // SYS_GETTIMEOFDAY
    246 	INT	$0x80
    247 	CMPL	AX, $0
    248 	JNE	inreg
    249 	MOVL	16(SP), AX
    250 	MOVL	20(SP), DX
    251 inreg:
    252 	// sec is in AX, usec in DX
    253 	// convert to DX:AX nsec
    254 	MOVL	DX, BX
    255 	MOVL	$1000000000, CX
    256 	MULL	CX
    257 	IMULL	$1000, BX
    258 	ADDL	BX, AX
    259 	ADCL	$0, DX
    260 	RET
    261 
    262 // func now() (sec int64, nsec int32, mono uint64)
    263 TEXT timenow(SB),NOSPLIT,$0-20
    264 	CALL	runtimenow(SB)
    265 	MOVL	AX, BX
    266 	MOVL	DX, BP
    267 	SUBL	runtimestartNano(SB), BX
    268 	SBBL	runtimestartNano+4(SB), BP
    269 	MOVL	BX, mono+12(FP)
    270 	MOVL	BP, mono+16(FP)
    271 	MOVL	$1000000000, CX
    272 	DIVL	CX
    273 	MOVL	AX, sec+0(FP)
    274 	MOVL	$0, sec+4(FP)
    275 	MOVL	DX, nsec+8(FP)
    276 	RET
    277 
    278 // func nanotime() int64
    279 TEXT runtimenanotime(SB),NOSPLIT,$0
    280 	CALL	runtimenow(SB)
    281 	SUBL	runtimestartNano(SB), AX
    282 	SBBL	runtimestartNano+4(SB), DX
    283 	MOVL	AX, ret_lo+0(FP)
    284 	MOVL	DX, ret_hi+4(FP)
    285 	RET
    286 
    287 TEXT runtimesigprocmask(SB),NOSPLIT,$0
    288 	MOVL	$329, AX  // pthread_sigmask (on OS X, sigprocmask==entire process)
    289 	INT	$0x80
    290 	JAE	2(PC)
    291 	MOVL	$0xf1, 0xf1  // crash
    292 	RET
    293 
    294 TEXT runtimesigaction(SB),NOSPLIT,$0
    295 	MOVL	$46, AX
    296 	INT	$0x80
    297 	JAE	2(PC)
    298 	MOVL	$0xf1, 0xf1  // crash
    299 	RET
    300 
    301 TEXT runtimesigfwd(SB),NOSPLIT,$0-16
    302 	MOVL	fn+0(FP), AX
    303 	MOVL	sig+4(FP), BX
    304 	MOVL	info+8(FP), CX
    305 	MOVL	ctx+12(FP), DX
    306 	MOVL	SP, SI
    307 	SUBL	$32, SP
    308 	ANDL	$~15, SP	// align stack: handler might be a C function
    309 	MOVL	BX, 0(SP)
    310 	MOVL	CX, 4(SP)
    311 	MOVL	DX, 8(SP)
    312 	MOVL	SI, 12(SP)	// save SI: handler might be a Go function
    313 	CALL	AX
    314 	MOVL	12(SP), AX
    315 	MOVL	AX, SP
    316 	RET
    317 
    318 // Sigtramp's job is to call the actual signal handler.
    319 // It is called with the following arguments on the stack:
    320 //	0(SP)	"return address" - ignored
    321 //	4(SP)	actual handler
    322 //	8(SP)	siginfo style
    323 //	12(SP)	signal number
    324 //	16(SP)	siginfo
    325 //	20(SP)	context
    326 TEXT runtimesigtramp(SB),NOSPLIT,$20
    327 	MOVL	sig+8(FP), BX
    328 	MOVL	BX, 0(SP)
    329 	MOVL	info+12(FP), BX
    330 	MOVL	BX, 4(SP)
    331 	MOVL	ctx+16(FP), BX
    332 	MOVL	BX, 8(SP)
    333 	CALL	runtimesigtrampgo(SB)
    334 
    335 	// call sigreturn
    336 	MOVL	ctx+16(FP), CX
    337 	MOVL	infostyle+4(FP), BX
    338 	MOVL	$0, 0(SP)	// "caller PC" - ignored
    339 	MOVL	CX, 4(SP)
    340 	MOVL	BX, 8(SP)
    341 	MOVL	$184, AX	// sigreturn(ucontext, infostyle)
    342 	INT	$0x80
    343 	MOVL	$0xf1, 0xf1  // crash
    344 	RET
    345 
    346 TEXT runtimesigaltstack(SB),NOSPLIT,$0
    347 	MOVL	$53, AX
    348 	INT	$0x80
    349 	JAE	2(PC)
    350 	MOVL	$0xf1, 0xf1  // crash
    351 	RET
    352 
    353 TEXT runtimeusleep(SB),NOSPLIT,$32
    354 	MOVL	$0, DX
    355 	MOVL	usec+0(FP), AX
    356 	MOVL	$1000000, CX
    357 	DIVL	CX
    358 	MOVL	AX, 24(SP)  // sec
    359 	MOVL	DX, 28(SP)  // usec
    360 
    361 	// select(0, 0, 0, 0, &tv)
    362 	MOVL	$0, 0(SP)  // "return PC" - ignored
    363 	MOVL	$0, 4(SP)
    364 	MOVL	$0, 8(SP)
    365 	MOVL	$0, 12(SP)
    366 	MOVL	$0, 16(SP)
    367 	LEAL	24(SP), AX
    368 	MOVL	AX, 20(SP)
    369 	MOVL	$93, AX
    370 	INT	$0x80
    371 	RET
    372 
    373 // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
    374 // System call args are: func arg stack pthread flags.
    375 TEXT runtimebsdthread_create(SB),NOSPLIT,$32
    376 	MOVL	$360, AX
    377 	// 0(SP) is where the caller PC would be; kernel skips it
    378 	MOVL	fn+8(FP), BX
    379 	MOVL	BX, 4(SP)	// func
    380 	MOVL	arg+4(FP), BX
    381 	MOVL	BX, 8(SP)	// arg
    382 	MOVL	stk+0(FP), BX
    383 	MOVL	BX, 12(SP)	// stack
    384 	MOVL    $0, 16(SP)      // pthread
    385 	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
    386 	INT	$0x80
    387 	JAE	4(PC)
    388 	NEGL	AX
    389 	MOVL	AX, ret+12(FP)
    390 	RET
    391 	MOVL	$0, AX
    392 	MOVL	AX, ret+12(FP)
    393 	RET
    394 
    395 // The thread that bsdthread_create creates starts executing here,
    396 // because we registered this function using bsdthread_register
    397 // at startup.
    398 //	AX = "pthread" (= 0x0)
    399 //	BX = mach thread port
    400 //	CX = "func" (= fn)
    401 //	DX = "arg" (= m)
    402 //	DI = stack top
    403 //	SI = flags (= 0x1000000)
    404 //	SP = stack - C_32_STK_ALIGN
    405 TEXT runtimebsdthread_start(SB),NOSPLIT,$0
    406 	// set up ldt 7+id to point at m->tls.
    407 	LEAL	m_tls(DX), BP
    408 	MOVL	m_id(DX), DI
    409 	ADDL	$7, DI	// m0 is LDT#7. count up.
    410 	// setldt(tls#, &tls, sizeof tls)
    411 	PUSHAL	// save registers
    412 	PUSHL	$32	// sizeof tls
    413 	PUSHL	BP	// &tls
    414 	PUSHL	DI	// tls #
    415 	CALL	runtimesetldt(SB)
    416 	POPL	AX
    417 	POPL	AX
    418 	POPL	AX
    419 	POPAL
    420 
    421 	// Now segment is established. Initialize m, g.
    422 	get_tls(BP)
    423 	MOVL    m_g0(DX), AX
    424 	MOVL	AX, g(BP)
    425 	MOVL	DX, g_m(AX)
    426 	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
    427 	CALL	runtimestackcheck(SB)		// smashes AX
    428 	CALL	CX	// fn()
    429 	CALL	exit1<>(SB)
    430 	RET
    431 
    432 // func bsdthread_register() int32
    433 // registers callbacks for threadstart (see bsdthread_create above
    434 // and wqthread and pthsize (not used).  returns 0 on success.
    435 TEXT runtimebsdthread_register(SB),NOSPLIT,$40
    436 	MOVL	$366, AX
    437 	// 0(SP) is where kernel expects caller PC; ignored
    438 	MOVL	$runtimebsdthread_start(SB), 4(SP)	// threadstart
    439 	MOVL	$0, 8(SP)	// wqthread, not used by us
    440 	MOVL	$0, 12(SP)	// pthsize, not used by us
    441 	MOVL	$0, 16(SP)	// dummy_value [sic]
    442 	MOVL	$0, 20(SP)	// targetconc_ptr
    443 	MOVL	$0, 24(SP)	// dispatchqueue_offset
    444 	INT	$0x80
    445 	JAE	4(PC)
    446 	NEGL	AX
    447 	MOVL	AX, ret+0(FP)
    448 	RET
    449 	MOVL	$0, AX
    450 	MOVL	AX, ret+0(FP)
    451 	RET
    452 
    453 // Invoke Mach system call.
    454 // Assumes system call number in AX,
    455 // caller PC on stack, caller's caller PC next,
    456 // and then the system call arguments.
    457 //
    458 // Can be used for BSD too, but we don't,
    459 // because if you use this interface the BSD
    460 // system call numbers need an extra field
    461 // in the high 16 bits that seems to be the
    462 // argument count in bytes but is not always.
    463 // INT $0x80 works fine for those.
    464 TEXT runtimesysenter(SB),NOSPLIT,$0
    465 	POPL	DX
    466 	MOVL	SP, CX
    467 	BYTE $0x0F; BYTE $0x34;  // SYSENTER
    468 	// returns to DX with SP set to CX
    469 
    470 TEXT runtimemach_msg_trap(SB),NOSPLIT,$0
    471 	MOVL	$-31, AX
    472 	CALL	runtimesysenter(SB)
    473 	MOVL	AX, ret+28(FP)
    474 	RET
    475 
    476 TEXT runtimemach_reply_port(SB),NOSPLIT,$0
    477 	MOVL	$-26, AX
    478 	CALL	runtimesysenter(SB)
    479 	MOVL	AX, ret+0(FP)
    480 	RET
    481 
    482 TEXT runtimemach_task_self(SB),NOSPLIT,$0
    483 	MOVL	$-28, AX
    484 	CALL	runtimesysenter(SB)
    485 	MOVL	AX, ret+0(FP)
    486 	RET
    487 
    488 // Mach provides trap versions of the semaphore ops,
    489 // instead of requiring the use of RPC.
    490 
    491 // func mach_semaphore_wait(sema uint32) int32
    492 TEXT runtimemach_semaphore_wait(SB),NOSPLIT,$0
    493 	MOVL	$-36, AX
    494 	CALL	runtimesysenter(SB)
    495 	MOVL	AX, ret+4(FP)
    496 	RET
    497 
    498 // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
    499 TEXT runtimemach_semaphore_timedwait(SB),NOSPLIT,$0
    500 	MOVL	$-38, AX
    501 	CALL	runtimesysenter(SB)
    502 	MOVL	AX, ret+12(FP)
    503 	RET
    504 
    505 // func mach_semaphore_signal(sema uint32) int32
    506 TEXT runtimemach_semaphore_signal(SB),NOSPLIT,$0
    507 	MOVL	$-33, AX
    508 	CALL	runtimesysenter(SB)
    509 	MOVL	AX, ret+4(FP)
    510 	RET
    511 
    512 // func mach_semaphore_signal_all(sema uint32) int32
    513 TEXT runtimemach_semaphore_signal_all(SB),NOSPLIT,$0
    514 	MOVL	$-34, AX
    515 	CALL	runtimesysenter(SB)
    516 	MOVL	AX, ret+4(FP)
    517 	RET
    518 
    519 // func setldt(entry int, address int, limit int)
    520 // entry and limit are ignored.
    521 TEXT runtimesetldt(SB),NOSPLIT,$32
    522 	MOVL	address+4(FP), BX	// aka base
    523 
    524 	/*
    525 	 * When linking against the system libraries,
    526 	 * we use its pthread_create and let it set up %gs
    527 	 * for us.  When we do that, the private storage
    528 	 * we get is not at 0(GS) but at 0x468(GS).
    529 	 * 8l rewrites 0(TLS) into 0x468(GS) for us.
    530 	 * To accommodate that rewrite, we translate the
    531 	 * address and limit here so that 0x468(GS) maps to 0(address).
    532 	 *
    533 	 * See cgo/gcc_darwin_386.c:/468 for the derivation
    534 	 * of the constant.
    535 	 */
    536 	SUBL	$0x468, BX
    537 
    538 	/*
    539 	 * Must set up as USER_CTHREAD segment because
    540 	 * Darwin forces that value into %gs for signal handlers,
    541 	 * and if we don't set one up, we'll get a recursive
    542 	 * fault trying to get into the signal handler.
    543 	 * Since we have to set one up anyway, it might as
    544 	 * well be the value we want.  So don't bother with
    545 	 * i386_set_ldt.
    546 	 */
    547 	MOVL	BX, 4(SP)
    548 	MOVL	$3, AX	// thread_fast_set_cthread_self - machdep call #3
    549 	INT	$0x82	// sic: 0x82, not 0x80, for machdep call
    550 
    551 	XORL	AX, AX
    552 	MOVW	GS, AX
    553 	RET
    554 
    555 TEXT runtimesysctl(SB),NOSPLIT,$0
    556 	MOVL	$202, AX
    557 	INT	$0x80
    558 	JAE	4(PC)
    559 	NEGL	AX
    560 	MOVL	AX, ret+24(FP)
    561 	RET
    562 	MOVL	$0, AX
    563 	MOVL	AX, ret+24(FP)
    564 	RET
    565 
    566 // func kqueue() int32
    567 TEXT runtimekqueue(SB),NOSPLIT,$0
    568 	MOVL	$362, AX
    569 	INT	$0x80
    570 	JAE	2(PC)
    571 	NEGL	AX
    572 	MOVL	AX, ret+0(FP)
    573 	RET
    574 
    575 // func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    576 TEXT runtimekevent(SB),NOSPLIT,$0
    577 	MOVL	$363, AX
    578 	INT	$0x80
    579 	JAE	2(PC)
    580 	NEGL	AX
    581 	MOVL	AX, ret+24(FP)
    582 	RET
    583 
    584 // func closeonexec(fd int32)
    585 TEXT runtimecloseonexec(SB),NOSPLIT,$32
    586 	MOVL	$92, AX  // fcntl
    587 	// 0(SP) is where the caller PC would be; kernel skips it
    588 	MOVL	fd+0(FP), BX
    589 	MOVL	BX, 4(SP)  // fd
    590 	MOVL	$2, 8(SP)  // F_SETFD
    591 	MOVL	$1, 12(SP)  // FD_CLOEXEC
    592 	INT	$0x80
    593 	JAE	2(PC)
    594 	NEGL	AX
    595 	RET
    596