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