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 // 6 // System calls and other sys.stuff for arm, Linux 7 // 8 9 #include "go_asm.h" 10 #include "go_tls.h" 11 #include "textflag.h" 12 13 // for EABI, as we don't support OABI 14 #define SYS_BASE 0x0 15 16 #define SYS_exit (SYS_BASE + 1) 17 #define SYS_read (SYS_BASE + 3) 18 #define SYS_write (SYS_BASE + 4) 19 #define SYS_open (SYS_BASE + 5) 20 #define SYS_close (SYS_BASE + 6) 21 #define SYS_getpid (SYS_BASE + 20) 22 #define SYS_kill (SYS_BASE + 37) 23 #define SYS_gettimeofday (SYS_BASE + 78) 24 #define SYS_clone (SYS_BASE + 120) 25 #define SYS_rt_sigreturn (SYS_BASE + 173) 26 #define SYS_rt_sigaction (SYS_BASE + 174) 27 #define SYS_rt_sigprocmask (SYS_BASE + 175) 28 #define SYS_sigaltstack (SYS_BASE + 186) 29 #define SYS_mmap2 (SYS_BASE + 192) 30 #define SYS_futex (SYS_BASE + 240) 31 #define SYS_exit_group (SYS_BASE + 248) 32 #define SYS_munmap (SYS_BASE + 91) 33 #define SYS_madvise (SYS_BASE + 220) 34 #define SYS_setitimer (SYS_BASE + 104) 35 #define SYS_mincore (SYS_BASE + 219) 36 #define SYS_gettid (SYS_BASE + 224) 37 #define SYS_tkill (SYS_BASE + 238) 38 #define SYS_sched_yield (SYS_BASE + 158) 39 #define SYS_select (SYS_BASE + 142) // newselect 40 #define SYS_ugetrlimit (SYS_BASE + 191) 41 #define SYS_sched_getaffinity (SYS_BASE + 242) 42 #define SYS_clock_gettime (SYS_BASE + 263) 43 #define SYS_epoll_create (SYS_BASE + 250) 44 #define SYS_epoll_ctl (SYS_BASE + 251) 45 #define SYS_epoll_wait (SYS_BASE + 252) 46 #define SYS_epoll_create1 (SYS_BASE + 357) 47 #define SYS_fcntl (SYS_BASE + 55) 48 #define SYS_access (SYS_BASE + 33) 49 #define SYS_connect (SYS_BASE + 283) 50 #define SYS_socket (SYS_BASE + 281) 51 52 #define ARM_BASE (SYS_BASE + 0x0f0000) 53 54 TEXT runtimeopen(SB),NOSPLIT,$0 55 MOVW name+0(FP), R0 56 MOVW mode+4(FP), R1 57 MOVW perm+8(FP), R2 58 MOVW $SYS_open, R7 59 SWI $0 60 MOVW $0xfffff001, R1 61 CMP R1, R0 62 MOVW.HI $-1, R0 63 MOVW R0, ret+12(FP) 64 RET 65 66 TEXT runtimeclosefd(SB),NOSPLIT,$0 67 MOVW fd+0(FP), R0 68 MOVW $SYS_close, R7 69 SWI $0 70 MOVW $0xfffff001, R1 71 CMP R1, R0 72 MOVW.HI $-1, R0 73 MOVW R0, ret+4(FP) 74 RET 75 76 TEXT runtimewrite(SB),NOSPLIT,$0 77 MOVW fd+0(FP), R0 78 MOVW p+4(FP), R1 79 MOVW n+8(FP), R2 80 MOVW $SYS_write, R7 81 SWI $0 82 MOVW $0xfffff001, R1 83 CMP R1, R0 84 MOVW.HI $-1, R0 85 MOVW R0, ret+12(FP) 86 RET 87 88 TEXT runtimeread(SB),NOSPLIT,$0 89 MOVW fd+0(FP), R0 90 MOVW p+4(FP), R1 91 MOVW n+8(FP), R2 92 MOVW $SYS_read, R7 93 SWI $0 94 MOVW $0xfffff001, R1 95 CMP R1, R0 96 MOVW.HI $-1, R0 97 MOVW R0, ret+12(FP) 98 RET 99 100 TEXT runtimegetrlimit(SB),NOSPLIT,$0 101 MOVW kind+0(FP), R0 102 MOVW limit+4(FP), R1 103 MOVW $SYS_ugetrlimit, R7 104 SWI $0 105 MOVW R0, ret+8(FP) 106 RET 107 108 TEXT runtimeexit(SB),NOSPLIT,$-4 109 MOVW code+0(FP), R0 110 MOVW $SYS_exit_group, R7 111 SWI $0 112 MOVW $1234, R0 113 MOVW $1002, R1 114 MOVW R0, (R1) // fail hard 115 116 TEXT runtimeexit1(SB),NOSPLIT,$-4 117 MOVW code+0(FP), R0 118 MOVW $SYS_exit, R7 119 SWI $0 120 MOVW $1234, R0 121 MOVW $1003, R1 122 MOVW R0, (R1) // fail hard 123 124 TEXT runtimegettid(SB),NOSPLIT,$0-4 125 MOVW $SYS_gettid, R7 126 SWI $0 127 MOVW R0, ret+0(FP) 128 RET 129 130 TEXT runtimeraise(SB),NOSPLIT,$-4 131 MOVW $SYS_gettid, R7 132 SWI $0 133 // arg 1 tid already in R0 from gettid 134 MOVW sig+0(FP), R1 // arg 2 - signal 135 MOVW $SYS_tkill, R7 136 SWI $0 137 RET 138 139 TEXT runtimeraiseproc(SB),NOSPLIT,$-4 140 MOVW $SYS_getpid, R7 141 SWI $0 142 // arg 1 tid already in R0 from getpid 143 MOVW sig+0(FP), R1 // arg 2 - signal 144 MOVW $SYS_kill, R7 145 SWI $0 146 RET 147 148 TEXT runtimemmap(SB),NOSPLIT,$0 149 MOVW addr+0(FP), R0 150 MOVW n+4(FP), R1 151 MOVW prot+8(FP), R2 152 MOVW flags+12(FP), R3 153 MOVW fd+16(FP), R4 154 MOVW off+20(FP), R5 155 MOVW $SYS_mmap2, R7 156 SWI $0 157 MOVW $0xfffff001, R6 158 CMP R6, R0 159 RSB.HI $0, R0 160 MOVW R0, ret+24(FP) 161 RET 162 163 TEXT runtimemunmap(SB),NOSPLIT,$0 164 MOVW addr+0(FP), R0 165 MOVW n+4(FP), R1 166 MOVW $SYS_munmap, R7 167 SWI $0 168 MOVW $0xfffff001, R6 169 CMP R6, R0 170 MOVW.HI $0, R8 // crash on syscall failure 171 MOVW.HI R8, (R8) 172 RET 173 174 TEXT runtimemadvise(SB),NOSPLIT,$0 175 MOVW addr+0(FP), R0 176 MOVW n+4(FP), R1 177 MOVW flags+8(FP), R2 178 MOVW $SYS_madvise, R7 179 SWI $0 180 // ignore failure - maybe pages are locked 181 RET 182 183 TEXT runtimesetitimer(SB),NOSPLIT,$0 184 MOVW mode+0(FP), R0 185 MOVW new+4(FP), R1 186 MOVW old+8(FP), R2 187 MOVW $SYS_setitimer, R7 188 SWI $0 189 RET 190 191 TEXT runtimemincore(SB),NOSPLIT,$0 192 MOVW addr+0(FP), R0 193 MOVW n+4(FP), R1 194 MOVW dst+8(FP), R2 195 MOVW $SYS_mincore, R7 196 SWI $0 197 MOVW R0, ret+12(FP) 198 RET 199 200 TEXT timenow(SB), NOSPLIT, $32 201 MOVW $0, R0 // CLOCK_REALTIME 202 MOVW $8(R13), R1 // timespec 203 MOVW $SYS_clock_gettime, R7 204 SWI $0 205 206 MOVW 8(R13), R0 // sec 207 MOVW 12(R13), R2 // nsec 208 209 MOVW R0, sec+0(FP) 210 MOVW $0, R1 211 MOVW R1, loc+4(FP) 212 MOVW R2, nsec+8(FP) 213 RET 214 215 // int64 nanotime(void) 216 TEXT runtimenanotime(SB),NOSPLIT,$32 217 MOVW $1, R0 // CLOCK_MONOTONIC 218 MOVW $8(R13), R1 // timespec 219 MOVW $SYS_clock_gettime, R7 220 SWI $0 221 222 MOVW 8(R13), R0 // sec 223 MOVW 12(R13), R2 // nsec 224 225 MOVW $1000000000, R3 226 MULLU R0, R3, (R1, R0) 227 MOVW $0, R4 228 ADD.S R2, R0 229 ADC R4, R1 230 231 MOVW R0, ret_lo+0(FP) 232 MOVW R1, ret_hi+4(FP) 233 RET 234 235 // int32 futex(int32 *uaddr, int32 op, int32 val, 236 // struct timespec *timeout, int32 *uaddr2, int32 val2); 237 TEXT runtimefutex(SB),NOSPLIT,$0 238 // TODO: Rewrite to use FP references. Vet complains. 239 MOVW 4(R13), R0 240 MOVW 8(R13), R1 241 MOVW 12(R13), R2 242 MOVW 16(R13), R3 243 MOVW 20(R13), R4 244 MOVW 24(R13), R5 245 MOVW $SYS_futex, R7 246 SWI $0 247 MOVW R0, ret+24(FP) 248 RET 249 250 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); 251 TEXT runtimeclone(SB),NOSPLIT,$0 252 MOVW flags+0(FP), R0 253 MOVW stk+4(FP), R1 254 MOVW $0, R2 // parent tid ptr 255 MOVW $0, R3 // tls_val 256 MOVW $0, R4 // child tid ptr 257 MOVW $0, R5 258 259 // Copy mp, gp, fn off parent stack for use by child. 260 // TODO(kaib): figure out which registers are clobbered by clone and avoid stack copying 261 MOVW $-16(R1), R1 262 MOVW mm+8(FP), R6 263 MOVW R6, 0(R1) 264 MOVW gg+12(FP), R6 265 MOVW R6, 4(R1) 266 MOVW fn+16(FP), R6 267 MOVW R6, 8(R1) 268 MOVW $1234, R6 269 MOVW R6, 12(R1) 270 271 MOVW $SYS_clone, R7 272 SWI $0 273 274 // In parent, return. 275 CMP $0, R0 276 BEQ 3(PC) 277 MOVW R0, ret+20(FP) 278 RET 279 280 // Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup' 281 MOVW 12(R13), R0 282 MOVW $1234, R1 283 CMP R0, R1 284 BEQ 2(PC) 285 BL runtimeabort(SB) 286 287 MOVW 0(R13), R8 // m 288 MOVW 4(R13), R0 // g 289 290 CMP $0, R8 291 BEQ nog 292 CMP $0, R0 293 BEQ nog 294 295 MOVW R0, g 296 MOVW R8, g_m(g) 297 298 // paranoia; check they are not nil 299 MOVW 0(R8), R0 300 MOVW 0(g), R0 301 302 BL runtimeemptyfunc(SB) // fault if stack check is wrong 303 304 // Initialize m->procid to Linux tid 305 MOVW $SYS_gettid, R7 306 SWI $0 307 MOVW g_m(g), R8 308 MOVW R0, m_procid(R8) 309 310 nog: 311 // Call fn 312 MOVW 8(R13), R0 313 MOVW $16(R13), R13 314 BL (R0) 315 316 // It shouldn't return. If it does, exit that thread. 317 SUB $16, R13 // restore the stack pointer to avoid memory corruption 318 MOVW $0, R0 319 MOVW R0, 4(R13) 320 BL runtimeexit1(SB) 321 322 MOVW $1234, R0 323 MOVW $1005, R1 324 MOVW R0, (R1) 325 326 TEXT runtimesigaltstack(SB),NOSPLIT,$0 327 MOVW new+0(FP), R0 328 MOVW old+4(FP), R1 329 MOVW $SYS_sigaltstack, R7 330 SWI $0 331 MOVW $0xfffff001, R6 332 CMP R6, R0 333 MOVW.HI $0, R8 // crash on syscall failure 334 MOVW.HI R8, (R8) 335 RET 336 337 TEXT runtimesigfwd(SB),NOSPLIT,$0-16 338 MOVW sig+4(FP), R0 339 MOVW info+8(FP), R1 340 MOVW ctx+12(FP), R2 341 MOVW fn+0(FP), R11 342 BL (R11) 343 RET 344 345 TEXT runtimesigtramp(SB),NOSPLIT,$12 346 // this might be called in external code context, 347 // where g is not set. 348 // first save R0, because runtimeload_g will clobber it 349 MOVW R0, 4(R13) 350 MOVB runtimeiscgo(SB), R0 351 CMP $0, R0 352 BL.NE runtimeload_g(SB) 353 354 MOVW R1, 8(R13) 355 MOVW R2, 12(R13) 356 MOVW $runtimesigtrampgo(SB), R11 357 BL (R11) 358 RET 359 360 TEXT runtimertsigprocmask(SB),NOSPLIT,$0 361 MOVW sig+0(FP), R0 362 MOVW new+4(FP), R1 363 MOVW old+8(FP), R2 364 MOVW size+12(FP), R3 365 MOVW $SYS_rt_sigprocmask, R7 366 SWI $0 367 RET 368 369 TEXT runtimert_sigaction(SB),NOSPLIT,$0 370 MOVW sig+0(FP), R0 371 MOVW new+4(FP), R1 372 MOVW old+8(FP), R2 373 MOVW size+12(FP), R3 374 MOVW $SYS_rt_sigaction, R7 375 SWI $0 376 MOVW R0, ret+16(FP) 377 RET 378 379 TEXT runtimeusleep(SB),NOSPLIT,$12 380 MOVW usec+0(FP), R0 381 CALL runtimeusplitR0(SB) 382 MOVW R0, 4(R13) 383 MOVW R1, 8(R13) 384 MOVW $0, R0 385 MOVW $0, R1 386 MOVW $0, R2 387 MOVW $0, R3 388 MOVW $4(R13), R4 389 MOVW $SYS_select, R7 390 SWI $0 391 RET 392 393 // Use kernel version instead of native armcas in asm_arm.s. 394 // See ../sync/atomic/asm_linux_arm.s for details. 395 TEXT cas<>(SB),NOSPLIT,$0 396 MOVW $0xffff0fc0, R15 // R15 is hardware PC. 397 398 TEXT runtimecas(SB),NOSPLIT,$0 399 MOVW ptr+0(FP), R2 400 MOVW old+4(FP), R0 401 loop: 402 MOVW new+8(FP), R1 403 BL cas<>(SB) 404 BCC check 405 MOVW $1, R0 406 MOVB R0, ret+12(FP) 407 RET 408 check: 409 // Kernel lies; double-check. 410 MOVW ptr+0(FP), R2 411 MOVW old+4(FP), R0 412 MOVW 0(R2), R3 413 CMP R0, R3 414 BEQ loop 415 MOVW $0, R0 416 MOVB R0, ret+12(FP) 417 RET 418 419 TEXT runtimecasp1(SB),NOSPLIT,$0 420 B runtimecas(SB) 421 422 // As for cas, memory barriers are complicated on ARM, but the kernel 423 // provides a user helper. ARMv5 does not support SMP and has no 424 // memory barrier instruction at all. ARMv6 added SMP support and has 425 // a memory barrier, but it requires writing to a coprocessor 426 // register. ARMv7 introduced the DMB instruction, but it's expensive 427 // even on single-core devices. The kernel helper takes care of all of 428 // this for us. 429 430 TEXT publicationBarrier<>(SB),NOSPLIT,$0 431 // void __kuser_memory_barrier(void); 432 MOVW $0xffff0fa0, R15 // R15 is hardware PC. 433 434 TEXT publicationBarrier(SB),NOSPLIT,$0 435 BL publicationBarrier<>(SB) 436 RET 437 438 TEXT runtimeosyield(SB),NOSPLIT,$0 439 MOVW $SYS_sched_yield, R7 440 SWI $0 441 RET 442 443 TEXT runtimesched_getaffinity(SB),NOSPLIT,$0 444 MOVW pid+0(FP), R0 445 MOVW len+4(FP), R1 446 MOVW buf+8(FP), R2 447 MOVW $SYS_sched_getaffinity, R7 448 SWI $0 449 MOVW R0, ret+12(FP) 450 RET 451 452 // int32 runtimeepollcreate(int32 size) 453 TEXT runtimeepollcreate(SB),NOSPLIT,$0 454 MOVW size+0(FP), R0 455 MOVW $SYS_epoll_create, R7 456 SWI $0 457 MOVW R0, ret+4(FP) 458 RET 459 460 // int32 runtimeepollcreate1(int32 flags) 461 TEXT runtimeepollcreate1(SB),NOSPLIT,$0 462 MOVW flags+0(FP), R0 463 MOVW $SYS_epoll_create1, R7 464 SWI $0 465 MOVW R0, ret+4(FP) 466 RET 467 468 // func epollctl(epfd, op, fd int32, ev *epollEvent) int 469 TEXT runtimeepollctl(SB),NOSPLIT,$0 470 MOVW epfd+0(FP), R0 471 MOVW op+4(FP), R1 472 MOVW fd+8(FP), R2 473 MOVW ev+12(FP), R3 474 MOVW $SYS_epoll_ctl, R7 475 SWI $0 476 MOVW R0, ret+16(FP) 477 RET 478 479 // int32 runtimeepollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout) 480 TEXT runtimeepollwait(SB),NOSPLIT,$0 481 MOVW epfd+0(FP), R0 482 MOVW ev+4(FP), R1 483 MOVW nev+8(FP), R2 484 MOVW timeout+12(FP), R3 485 MOVW $SYS_epoll_wait, R7 486 SWI $0 487 MOVW R0, ret+16(FP) 488 RET 489 490 // void runtimecloseonexec(int32 fd) 491 TEXT runtimecloseonexec(SB),NOSPLIT,$0 492 MOVW fd+0(FP), R0 // fd 493 MOVW $2, R1 // F_SETFD 494 MOVW $1, R2 // FD_CLOEXEC 495 MOVW $SYS_fcntl, R7 496 SWI $0 497 RET 498 499 // b __kuser_get_tls @ 0xffff0fe0 500 TEXT runtimeread_tls_fallback(SB),NOSPLIT,$-4 501 MOVW $0xffff0fe0, R0 502 B (R0) 503 504 TEXT runtimeaccess(SB),NOSPLIT,$0 505 MOVW name+0(FP), R0 506 MOVW mode+4(FP), R1 507 MOVW $SYS_access, R7 508 SWI $0 509 MOVW R0, ret+8(FP) 510 RET 511 512 TEXT runtimeconnect(SB),NOSPLIT,$0 513 MOVW fd+0(FP), R0 514 MOVW addr+4(FP), R1 515 MOVW addrlen+8(FP), R2 516 MOVW $SYS_connect, R7 517 SWI $0 518 MOVW R0, ret+12(FP) 519 RET 520 521 TEXT runtimesocket(SB),NOSPLIT,$0 522 MOVW domain+0(FP), R0 523 MOVW type+4(FP), R1 524 MOVW protocol+8(FP), R2 525 MOVW $SYS_socket, R7 526 SWI $0 527 MOVW R0, ret+12(FP) 528 RET 529