github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/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 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 runtime·exitThread(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 runtime·open(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 runtime·closefd(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 runtime·read(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 runtime·write(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 runtime·raise(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 runtime·raiseproc(SB) 91 92 TEXT runtime·raiseproc(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 runtime·mmap(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 runtime·madvise(SB),NOSPLIT,$0 116 MOVL $75, AX 117 INT $0x80 118 // ignore failure - maybe pages are locked 119 RET 120 121 TEXT runtime·munmap(SB),NOSPLIT,$0 122 MOVL $73, AX 123 INT $0x80 124 JAE 2(PC) 125 MOVL $0xf1, 0xf1 // crash 126 RET 127 128 TEXT runtime·setitimer(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 runtime·now(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 time·now(SB),NOSPLIT,$0-20 264 CALL runtime·now(SB) 265 MOVL AX, BX 266 MOVL DX, BP 267 SUBL runtime·startNano(SB), BX 268 SBBL runtime·startNano+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 runtime·nanotime(SB),NOSPLIT,$0 280 CALL runtime·now(SB) 281 SUBL runtime·startNano(SB), AX 282 SBBL runtime·startNano+4(SB), DX 283 MOVL AX, ret_lo+0(FP) 284 MOVL DX, ret_hi+4(FP) 285 RET 286 287 TEXT runtime·sigprocmask(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 runtime·sigaction(SB),NOSPLIT,$0 295 MOVL $46, AX 296 INT $0x80 297 JAE 2(PC) 298 MOVL $0xf1, 0xf1 // crash 299 RET 300 301 TEXT runtime·sigfwd(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 runtime·sigtramp(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 runtime·sigtrampgo(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 runtime·sigaltstack(SB),NOSPLIT,$0 347 MOVL $53, AX 348 INT $0x80 349 JAE 2(PC) 350 MOVL $0xf1, 0xf1 // crash 351 RET 352 353 TEXT runtime·usleep(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 runtime·bsdthread_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 runtime·bsdthread_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 runtime·setldt(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 runtime·stackcheck(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 runtime·bsdthread_register(SB),NOSPLIT,$40 436 MOVL $366, AX 437 // 0(SP) is where kernel expects caller PC; ignored 438 MOVL $runtime·bsdthread_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 runtime·sysenter(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 runtime·mach_msg_trap(SB),NOSPLIT,$0 471 MOVL $-31, AX 472 CALL runtime·sysenter(SB) 473 MOVL AX, ret+28(FP) 474 RET 475 476 TEXT runtime·mach_reply_port(SB),NOSPLIT,$0 477 MOVL $-26, AX 478 CALL runtime·sysenter(SB) 479 MOVL AX, ret+0(FP) 480 RET 481 482 TEXT runtime·mach_task_self(SB),NOSPLIT,$0 483 MOVL $-28, AX 484 CALL runtime·sysenter(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 runtime·mach_semaphore_wait(SB),NOSPLIT,$0 493 MOVL $-36, AX 494 CALL runtime·sysenter(SB) 495 MOVL AX, ret+4(FP) 496 RET 497 498 // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 499 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0 500 MOVL $-38, AX 501 CALL runtime·sysenter(SB) 502 MOVL AX, ret+12(FP) 503 RET 504 505 // func mach_semaphore_signal(sema uint32) int32 506 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0 507 MOVL $-33, AX 508 CALL runtime·sysenter(SB) 509 MOVL AX, ret+4(FP) 510 RET 511 512 // func mach_semaphore_signal_all(sema uint32) int32 513 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 514 MOVL $-34, AX 515 CALL runtime·sysenter(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 runtime·setldt(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 runtime·sysctl(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 runtime·kqueue(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 runtime·kevent(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 runtime·closeonexec(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