1 // Copyright 2014 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 ARM, 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 // Copied from /usr/include/sys/syscall.h 14 #define SYS_exit 1 15 #define SYS_read 3 16 #define SYS_write 4 17 #define SYS_open 5 18 #define SYS_close 6 19 #define SYS_mmap 197 20 #define SYS_munmap 73 21 #define SYS_madvise 75 22 #define SYS_gettimeofday 116 23 #define SYS_kill 37 24 #define SYS_getpid 20 25 #define SYS___pthread_kill 328 26 #define SYS_pthread_sigmask 329 27 #define SYS_setitimer 83 28 #define SYS___sysctl 202 29 #define SYS_sigaction 46 30 #define SYS_sigreturn 184 31 #define SYS_select 93 32 #define SYS_bsdthread_register 366 33 #define SYS_bsdthread_create 360 34 #define SYS_bsdthread_terminate 361 35 #define SYS_kqueue 362 36 #define SYS_kevent 363 37 #define SYS_fcntl 92 38 39 TEXT notok<>(SB),NOSPLIT,$0 40 MOVW $0, R8 41 MOVW R8, (R8) 42 B 0(PC) 43 44 TEXT runtimeopen(SB),NOSPLIT,$0 45 MOVW name+0(FP), R0 46 MOVW mode+4(FP), R1 47 MOVW perm+8(FP), R2 48 MOVW $SYS_open, R12 49 SWI $0x80 50 MOVW.CS $-1, R0 51 MOVW R0, ret+12(FP) 52 RET 53 54 TEXT runtimeclosefd(SB),NOSPLIT,$0 55 MOVW fd+0(FP), R0 56 MOVW $SYS_close, R12 57 SWI $0x80 58 MOVW.CS $-1, R0 59 MOVW R0, ret+4(FP) 60 RET 61 62 TEXT runtimewrite(SB),NOSPLIT,$0 63 MOVW fd+0(FP), R0 64 MOVW p+4(FP), R1 65 MOVW n+8(FP), R2 66 MOVW $SYS_write, R12 67 SWI $0x80 68 MOVW.CS $-1, R0 69 MOVW R0, ret+12(FP) 70 RET 71 72 TEXT runtimeread(SB),NOSPLIT,$0 73 MOVW fd+0(FP), R0 74 MOVW p+4(FP), R1 75 MOVW n+8(FP), R2 76 MOVW $SYS_read, R12 77 SWI $0x80 78 MOVW.CS $-1, R0 79 MOVW R0, ret+12(FP) 80 RET 81 82 TEXT runtimeexit(SB),NOSPLIT,$-4 83 MOVW code+0(FP), R0 84 MOVW $SYS_exit, R12 85 SWI $0x80 86 MOVW $1234, R0 87 MOVW $1002, R1 88 MOVW R0, (R1) // fail hard 89 90 // Exit this OS thread (like pthread_exit, which eventually 91 // calls __bsdthread_terminate). 92 TEXT exit1<>(SB),NOSPLIT,$0 93 // Because of exitThread below, this must not use the stack. 94 // __bsdthread_terminate takes 4 word-size arguments. 95 // Set them all to 0. (None are an exit status.) 96 MOVW $0, R0 97 MOVW $0, R1 98 MOVW $0, R2 99 MOVW $0, R3 100 MOVW $SYS_bsdthread_terminate, R12 101 SWI $0x80 102 MOVW $1234, R0 103 MOVW $1003, R1 104 MOVW R0, (R1) // fail hard 105 106 // func exitThread(wait *uint32) 107 TEXT runtimeexitThread(SB),NOSPLIT,$0-4 108 MOVW wait+0(FP), R0 109 // We're done using the stack. 110 MOVW $0, R2 111 storeloop: 112 LDREX (R0), R4 // loads R4 113 STREX R2, (R0), R1 // stores R2 114 CMP $0, R1 115 BNE storeloop 116 JMP exit1<>(SB) 117 118 TEXT runtimeraise(SB),NOSPLIT,$0 119 // Ideally we'd send the signal to the current thread, 120 // not the whole process, but that's too hard on OS X. 121 JMP runtimeraiseproc(SB) 122 123 TEXT runtimeraiseproc(SB),NOSPLIT,$24 124 MOVW $SYS_getpid, R12 125 SWI $0x80 126 // arg 1 pid already in R0 from getpid 127 MOVW sig+0(FP), R1 // arg 2 - signal 128 MOVW $1, R2 // arg 3 - posix 129 MOVW $SYS_kill, R12 130 SWI $0x80 131 RET 132 133 TEXT runtimemmap(SB),NOSPLIT,$0 134 MOVW addr+0(FP), R0 135 MOVW n+4(FP), R1 136 MOVW prot+8(FP), R2 137 MOVW flags+12(FP), R3 138 MOVW fd+16(FP), R4 139 MOVW off+20(FP), R5 140 MOVW $0, R6 // off_t is uint64_t 141 MOVW $SYS_mmap, R12 142 SWI $0x80 143 MOVW $0, R1 144 BCC ok 145 MOVW R1, p+24(FP) 146 MOVW R0, err+28(FP) 147 RET 148 ok: 149 MOVW R0, p+24(FP) 150 MOVW R1, err+28(FP) 151 RET 152 153 TEXT runtimemunmap(SB),NOSPLIT,$0 154 MOVW addr+0(FP), R0 155 MOVW n+4(FP), R1 156 MOVW $SYS_munmap, R12 157 SWI $0x80 158 BL.CS notok<>(SB) 159 RET 160 161 TEXT runtimemadvise(SB),NOSPLIT,$0 162 MOVW addr+0(FP), R0 163 MOVW n+4(FP), R1 164 MOVW flags+8(FP), R2 165 MOVW $SYS_madvise, R12 166 SWI $0x80 167 BL.CS notok<>(SB) 168 RET 169 170 TEXT runtimesetitimer(SB),NOSPLIT,$0 171 MOVW mode+0(FP), R0 172 MOVW new+4(FP), R1 173 MOVW old+8(FP), R2 174 MOVW $SYS_setitimer, R12 175 SWI $0x80 176 RET 177 178 TEXT runtimewalltime(SB), 7, $32 179 MOVW $8(R13), R0 // timeval 180 MOVW $0, R1 // zone 181 MOVW $0, R2 // see issue 16570 182 MOVW $SYS_gettimeofday, R12 183 SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec 184 CMP $0, R0 185 BNE inreg 186 MOVW 8(R13), R0 187 MOVW 12(R13), R1 188 inreg: 189 MOVW R1, R2 // usec 190 MOVW R0, sec_lo+0(FP) 191 MOVW $0, R1 192 MOVW R1, sec_hi+4(FP) 193 MOVW $1000, R3 194 MUL R3, R2 195 MOVW R2, nsec+8(FP) 196 RET 197 198 TEXT runtimenanotime(SB),NOSPLIT,$32 199 MOVW $8(R13), R0 // timeval 200 MOVW $0, R1 // zone 201 MOVW $0, R2 // see issue 16570 202 MOVW $SYS_gettimeofday, R12 203 SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec 204 CMP $0, R0 205 BNE inreg 206 MOVW 8(R13), R0 207 MOVW 12(R13), R1 208 inreg: 209 MOVW R1, R2 210 MOVW $1000000000, R3 211 MULLU R0, R3, (R1, R0) 212 MOVW $1000, R3 213 MOVW $0, R4 214 MUL R3, R2 215 ADD.S R2, R0 216 ADC R4, R1 217 218 MOVW R0, ret_lo+0(FP) 219 MOVW R1, ret_hi+4(FP) 220 RET 221 222 TEXT runtimesigfwd(SB),NOSPLIT,$0-16 223 MOVW sig+4(FP), R0 224 MOVW info+8(FP), R1 225 MOVW ctx+12(FP), R2 226 MOVW fn+0(FP), R11 227 MOVW R13, R4 228 SUB $24, R13 229 BIC $0x7, R13 // alignment for ELF ABI 230 BL (R11) 231 MOVW R4, R13 232 RET 233 234 // Sigtramp's job is to call the actual signal handler. 235 // It is called with the following arguments on the stack: 236 // LR "return address" - ignored 237 // R0 actual handler 238 // R1 siginfo style - ignored 239 // R2 signal number 240 // R3 siginfo 241 // -4(FP) context, beware that 0(FP) is the saved LR 242 TEXT runtimesigtramp(SB),NOSPLIT,$0 243 // this might be called in external code context, 244 // where g is not set. 245 // first save R0, because runtimeload_g will clobber it 246 MOVM.DB.W [R0], (R13) 247 MOVB runtimeiscgo(SB), R0 248 CMP $0, R0 249 BL.NE runtimeload_g(SB) 250 251 CMP $0, g 252 BNE cont 253 // fake function call stack frame for badsignal 254 // we only need to pass R2 (signal number), but 255 // badsignal will expect R2 at 4(R13), so we also 256 // push R1 onto stack. turns out we do need R1 257 // to do sigreturn. 258 MOVM.DB.W [R1,R2], (R13) 259 MOVW $runtimebadsignal(SB), R11 260 BL (R11) 261 MOVM.IA.W [R1], (R13) // saved infostype 262 ADD $(4+4), R13 // +4: also need to remove the pushed R0. 263 MOVW ucontext-4(FP), R0 // load ucontext 264 B ret 265 266 cont: 267 // Restore R0 268 MOVM.IA.W (R13), [R0] 269 270 // NOTE: some Darwin/ARM kernels always use the main stack to run the 271 // signal handler. We need to switch to gsignal ourselves. 272 MOVW g_m(g), R11 273 MOVW m_gsignal(R11), R5 274 MOVW (g_stack+stack_hi)(R5), R6 275 SUB $28, R6 276 277 // copy arguments for call to sighandler 278 MOVW R2, 4(R6) // signal num 279 MOVW R3, 8(R6) // signal info 280 MOVW g, 16(R6) // old_g 281 MOVW context-4(FP), R4 282 MOVW R4, 12(R6) // context 283 284 // Backup ucontext and infostyle 285 MOVW R4, 20(R6) 286 MOVW R1, 24(R6) 287 288 // switch stack and g 289 MOVW R6, R13 // sigtramp is not re-entrant, so no need to back up R13. 290 MOVW R5, g 291 292 BL (R0) 293 294 // call sigreturn 295 MOVW 20(R13), R0 // saved ucontext 296 MOVW 24(R13), R1 // saved infostyle 297 ret: 298 MOVW $SYS_sigreturn, R12 // sigreturn(ucontext, infostyle) 299 SWI $0x80 300 301 // if sigreturn fails, we can do nothing but exit 302 B runtimeexit(SB) 303 304 TEXT runtimesigprocmask(SB),NOSPLIT,$0 305 MOVW how+0(FP), R0 306 MOVW new+4(FP), R1 307 MOVW old+8(FP), R2 308 MOVW $SYS_pthread_sigmask, R12 309 SWI $0x80 310 BL.CS notok<>(SB) 311 RET 312 313 TEXT runtimesigaction(SB),NOSPLIT,$0 314 MOVW mode+0(FP), R0 315 MOVW new+4(FP), R1 316 MOVW old+8(FP), R2 317 MOVW $SYS_sigaction, R12 318 SWI $0x80 319 RET 320 321 TEXT runtimeusleep(SB),NOSPLIT,$12 322 MOVW usec+0(FP), R0 323 CALL runtimeusplitR0(SB) 324 MOVW R0, a-12(SP) 325 MOVW R1, b-8(SP) 326 327 // select(0, 0, 0, 0, &tv) 328 MOVW $0, R0 329 MOVW $0, R1 330 MOVW $0, R2 331 MOVW $0, R3 332 MOVW $a-12(SP), R4 333 MOVW $SYS_select, R12 334 SWI $0x80 335 RET 336 337 TEXT publicationBarrier(SB),NOSPLIT,$-4-0 338 B runtimearmPublicationBarrier(SB) 339 340 TEXT runtimesysctl(SB),NOSPLIT,$0 341 MOVW mib+0(FP), R0 342 MOVW miblen+4(FP), R1 343 MOVW out+8(FP), R2 344 MOVW size+12(FP), R3 345 MOVW dst+16(FP), R4 346 MOVW ndst+20(FP), R5 347 MOVW $SYS___sysctl, R12 // syscall entry 348 SWI $0x80 349 BCC sysctl_ret 350 RSB $0, R0, R0 351 MOVW R0, ret+24(FP) 352 RET 353 sysctl_ret: 354 MOVW $0, R0 355 MOVW R0, ret+24(FP) 356 RET 357 358 // Thread related functions 359 // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32 360 TEXT runtimebsdthread_create(SB),NOSPLIT,$0 361 // Set up arguments to bsdthread_create system call. 362 // The ones in quotes pass through to the thread callback 363 // uninterpreted, so we can put whatever we want there. 364 MOVW fn+8(FP), R0 // "func" 365 MOVW arg+4(FP), R1 // "arg" 366 MOVW stk+0(FP), R2 // stack 367 MOVW $0x01000000, R4 // flags = PTHREAD_START_CUSTOM 368 MOVW $0, R5 // paranoia 369 MOVW $SYS_bsdthread_create, R12 370 SWI $0x80 371 BCC create_ret 372 RSB $0, R0, R0 373 MOVW R0, ret+12(FP) 374 RET 375 create_ret: 376 MOVW $0, R0 377 MOVW R0, ret+12(FP) 378 RET 379 380 // The thread that bsdthread_create creates starts executing here, 381 // because we registered this function using bsdthread_register 382 // at startup. 383 // R0 = "pthread" 384 // R1 = mach thread port 385 // R2 = "func" (= fn) 386 // R3 = "arg" (= m) 387 // R4 = stack 388 // R5 = flags (= 0) 389 // XXX: how to deal with R4/SP? ref: Libc-594.9.1/arm/pthreads/thread_start.s 390 TEXT runtimebsdthread_start(SB),NOSPLIT,$0 391 MOVW R1, m_procid(R3) // thread port is m->procid 392 MOVW m_g0(R3), g 393 MOVW R3, g_m(g) 394 // ARM don't have runtimestackcheck(SB) 395 // disable runfast mode of vfp 396 EOR R12, R12 397 WORD $0xeee1ca10 // fmxr fpscr, ip 398 BL (R2) // fn 399 BL exit1<>(SB) 400 RET 401 402 // int32 bsdthread_register(void) 403 // registers callbacks for threadstart (see bsdthread_create above 404 // and wqthread and pthsize (not used). returns 0 on success. 405 TEXT runtimebsdthread_register(SB),NOSPLIT,$0 406 MOVW $runtimebsdthread_start(SB), R0 // threadstart 407 MOVW $0, R1 // wqthread, not used by us 408 MOVW $0, R2 // pthsize, not used by us 409 MOVW $0, R3 // dummy_value [sic] 410 MOVW $0, R4 // targetconc_ptr 411 MOVW $0, R5 // dispatchqueue_offset 412 MOVW $SYS_bsdthread_register, R12 // bsdthread_register 413 SWI $0x80 414 MOVW R0, ret+0(FP) 415 RET 416 417 // uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) 418 TEXT runtimemach_msg_trap(SB),NOSPLIT,$0 419 MOVW h+0(FP), R0 420 MOVW op+4(FP), R1 421 MOVW send_size+8(FP), R2 422 MOVW rcv_size+12(FP), R3 423 MOVW rcv_name+16(FP), R4 424 MOVW timeout+20(FP), R5 425 MOVW notify+24(FP), R6 426 MVN $30, R12 427 SWI $0x80 428 MOVW R0, ret+28(FP) 429 RET 430 431 TEXT runtimemach_task_self(SB),NOSPLIT,$0 432 MVN $27, R12 // task_self_trap 433 SWI $0x80 434 MOVW R0, ret+0(FP) 435 RET 436 437 TEXT runtimemach_thread_self(SB),NOSPLIT,$0 438 MVN $26, R12 // thread_self_trap 439 SWI $0x80 440 MOVW R0, ret+0(FP) 441 RET 442 443 TEXT runtimemach_reply_port(SB),NOSPLIT,$0 444 MVN $25, R12 // mach_reply_port 445 SWI $0x80 446 MOVW R0, ret+0(FP) 447 RET 448 449 // Mach provides trap versions of the semaphore ops, 450 // instead of requiring the use of RPC. 451 452 // uint32 mach_semaphore_wait(uint32) 453 TEXT runtimemach_semaphore_wait(SB),NOSPLIT,$0 454 MOVW sema+0(FP), R0 455 MVN $35, R12 // semaphore_wait_trap 456 SWI $0x80 457 MOVW R0, ret+4(FP) 458 RET 459 460 // uint32 mach_semaphore_timedwait(uint32, uint32, uint32) 461 TEXT runtimemach_semaphore_timedwait(SB),NOSPLIT,$0 462 MOVW sema+0(FP), R0 463 MOVW sec+4(FP), R1 464 MOVW nsec+8(FP), R2 465 MVN $37, R12 // semaphore_timedwait_trap 466 SWI $0x80 467 MOVW R0, ret+12(FP) 468 RET 469 470 // uint32 mach_semaphore_signal(uint32) 471 TEXT runtimemach_semaphore_signal(SB),NOSPLIT,$0 472 MOVW sema+0(FP), R0 473 MVN $32, R12 // semaphore_signal_trap 474 SWI $0x80 475 MOVW R0, ret+4(FP) 476 RET 477 478 // uint32 mach_semaphore_signal_all(uint32) 479 TEXT runtimemach_semaphore_signal_all(SB),NOSPLIT,$0 480 MOVW sema+0(FP), R0 481 MVN $33, R12 // semaphore_signal_all_trap 482 SWI $0x80 483 MOVW R0, ret+4(FP) 484 RET 485 486 // int32 runtimekqueue(void) 487 TEXT runtimekqueue(SB),NOSPLIT,$0 488 MOVW $SYS_kqueue, R12 489 SWI $0x80 490 RSB.CS $0, R0, R0 491 MOVW R0, ret+0(FP) 492 RET 493 494 // int32 runtimekevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout) 495 TEXT runtimekevent(SB),NOSPLIT,$0 496 MOVW $SYS_kevent, R12 497 MOVW kq+0(FP), R0 498 MOVW ch+4(FP), R1 499 MOVW nch+8(FP), R2 500 MOVW ev+12(FP), R3 501 MOVW nev+16(FP), R4 502 MOVW ts+20(FP), R5 503 SWI $0x80 504 RSB.CS $0, R0, R0 505 MOVW R0, ret+24(FP) 506 RET 507 508 // int32 runtimecloseonexec(int32 fd) 509 TEXT runtimecloseonexec(SB),NOSPLIT,$0 510 MOVW $SYS_fcntl, R12 511 MOVW fd+0(FP), R0 512 MOVW $2, R1 // F_SETFD 513 MOVW $1, R2 // FD_CLOEXEC 514 SWI $0x80 515 RET 516 517 // sigaltstack on some darwin/arm version is buggy and will always 518 // run the signal handler on the main stack, so our sigtramp has 519 // to do the stack switch ourselves. 520 TEXT runtimesigaltstack(SB),NOSPLIT,$0 521 RET 522