github.com/aloncn/graphics-go@v0.0.1/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 JAE 2(PC) 33 MOVL $-1, AX 34 MOVL AX, ret+12(FP) 35 RET 36 37 TEXT runtime·closefd(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 runtime·read(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 runtime·write(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 runtime·raise(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 runtime·raiseproc(SB) 65 66 TEXT runtime·raiseproc(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 runtime·mmap(SB),NOSPLIT,$0 78 MOVL $197, AX 79 INT $0x80 80 MOVL AX, ret+24(FP) 81 RET 82 83 TEXT runtime·madvise(SB),NOSPLIT,$0 84 MOVL $75, AX 85 INT $0x80 86 // ignore failure - maybe pages are locked 87 RET 88 89 TEXT runtime·munmap(SB),NOSPLIT,$0 90 MOVL $73, AX 91 INT $0x80 92 JAE 2(PC) 93 MOVL $0xf1, 0xf1 // crash 94 RET 95 96 TEXT runtime·setitimer(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 runtime·now(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 time·now(SB),NOSPLIT,$0 216 CALL runtime·now(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 runtime·nanotime(SB),NOSPLIT,$0 226 CALL runtime·now(SB) 227 MOVL AX, ret_lo+0(FP) 228 MOVL DX, ret_hi+4(FP) 229 RET 230 231 TEXT runtime·sigprocmask(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 runtime·sigaction(SB),NOSPLIT,$0 239 MOVL $46, AX 240 INT $0x80 241 JAE 2(PC) 242 MOVL $0xf1, 0xf1 // crash 243 RET 244 245 TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 246 MOVL fn+0(FP), AX 247 MOVL sig+4(FP), BX 248 MOVL info+8(FP), CX 249 MOVL ctx+12(FP), DX 250 MOVL SP, SI 251 SUBL $32, SP // align stack; handler might be C code 252 ANDL $~15, SP 253 MOVL BX, 0(SP) 254 MOVL CX, 4(SP) 255 MOVL DX, 8(SP) 256 MOVL SI, 12(SP) 257 CALL AX 258 MOVL 12(SP), AX 259 MOVL AX, SP 260 RET 261 262 TEXT runtime·sigreturn(SB),NOSPLIT,$12-8 263 MOVL ctx+0(FP), CX 264 MOVL infostyle+4(FP), BX 265 MOVL $0, 0(SP) // "caller PC" - ignored 266 MOVL CX, 4(SP) 267 MOVL BX, 8(SP) 268 MOVL $184, AX // sigreturn(ucontext, infostyle) 269 INT $0x80 270 MOVL $0xf1, 0xf1 // crash 271 RET 272 273 // Sigtramp's job is to call the actual signal handler. 274 // It is called with the following arguments on the stack: 275 // 0(SP) "return address" - ignored 276 // 4(SP) actual handler 277 // 8(SP) signal number 278 // 12(SP) siginfo style 279 // 16(SP) siginfo 280 // 20(SP) context 281 TEXT runtime·sigtramp(SB),NOSPLIT,$20 282 MOVL fn+0(FP), BX 283 MOVL BX, 0(SP) 284 MOVL style+4(FP), BX 285 MOVL BX, 4(SP) 286 MOVL sig+8(FP), BX 287 MOVL BX, 8(SP) 288 MOVL info+12(FP), BX 289 MOVL BX, 12(SP) 290 MOVL context+16(FP), BX 291 MOVL BX, 16(SP) 292 CALL runtime·sigtrampgo(SB) 293 294 // call sigreturn 295 MOVL context+16(FP), CX 296 MOVL style+4(FP), BX 297 MOVL $0, 0(SP) // "caller PC" - ignored 298 MOVL CX, 4(SP) 299 MOVL BX, 8(SP) 300 MOVL $184, AX // sigreturn(ucontext, infostyle) 301 INT $0x80 302 MOVL $0xf1, 0xf1 // crash 303 RET 304 305 TEXT runtime·sigaltstack(SB),NOSPLIT,$0 306 MOVL $53, AX 307 INT $0x80 308 JAE 2(PC) 309 MOVL $0xf1, 0xf1 // crash 310 RET 311 312 TEXT runtime·usleep(SB),NOSPLIT,$32 313 MOVL $0, DX 314 MOVL usec+0(FP), AX 315 MOVL $1000000, CX 316 DIVL CX 317 MOVL AX, 24(SP) // sec 318 MOVL DX, 28(SP) // usec 319 320 // select(0, 0, 0, 0, &tv) 321 MOVL $0, 0(SP) // "return PC" - ignored 322 MOVL $0, 4(SP) 323 MOVL $0, 8(SP) 324 MOVL $0, 12(SP) 325 MOVL $0, 16(SP) 326 LEAL 24(SP), AX 327 MOVL AX, 20(SP) 328 MOVL $93, AX 329 INT $0x80 330 RET 331 332 // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32 333 // System call args are: func arg stack pthread flags. 334 TEXT runtime·bsdthread_create(SB),NOSPLIT,$32 335 MOVL $360, AX 336 // 0(SP) is where the caller PC would be; kernel skips it 337 MOVL fn+8(FP), BX 338 MOVL BX, 4(SP) // func 339 MOVL arg+4(FP), BX 340 MOVL BX, 8(SP) // arg 341 MOVL stk+0(FP), BX 342 MOVL BX, 12(SP) // stack 343 MOVL $0, 16(SP) // pthread 344 MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM 345 INT $0x80 346 JAE 4(PC) 347 NEGL AX 348 MOVL AX, ret+12(FP) 349 RET 350 MOVL $0, AX 351 MOVL AX, ret+12(FP) 352 RET 353 354 // The thread that bsdthread_create creates starts executing here, 355 // because we registered this function using bsdthread_register 356 // at startup. 357 // AX = "pthread" (= 0x0) 358 // BX = mach thread port 359 // CX = "func" (= fn) 360 // DX = "arg" (= m) 361 // DI = stack top 362 // SI = flags (= 0x1000000) 363 // SP = stack - C_32_STK_ALIGN 364 TEXT runtime·bsdthread_start(SB),NOSPLIT,$0 365 // set up ldt 7+id to point at m->tls. 366 LEAL m_tls(DX), BP 367 MOVL m_id(DX), 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 runtime·setldt(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 runtime·stackcheck(SB) // smashes AX 387 CALL CX // fn() 388 CALL runtime·exit1(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 runtime·bsdthread_register(SB),NOSPLIT,$40 395 MOVL $366, AX 396 // 0(SP) is where kernel expects caller PC; ignored 397 MOVL $runtime·bsdthread_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 runtime·sysenter(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 runtime·mach_msg_trap(SB),NOSPLIT,$0 430 MOVL $-31, AX 431 CALL runtime·sysenter(SB) 432 MOVL AX, ret+28(FP) 433 RET 434 435 TEXT runtime·mach_reply_port(SB),NOSPLIT,$0 436 MOVL $-26, AX 437 CALL runtime·sysenter(SB) 438 MOVL AX, ret+0(FP) 439 RET 440 441 TEXT runtime·mach_task_self(SB),NOSPLIT,$0 442 MOVL $-28, AX 443 CALL runtime·sysenter(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 runtime·mach_semaphore_wait(SB),NOSPLIT,$0 452 MOVL $-36, AX 453 CALL runtime·sysenter(SB) 454 MOVL AX, ret+4(FP) 455 RET 456 457 // func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 458 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0 459 MOVL $-38, AX 460 CALL runtime·sysenter(SB) 461 MOVL AX, ret+12(FP) 462 RET 463 464 // func mach_semaphore_signal(sema uint32) int32 465 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0 466 MOVL $-33, AX 467 CALL runtime·sysenter(SB) 468 MOVL AX, ret+4(FP) 469 RET 470 471 // func mach_semaphore_signal_all(sema uint32) int32 472 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 473 MOVL $-34, AX 474 CALL runtime·sysenter(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 runtime·setldt(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 runtime·sysctl(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 runtime·kqueue(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 runtime·kevent(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 runtime·closeonexec(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