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// System calls are implemented in libSystem, this file contains 7// trampolines that convert from Go to C calling convention. 8 9#include "go_asm.h" 10#include "go_tls.h" 11#include "textflag.h" 12 13TEXT notok<>(SB),NOSPLIT,$0 14 MOVW $0, R8 15 MOVW R8, (R8) 16 B 0(PC) 17 18TEXT runtime·open_trampoline(SB),NOSPLIT,$0 19 MOVW 4(R0), R1 // arg 2 mode 20 MOVW 8(R0), R2 // arg 3 perm 21 MOVW 0(R0), R0 // arg 1 name 22 BL libc_open(SB) 23 RET 24 25TEXT runtime·close_trampoline(SB),NOSPLIT,$0 26 MOVW 0(R0), R0 // arg 1 fd 27 BL libc_close(SB) 28 RET 29 30TEXT runtime·write_trampoline(SB),NOSPLIT,$0 31 MOVW 4(R0), R1 // arg 2 buf 32 MOVW 8(R0), R2 // arg 3 count 33 MOVW 0(R0), R0 // arg 1 fd 34 BL libc_write(SB) 35 MOVW $-1, R1 36 CMP R0, R1 37 BNE noerr 38 BL libc_error(SB) 39 MOVW (R0), R0 40 RSB $0, R0, R0 // caller expects negative errno value 41noerr: 42 RET 43 44TEXT runtime·read_trampoline(SB),NOSPLIT,$0 45 MOVW 4(R0), R1 // arg 2 buf 46 MOVW 8(R0), R2 // arg 3 count 47 MOVW 0(R0), R0 // arg 1 fd 48 BL libc_read(SB) 49 MOVW $-1, R1 50 CMP R0, R1 51 BNE noerr 52 BL libc_error(SB) 53 MOVW (R0), R0 54 RSB $0, R0, R0 // caller expects negative errno value 55noerr: 56 RET 57 58TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0 59 BL libc_pipe(SB) // pointer already in R0 60 CMP $0, R0 61 BEQ 3(PC) 62 BL libc_error(SB) // return negative errno value 63 RSB $0, R0, R0 64 RET 65 66TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0 67 MOVW 0(R0), R0 // arg 0 code 68 BL libc_exit(SB) 69 MOVW $1234, R0 70 MOVW $1002, R1 71 MOVW R0, (R1) // fail hard 72 73TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 74 MOVW 0(R0), R8 // signal 75 BL libc_getpid(SB) 76 // arg 1 pid already in R0 from getpid 77 MOVW R8, R1 // arg 2 signal 78 BL libc_kill(SB) 79 RET 80 81TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 82 MOVW R0, R8 83 MOVW 0(R8), R0 // arg 1 addr 84 MOVW 4(R8), R1 // arg 2 len 85 MOVW 8(R8), R2 // arg 3 prot 86 MOVW 12(R8), R3 // arg 4 flags 87 MOVW 16(R8), R4 // arg 5 fid 88 MOVW 20(R8), R5 // arg 6 offset 89 MOVW $0, R6 // off_t is uint64_t 90 // Only R0-R3 are used for arguments, the rest 91 // go on the stack. 92 MOVM.DB.W [R4-R6], (R13) 93 BL libc_mmap(SB) 94 ADD $12, R13 95 MOVW $0, R1 96 MOVW $-1, R2 97 CMP R0, R2 98 BNE ok 99 BL libc_error(SB) 100 MOVW (R0), R1 101 MOVW $0, R0 102ok: 103 MOVW R0, 24(R8) // ret 1 addr 104 MOVW R1, 28(R8) // ret 2 err 105 RET 106 107TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 108 MOVW 4(R0), R1 // arg 2 len 109 MOVW 0(R0), R0 // arg 1 addr 110 BL libc_munmap(SB) 111 MOVW $-1, R2 112 CMP R0, R2 113 BL.EQ notok<>(SB) 114 RET 115 116TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0 117 MOVW 4(R0), R1 // arg 2 len 118 MOVW 8(R0), R2 // arg 3 advice 119 MOVW 0(R0), R0 // arg 1 addr 120 BL libc_madvise(SB) 121 MOVW $-1, R2 122 CMP R0, R2 123 BL.EQ notok<>(SB) 124 RET 125 126TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 127 MOVW 4(R0), R1 // arg 2 new 128 MOVW 8(R0), R2 // arg 3 old 129 MOVW 0(R0), R0 // arg 1 which 130 BL libc_setitimer(SB) 131 RET 132 133TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 134 // R0 already has *timeval 135 MOVW $0, R1 // no timezone needed 136 BL libc_gettimeofday(SB) 137 RET 138 139GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size) 140 141TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0 142 MOVW R0, R8 143 BL libc_mach_absolute_time(SB) 144 MOVW R0, 0(R8) 145 MOVW R1, 4(R8) 146 MOVW timebase<>+machTimebaseInfo_numer(SB), R6 147 MOVW $timebase<>+machTimebaseInfo_denom(SB), R5 148 MOVW (R5), R7 149 DMB MB_ISH // memory barrier for atomic read 150 CMP $0, R7 151 BNE initialized 152 153 SUB $(machTimebaseInfo__size+7)/8*8, R13 154 MOVW R13, R0 155 BL libc_mach_timebase_info(SB) 156 MOVW machTimebaseInfo_numer(R13), R6 157 MOVW machTimebaseInfo_denom(R13), R7 158 ADD $(machTimebaseInfo__size+7)/8*8, R13 159 160 MOVW R6, timebase<>+machTimebaseInfo_numer(SB) 161 MOVW $timebase<>+machTimebaseInfo_denom(SB), R5 162 DMB MB_ISH // memory barrier for atomic write 163 MOVW R7, (R5) 164 DMB MB_ISH 165 166initialized: 167 MOVW R6, 8(R8) 168 MOVW R7, 12(R8) 169 RET 170 171TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 172 MOVW sig+4(FP), R0 173 MOVW info+8(FP), R1 174 MOVW ctx+12(FP), R2 175 MOVW fn+0(FP), R11 176 MOVW R13, R4 177 SUB $24, R13 178 BIC $0x7, R13 // alignment for ELF ABI 179 BL (R11) 180 MOVW R4, R13 181 RET 182 183TEXT runtime·sigtramp(SB),NOSPLIT,$0 184 // Reserve space for callee-save registers and arguments. 185 MOVM.DB.W [R4-R11], (R13) 186 SUB $16, R13 187 188 // Save arguments. 189 MOVW R0, 4(R13) // sig 190 MOVW R1, 8(R13) // info 191 MOVW R2, 12(R13) // ctx 192 193 // this might be called in external code context, 194 // where g is not set. 195 MOVB runtime·iscgo(SB), R0 196 CMP $0, R0 197 BL.NE runtime·load_g(SB) 198 199 MOVW R13, R6 200 CMP $0, g 201 BEQ nog 202 203 // iOS always use the main stack to run the signal handler. 204 // We need to switch to gsignal ourselves. 205 MOVW g_m(g), R11 206 MOVW m_gsignal(R11), R5 207 MOVW (g_stack+stack_hi)(R5), R6 208 209nog: 210 // Restore arguments. 211 MOVW 4(R13), R0 212 MOVW 8(R13), R1 213 MOVW 12(R13), R2 214 215 // Reserve space for args and the stack pointer on the 216 // gsignal stack. 217 SUB $24, R6 218 // Save stack pointer. 219 MOVW R13, R4 220 MOVW R4, 16(R6) 221 // Switch to gsignal stack. 222 MOVW R6, R13 223 224 // Call sigtrampgo 225 MOVW R0, 4(R13) 226 MOVW R1, 8(R13) 227 MOVW R2, 12(R13) 228 BL runtime·sigtrampgo(SB) 229 230 // Switch to old stack. 231 MOVW 16(R13), R5 232 MOVW R5, R13 233 234 // Restore callee-save registers. 235 ADD $16, R13 236 MOVM.IA.W (R13), [R4-R11] 237 238 RET 239 240TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 241 JMP runtime·sigtramp(SB) 242 243TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 244 MOVW 4(R0), R1 // arg 2 new 245 MOVW 8(R0), R2 // arg 3 old 246 MOVW 0(R0), R0 // arg 1 how 247 BL libc_pthread_sigmask(SB) 248 CMP $0, R0 249 BL.NE notok<>(SB) 250 RET 251 252TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 253 MOVW 4(R0), R1 // arg 2 new 254 MOVW 8(R0), R2 // arg 3 old 255 MOVW 0(R0), R0 // arg 1 how 256 BL libc_sigaction(SB) 257 RET 258 259TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 260 MOVW 0(R0), R0 // arg 1 usec 261 BL libc_usleep(SB) 262 RET 263 264TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 265 B runtime·armPublicationBarrier(SB) 266 267TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 268 MOVW 4(R0), R1 // arg 2 miblen 269 MOVW 8(R0), R2 // arg 3 out 270 MOVW 12(R0), R3 // arg 4 size 271 MOVW 16(R0), R4 // arg 5 dst 272 MOVW 20(R0), R5 // arg 6 ndst 273 MOVW 0(R0), R0 // arg 1 mib 274 // Only R0-R3 are used for arguments, the rest 275 // go on the stack. 276 MOVM.DB.W [R4-R5], (R13) 277 BL libc_sysctl(SB) 278 ADD $(2*4), R13 279 RET 280 281TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 282 BL libc_kqueue(SB) 283 RET 284 285// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout) 286TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 287 MOVW 4(R0), R1 // arg 2 keventss 288 MOVW 8(R0), R2 // arg 3 nch 289 MOVW 12(R0), R3 // arg 4 ev 290 MOVW 16(R0), R4 // arg 5 nev 291 MOVW 20(R0), R5 // arg 6 ts 292 MOVW 0(R0), R0 // arg 1 kq 293 // Only R0-R3 are used for arguments, the rest 294 // go on the stack. 295 MOVM.DB.W [R4-R5], (R13) 296 BL libc_kevent(SB) 297 ADD $(2*4), R13 298 MOVW $-1, R2 299 CMP R0, R2 300 BNE ok 301 BL libc_error(SB) 302 MOVW (R0), R0 // errno 303 RSB $0, R0, R0 // caller wants it as a negative error code 304ok: 305 RET 306 307TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 308 MOVW 4(R0), R1 // arg 2 cmd 309 MOVW 8(R0), R2 // arg 3 arg 310 MOVW 0(R0), R0 // arg 1 fd 311 BL libc_fcntl(SB) 312 RET 313 314// sigaltstack is not supported on iOS, so our sigtramp has 315// to do the stack switch ourselves. 316TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 317 MOVW $43, R0 318 BL libc_exit(SB) 319 RET 320 321// Thread related functions 322// Note: On darwin/arm, the runtime always use runtime/cgo to 323// create threads, so all thread related functions will just exit with a 324// unique status. 325 326TEXT runtime·mstart_stub(SB),NOSPLIT,$0 327 MOVW $44, R0 328 BL libc_exit(SB) 329 RET 330 331TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 332 MOVW $45, R0 333 BL libc_exit(SB) 334 RET 335 336TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 337 MOVW $46, R0 338 BL libc_exit(SB) 339 RET 340 341TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 342 MOVW $47, R0 343 BL libc_exit(SB) 344 RET 345 346TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 347 MOVW $48, R0 348 BL libc_exit(SB) 349 RET 350 351TEXT runtime·raise_trampoline(SB),NOSPLIT,$0 352 MOVW 0(R0), R0 // arg 1 sig 353 BL libc_raise(SB) 354 RET 355 356TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0 357 MOVW 4(R0), R1 // arg 2 attr 358 MOVW 0(R0), R0 // arg 1 mutex 359 BL libc_pthread_mutex_init(SB) 360 RET 361 362TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0 363 MOVW 0(R0), R0 // arg 1 mutex 364 BL libc_pthread_mutex_lock(SB) 365 RET 366 367TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0 368 MOVW 0(R0), R0 // arg 1 mutex 369 BL libc_pthread_mutex_unlock(SB) 370 RET 371 372TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0 373 MOVW 4(R0), R1 // arg 2 attr 374 MOVW 0(R0), R0 // arg 1 cond 375 BL libc_pthread_cond_init(SB) 376 RET 377 378TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0 379 MOVW 4(R0), R1 // arg 2 mutex 380 MOVW 0(R0), R0 // arg 1 cond 381 BL libc_pthread_cond_wait(SB) 382 RET 383 384TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0 385 MOVW 4(R0), R1 // arg 2 mutex 386 MOVW 8(R0), R2 // arg 3 timeout 387 MOVW 0(R0), R0 // arg 1 cond 388 BL libc_pthread_cond_timedwait_relative_np(SB) 389 RET 390 391TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0 392 MOVW 0(R0), R0 // arg 1 cond 393 BL libc_pthread_cond_signal(SB) 394 RET 395 396TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0 397 MOVW R0, R4 // R4 is callee-save 398 BL libc_pthread_self(SB) 399 MOVW R0, 0(R4) // return value 400 RET 401 402TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0 403 MOVW 4(R0), R1 // arg 2 sig 404 MOVW 0(R0), R0 // arg 1 thread 405 BL libc_pthread_kill(SB) 406 RET 407 408// syscall calls a function in libc on behalf of the syscall package. 409// syscall takes a pointer to a struct like: 410// struct { 411// fn uintptr 412// a1 uintptr 413// a2 uintptr 414// a3 uintptr 415// r1 uintptr 416// r2 uintptr 417// err uintptr 418// } 419// syscall must be called on the g0 stack with the 420// C calling convention (use libcCall). 421TEXT runtime·syscall(SB),NOSPLIT,$0 422 MOVW.W R0, -4(R13) // push structure pointer 423 MOVW 0(R0), R12 // fn 424 MOVW 8(R0), R1 // a2 425 MOVW 12(R0), R2 // a3 426 MOVW 4(R0), R0 // a1 427 BL (R12) 428 MOVW.P 4(R13), R2 // pop structure pointer 429 MOVW R0, 16(R2) // save r1 430 MOVW R1, 20(R2) // save r2 431 MOVW $-1, R3 432 CMP R0, R3 433 BNE ok 434 MOVW.W R2, -4(R13) // push structure pointer 435 BL libc_error(SB) 436 MOVW (R0), R0 437 MOVW.P 4(R13), R2 // pop structure pointer 438 MOVW R0, 24(R2) // save err 439ok: 440 RET 441 442// syscallPtr is like syscall except the libc function reports an 443// error by returning NULL and setting errno. 444TEXT runtime·syscallPtr(SB),NOSPLIT,$0 445 MOVW.W R0, -4(R13) // push structure pointer 446 MOVW 0(R0), R12 // fn 447 MOVW 8(R0), R1 // a2 448 MOVW 12(R0), R2 // a3 449 MOVW 4(R0), R0 // a1 450 BL (R12) 451 MOVW.P 4(R13), R2 // pop structure pointer 452 MOVW R0, 16(R2) // save r1 453 MOVW R1, 20(R2) // save r2 454 MOVW $0, R3 455 CMP R0, R3 456 BNE ok 457 MOVW.W R2, -4(R13) // push structure pointer 458 BL libc_error(SB) 459 MOVW (R0), R0 460 MOVW.P 4(R13), R2 // pop structure pointer 461 MOVW R0, 24(R2) // save err 462ok: 463 RET 464 465// syscall6 calls a function in libc on behalf of the syscall package. 466// syscall6 takes a pointer to a struct like: 467// struct { 468// fn uintptr 469// a1 uintptr 470// a2 uintptr 471// a3 uintptr 472// a4 uintptr 473// a5 uintptr 474// a6 uintptr 475// r1 uintptr 476// r2 uintptr 477// err uintptr 478// } 479// syscall6 must be called on the g0 stack with the 480// C calling convention (use libcCall). 481TEXT runtime·syscall6(SB),NOSPLIT,$0 482 MOVW.W R0, -4(R13) // push structure pointer 483 MOVW 0(R0), R12 // fn 484 MOVW 24(R0), R1 // a6 485 MOVW.W R1, -4(R13) 486 MOVW 20(R0), R1 // a5 487 MOVW.W R1, -4(R13) 488 MOVW 8(R0), R1 // a2 489 MOVW 12(R0), R2 // a3 490 MOVW 16(R0), R3 // a4 491 MOVW 4(R0), R0 // a1 492 BL (R12) 493 ADD $8, R13 494 MOVW.P 4(R13), R2 // pop structure pointer 495 MOVW R0, 28(R2) // save r1 496 MOVW R1, 32(R2) // save r2 497 MOVW $-1, R3 498 CMP R0, R3 499 BNE ok 500 MOVW.W R2, -4(R13) // push structure pointer 501 BL libc_error(SB) 502 MOVW (R0), R0 503 MOVW.P 4(R13), R2 // pop structure pointer 504 MOVW R0, 36(R2) // save err 505ok: 506 RET 507 508// syscall6X calls a function in libc on behalf of the syscall package. 509// syscall6X takes a pointer to a struct like: 510// struct { 511// fn uintptr 512// a1 uintptr 513// a2 uintptr 514// a3 uintptr 515// a4 uintptr 516// a5 uintptr 517// a6 uintptr 518// r1 uintptr 519// r2 uintptr 520// err uintptr 521// } 522// syscall6X must be called on the g0 stack with the 523// C calling convention (use libcCall). 524TEXT runtime·syscall6X(SB),NOSPLIT,$0 525 MOVW.W R0, -4(R13) // push structure pointer 526 MOVW 0(R0), R12 // fn 527 MOVW 24(R0), R1 // a6 528 MOVW.W R1, -4(R13) 529 MOVW 20(R0), R1 // a5 530 MOVW.W R1, -4(R13) 531 MOVW 8(R0), R1 // a2 532 MOVW 12(R0), R2 // a3 533 MOVW 16(R0), R3 // a4 534 MOVW 4(R0), R0 // a1 535 BL (R12) 536 ADD $8, R13 537 MOVW.P 4(R13), R2 // pop structure pointer 538 MOVW R0, 28(R2) // save r1 539 MOVW R1, 32(R2) // save r2 540 MOVW $-1, R3 541 CMP R0, R3 542 BNE ok 543 CMP R1, R3 544 BNE ok 545 MOVW.W R2, -4(R13) // push structure pointer 546 BL libc_error(SB) 547 MOVW (R0), R0 548 MOVW.P 4(R13), R2 // pop structure pointer 549 MOVW R0, 36(R2) // save err 550ok: 551 RET 552 553// syscall9 calls a function in libc on behalf of the syscall package. 554// syscall9 takes a pointer to a struct like: 555// struct { 556// fn uintptr 557// a1 uintptr 558// a2 uintptr 559// a3 uintptr 560// a4 uintptr 561// a5 uintptr 562// a6 uintptr 563// a7 uintptr 564// a8 uintptr 565// a9 uintptr 566// r1 uintptr 567// r2 uintptr 568// err uintptr 569// } 570// syscall9 must be called on the g0 stack with the 571// C calling convention (use libcCall). 572TEXT runtime·syscall9(SB),NOSPLIT,$0 573 MOVW.W R0, -4(R13) // push structure pointer 574 MOVW 0(R0), R12 // fn 575 MOVW 36(R0), R1 // a9 576 MOVW.W R1, -4(R13) 577 MOVW 32(R0), R1 // a8 578 MOVW.W R1, -4(R13) 579 MOVW 28(R0), R1 // a7 580 MOVW.W R1, -4(R13) 581 MOVW 24(R0), R1 // a6 582 MOVW.W R1, -4(R13) 583 MOVW 20(R0), R1 // a5 584 MOVW.W R1, -4(R13) 585 MOVW 8(R0), R1 // a2 586 MOVW 12(R0), R2 // a3 587 MOVW 16(R0), R3 // a4 588 MOVW 4(R0), R0 // a1 589 BL (R12) 590 ADD $20, R13 591 MOVW.P 4(R13), R2 // pop structure pointer 592 MOVW R0, 40(R2) // save r1 593 MOVW R1, 44(R2) // save r2 594 MOVW $-1, R3 595 CMP R0, R3 596 BNE ok 597 MOVW.W R2, -4(R13) // push structure pointer 598 BL libc_error(SB) 599 MOVW (R0), R0 600 MOVW.P 4(R13), R2 // pop structure pointer 601 MOVW R0, 48(R2) // save err 602ok: 603 RET 604