github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/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 MOVL AX, ret+12(FP) 33 RET 34 35 TEXT runtime·close(SB),NOSPLIT,$0 36 MOVL $6, AX 37 INT $0x80 38 MOVL AX, ret+4(FP) 39 RET 40 41 TEXT runtime·read(SB),NOSPLIT,$0 42 MOVL $3, AX 43 INT $0x80 44 MOVL AX, ret+12(FP) 45 RET 46 47 TEXT runtime·write(SB),NOSPLIT,$0 48 MOVL $4, AX 49 INT $0x80 50 MOVL AX, ret+12(FP) 51 RET 52 53 TEXT runtime·raise(SB),NOSPLIT,$16 54 MOVL $20, AX // getpid 55 INT $0x80 56 MOVL AX, 4(SP) // pid 57 MOVL sig+0(FP), AX 58 MOVL AX, 8(SP) // signal 59 MOVL $1, 12(SP) // posix 60 MOVL $37, AX // kill 61 INT $0x80 62 RET 63 64 TEXT runtime·mmap(SB),NOSPLIT,$0 65 MOVL $197, AX 66 INT $0x80 67 MOVL AX, ret+24(FP) 68 RET 69 70 TEXT runtime·madvise(SB),NOSPLIT,$0 71 MOVL $75, AX 72 INT $0x80 73 // ignore failure - maybe pages are locked 74 RET 75 76 TEXT runtime·munmap(SB),NOSPLIT,$0 77 MOVL $73, AX 78 INT $0x80 79 JAE 2(PC) 80 MOVL $0xf1, 0xf1 // crash 81 RET 82 83 TEXT runtime·setitimer(SB),NOSPLIT,$0 84 MOVL $83, AX 85 INT $0x80 86 RET 87 88 // OS X comm page time offsets 89 // http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/i386/cpu_capabilities.h 90 #define cpu_capabilities 0x20 91 #define nt_tsc_base 0x50 92 #define nt_scale 0x58 93 #define nt_shift 0x5c 94 #define nt_ns_base 0x60 95 #define nt_generation 0x68 96 #define gtod_generation 0x6c 97 #define gtod_ns_base 0x70 98 #define gtod_sec_base 0x78 99 100 // called from assembly 101 // 64-bit unix nanoseconds returned in DX:AX. 102 // I'd much rather write this in C but we need 103 // assembly for the 96-bit multiply and RDTSC. 104 TEXT runtime·now(SB),NOSPLIT,$40 105 MOVL $0xffff0000, BP /* comm page base */ 106 107 // Test for slow CPU. If so, the math is completely 108 // different, and unimplemented here, so use the 109 // system call. 110 MOVL cpu_capabilities(BP), AX 111 TESTL $0x4000, AX 112 JNZ systime 113 114 // Loop trying to take a consistent snapshot 115 // of the time parameters. 116 timeloop: 117 MOVL gtod_generation(BP), BX 118 TESTL BX, BX 119 JZ systime 120 MOVL nt_generation(BP), CX 121 TESTL CX, CX 122 JZ timeloop 123 RDTSC 124 MOVL nt_tsc_base(BP), SI 125 MOVL (nt_tsc_base+4)(BP), DI 126 MOVL SI, 0(SP) 127 MOVL DI, 4(SP) 128 MOVL nt_scale(BP), SI 129 MOVL SI, 8(SP) 130 MOVL nt_ns_base(BP), SI 131 MOVL (nt_ns_base+4)(BP), DI 132 MOVL SI, 12(SP) 133 MOVL DI, 16(SP) 134 CMPL nt_generation(BP), CX 135 JNE timeloop 136 MOVL gtod_ns_base(BP), SI 137 MOVL (gtod_ns_base+4)(BP), DI 138 MOVL SI, 20(SP) 139 MOVL DI, 24(SP) 140 MOVL gtod_sec_base(BP), SI 141 MOVL (gtod_sec_base+4)(BP), DI 142 MOVL SI, 28(SP) 143 MOVL DI, 32(SP) 144 CMPL gtod_generation(BP), BX 145 JNE timeloop 146 147 // Gathered all the data we need. Compute time. 148 // ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9 149 // The multiply and shift extracts the top 64 bits of the 96-bit product. 150 SUBL 0(SP), AX // DX:AX = (tsc - nt_tsc_base) 151 SBBL 4(SP), DX 152 153 // We have x = tsc - nt_tsc_base - DX:AX to be 154 // multiplied by y = nt_scale = 8(SP), keeping the top 64 bits of the 96-bit product. 155 // x*y = (x&0xffffffff)*y + (x&0xffffffff00000000)*y 156 // (x*y)>>32 = ((x&0xffffffff)*y)>>32 + (x>>32)*y 157 MOVL DX, CX // SI = (x&0xffffffff)*y >> 32 158 MOVL $0, DX 159 MULL 8(SP) 160 MOVL DX, SI 161 162 MOVL CX, AX // DX:AX = (x>>32)*y 163 MOVL $0, DX 164 MULL 8(SP) 165 166 ADDL SI, AX // DX:AX += (x&0xffffffff)*y >> 32 167 ADCL $0, DX 168 169 // DX:AX is now ((tsc - nt_tsc_base) * nt_scale) >> 32. 170 ADDL 12(SP), AX // DX:AX += nt_ns_base 171 ADCL 16(SP), DX 172 SUBL 20(SP), AX // DX:AX -= gtod_ns_base 173 SBBL 24(SP), DX 174 MOVL AX, SI // DI:SI = DX:AX 175 MOVL DX, DI 176 MOVL 28(SP), AX // DX:AX = gtod_sec_base*1e9 177 MOVL 32(SP), DX 178 MOVL $1000000000, CX 179 MULL CX 180 ADDL SI, AX // DX:AX += DI:SI 181 ADCL DI, DX 182 RET 183 184 systime: 185 // Fall back to system call (usually first call in this thread) 186 LEAL 12(SP), AX // must be non-nil, unused 187 MOVL AX, 4(SP) 188 MOVL $0, 8(SP) // time zone pointer 189 MOVL $116, AX 190 INT $0x80 191 // sec is in AX, usec in DX 192 // convert to DX:AX nsec 193 MOVL DX, BX 194 MOVL $1000000000, CX 195 MULL CX 196 IMULL $1000, BX 197 ADDL BX, AX 198 ADCL $0, DX 199 RET 200 201 // func now() (sec int64, nsec int32) 202 TEXT time·now(SB),NOSPLIT,$0 203 CALL runtime·now(SB) 204 MOVL $1000000000, CX 205 DIVL CX 206 MOVL AX, sec+0(FP) 207 MOVL $0, sec+4(FP) 208 MOVL DX, nsec+8(FP) 209 RET 210 211 // int64 nanotime(void) so really 212 // void nanotime(int64 *nsec) 213 TEXT runtime·nanotime(SB),NOSPLIT,$0 214 CALL runtime·now(SB) 215 MOVL AX, ret_lo+0(FP) 216 MOVL DX, ret_hi+4(FP) 217 RET 218 219 TEXT runtime·sigprocmask(SB),NOSPLIT,$0 220 MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process) 221 INT $0x80 222 JAE 2(PC) 223 MOVL $0xf1, 0xf1 // crash 224 RET 225 226 TEXT runtime·sigaction(SB),NOSPLIT,$0 227 MOVL $46, AX 228 INT $0x80 229 JAE 2(PC) 230 MOVL $0xf1, 0xf1 // crash 231 RET 232 233 // Sigtramp's job is to call the actual signal handler. 234 // It is called with the following arguments on the stack: 235 // 0(FP) "return address" - ignored 236 // 4(FP) actual handler 237 // 8(FP) signal number 238 // 12(FP) siginfo style 239 // 16(FP) siginfo 240 // 20(FP) context 241 TEXT runtime·sigtramp(SB),NOSPLIT,$40 242 get_tls(CX) 243 244 // check that g exists 245 MOVL g(CX), DI 246 CMPL DI, $0 247 JNE 6(PC) 248 MOVL sig+8(FP), BX 249 MOVL BX, 0(SP) 250 MOVL $runtime·badsignal(SB), AX 251 CALL AX 252 JMP ret 253 254 // save g 255 MOVL DI, 20(SP) 256 257 // g = m->gsignal 258 MOVL g_m(DI), BP 259 MOVL m_gsignal(BP), BP 260 MOVL BP, g(CX) 261 262 // copy arguments to sighandler 263 MOVL sig+8(FP), BX 264 MOVL BX, 0(SP) 265 MOVL info+12(FP), BX 266 MOVL BX, 4(SP) 267 MOVL context+16(FP), BX 268 MOVL BX, 8(SP) 269 MOVL DI, 12(SP) 270 271 MOVL handler+0(FP), BX 272 CALL BX 273 274 // restore g 275 get_tls(CX) 276 MOVL 20(SP), DI 277 MOVL DI, g(CX) 278 279 ret: 280 // call sigreturn 281 MOVL context+16(FP), CX 282 MOVL style+4(FP), BX 283 MOVL $0, 0(SP) // "caller PC" - ignored 284 MOVL CX, 4(SP) 285 MOVL BX, 8(SP) 286 MOVL $184, AX // sigreturn(ucontext, infostyle) 287 INT $0x80 288 MOVL $0xf1, 0xf1 // crash 289 RET 290 291 TEXT runtime·sigaltstack(SB),NOSPLIT,$0 292 MOVL $53, AX 293 INT $0x80 294 JAE 2(PC) 295 MOVL $0xf1, 0xf1 // crash 296 RET 297 298 TEXT runtime·usleep(SB),NOSPLIT,$32 299 MOVL $0, DX 300 MOVL usec+0(FP), AX 301 MOVL $1000000, CX 302 DIVL CX 303 MOVL AX, 24(SP) // sec 304 MOVL DX, 28(SP) // usec 305 306 // select(0, 0, 0, 0, &tv) 307 MOVL $0, 0(SP) // "return PC" - ignored 308 MOVL $0, 4(SP) 309 MOVL $0, 8(SP) 310 MOVL $0, 12(SP) 311 MOVL $0, 16(SP) 312 LEAL 24(SP), AX 313 MOVL AX, 20(SP) 314 MOVL $93, AX 315 INT $0x80 316 RET 317 318 // void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void)) 319 // System call args are: func arg stack pthread flags. 320 TEXT runtime·bsdthread_create(SB),NOSPLIT,$32 321 MOVL $360, AX 322 // 0(SP) is where the caller PC would be; kernel skips it 323 MOVL fn+12(FP), BX 324 MOVL BX, 4(SP) // func 325 MOVL mm+4(FP), BX 326 MOVL BX, 8(SP) // arg 327 MOVL stk+0(FP), BX 328 MOVL BX, 12(SP) // stack 329 MOVL gg+8(FP), BX 330 MOVL BX, 16(SP) // pthread 331 MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM 332 INT $0x80 333 JAE 4(PC) 334 NEGL AX 335 MOVL AX, ret+16(FP) 336 RET 337 MOVL $0, AX 338 MOVL AX, ret+16(FP) 339 RET 340 341 // The thread that bsdthread_create creates starts executing here, 342 // because we registered this function using bsdthread_register 343 // at startup. 344 // AX = "pthread" (= g) 345 // BX = mach thread port 346 // CX = "func" (= fn) 347 // DX = "arg" (= m) 348 // DI = stack top 349 // SI = flags (= 0x1000000) 350 // SP = stack - C_32_STK_ALIGN 351 TEXT runtime·bsdthread_start(SB),NOSPLIT,$0 352 // set up ldt 7+id to point at m->tls. 353 // m->tls is at m+40. newosproc left 354 // the m->id in tls[0]. 355 LEAL m_tls(DX), BP 356 MOVL 0(BP), DI 357 ADDL $7, DI // m0 is LDT#7. count up. 358 // setldt(tls#, &tls, sizeof tls) 359 PUSHAL // save registers 360 PUSHL $32 // sizeof tls 361 PUSHL BP // &tls 362 PUSHL DI // tls # 363 CALL runtime·setldt(SB) 364 POPL AX 365 POPL AX 366 POPL AX 367 POPAL 368 369 // Now segment is established. Initialize m, g. 370 get_tls(BP) 371 MOVL AX, g(BP) 372 MOVL DX, g_m(AX) 373 MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers) 374 CALL runtime·stackcheck(SB) // smashes AX 375 CALL CX // fn() 376 CALL runtime·exit1(SB) 377 RET 378 379 // void bsdthread_register(void) 380 // registers callbacks for threadstart (see bsdthread_create above 381 // and wqthread and pthsize (not used). returns 0 on success. 382 TEXT runtime·bsdthread_register(SB),NOSPLIT,$40 383 MOVL $366, AX 384 // 0(SP) is where kernel expects caller PC; ignored 385 MOVL $runtime·bsdthread_start(SB), 4(SP) // threadstart 386 MOVL $0, 8(SP) // wqthread, not used by us 387 MOVL $0, 12(SP) // pthsize, not used by us 388 MOVL $0, 16(SP) // dummy_value [sic] 389 MOVL $0, 20(SP) // targetconc_ptr 390 MOVL $0, 24(SP) // dispatchqueue_offset 391 INT $0x80 392 JAE 4(PC) 393 NEGL AX 394 MOVL AX, ret+0(FP) 395 RET 396 MOVL $0, AX 397 MOVL AX, ret+0(FP) 398 RET 399 400 // Invoke Mach system call. 401 // Assumes system call number in AX, 402 // caller PC on stack, caller's caller PC next, 403 // and then the system call arguments. 404 // 405 // Can be used for BSD too, but we don't, 406 // because if you use this interface the BSD 407 // system call numbers need an extra field 408 // in the high 16 bits that seems to be the 409 // argument count in bytes but is not always. 410 // INT $0x80 works fine for those. 411 TEXT runtime·sysenter(SB),NOSPLIT,$0 412 POPL DX 413 MOVL SP, CX 414 BYTE $0x0F; BYTE $0x34; // SYSENTER 415 // returns to DX with SP set to CX 416 417 TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0 418 MOVL $-31, AX 419 CALL runtime·sysenter(SB) 420 MOVL AX, ret+28(FP) 421 RET 422 423 TEXT runtime·mach_reply_port(SB),NOSPLIT,$0 424 MOVL $-26, AX 425 CALL runtime·sysenter(SB) 426 MOVL AX, ret+0(FP) 427 RET 428 429 TEXT runtime·mach_task_self(SB),NOSPLIT,$0 430 MOVL $-28, AX 431 CALL runtime·sysenter(SB) 432 MOVL AX, ret+0(FP) 433 RET 434 435 // Mach provides trap versions of the semaphore ops, 436 // instead of requiring the use of RPC. 437 438 // uint32 mach_semaphore_wait(uint32) 439 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0 440 MOVL $-36, AX 441 CALL runtime·sysenter(SB) 442 MOVL AX, ret+4(FP) 443 RET 444 445 // uint32 mach_semaphore_timedwait(uint32, uint32, uint32) 446 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0 447 MOVL $-38, AX 448 CALL runtime·sysenter(SB) 449 MOVL AX, ret+12(FP) 450 RET 451 452 // uint32 mach_semaphore_signal(uint32) 453 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0 454 MOVL $-33, AX 455 CALL runtime·sysenter(SB) 456 MOVL AX, ret+4(FP) 457 RET 458 459 // uint32 mach_semaphore_signal_all(uint32) 460 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 461 MOVL $-34, AX 462 CALL runtime·sysenter(SB) 463 MOVL AX, ret+4(FP) 464 RET 465 466 // setldt(int entry, int address, int limit) 467 // entry and limit are ignored. 468 TEXT runtime·setldt(SB),NOSPLIT,$32 469 MOVL address+4(FP), BX // aka base 470 471 /* 472 * When linking against the system libraries, 473 * we use its pthread_create and let it set up %gs 474 * for us. When we do that, the private storage 475 * we get is not at 0(GS) but at 0x468(GS). 476 * 8l rewrites 0(TLS) into 0x468(GS) for us. 477 * To accommodate that rewrite, we translate the 478 * address and limit here so that 0x468(GS) maps to 0(address). 479 * 480 * See cgo/gcc_darwin_386.c:/468 for the derivation 481 * of the constant. 482 */ 483 SUBL $0x468, BX 484 485 /* 486 * Must set up as USER_CTHREAD segment because 487 * Darwin forces that value into %gs for signal handlers, 488 * and if we don't set one up, we'll get a recursive 489 * fault trying to get into the signal handler. 490 * Since we have to set one up anyway, it might as 491 * well be the value we want. So don't bother with 492 * i386_set_ldt. 493 */ 494 MOVL BX, 4(SP) 495 MOVL $3, AX // thread_fast_set_cthread_self - machdep call #3 496 INT $0x82 // sic: 0x82, not 0x80, for machdep call 497 498 XORL AX, AX 499 MOVW GS, AX 500 RET 501 502 TEXT runtime·sysctl(SB),NOSPLIT,$0 503 MOVL $202, AX 504 INT $0x80 505 JAE 4(PC) 506 NEGL AX 507 MOVL AX, ret+24(FP) 508 RET 509 MOVL $0, AX 510 MOVL AX, ret+24(FP) 511 RET 512 513 // int32 runtime·kqueue(void); 514 TEXT runtime·kqueue(SB),NOSPLIT,$0 515 MOVL $362, AX 516 INT $0x80 517 JAE 2(PC) 518 NEGL AX 519 MOVL AX, ret+0(FP) 520 RET 521 522 // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout); 523 TEXT runtime·kevent(SB),NOSPLIT,$0 524 MOVL $363, AX 525 INT $0x80 526 JAE 2(PC) 527 NEGL AX 528 MOVL AX, ret+24(FP) 529 RET 530 531 // int32 runtime·closeonexec(int32 fd); 532 TEXT runtime·closeonexec(SB),NOSPLIT,$32 533 MOVL $92, AX // fcntl 534 // 0(SP) is where the caller PC would be; kernel skips it 535 MOVL fd+0(FP), BX 536 MOVL BX, 4(SP) // fd 537 MOVL $2, 8(SP) // F_SETFD 538 MOVL $1, 12(SP) // FD_CLOEXEC 539 INT $0x80 540 JAE 2(PC) 541 NEGL AX 542 RET