github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/sys_linux_arm.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 // 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 #define CLOCK_REALTIME 0 14 #define CLOCK_MONOTONIC 1 15 16 // for EABI, as we don't support OABI 17 #define SYS_BASE 0x0 18 19 #define SYS_exit (SYS_BASE + 1) 20 #define SYS_read (SYS_BASE + 3) 21 #define SYS_write (SYS_BASE + 4) 22 #define SYS_open (SYS_BASE + 5) 23 #define SYS_close (SYS_BASE + 6) 24 #define SYS_getpid (SYS_BASE + 20) 25 #define SYS_kill (SYS_BASE + 37) 26 #define SYS_clone (SYS_BASE + 120) 27 #define SYS_rt_sigreturn (SYS_BASE + 173) 28 #define SYS_rt_sigaction (SYS_BASE + 174) 29 #define SYS_rt_sigprocmask (SYS_BASE + 175) 30 #define SYS_sigaltstack (SYS_BASE + 186) 31 #define SYS_mmap2 (SYS_BASE + 192) 32 #define SYS_futex (SYS_BASE + 240) 33 #define SYS_exit_group (SYS_BASE + 248) 34 #define SYS_munmap (SYS_BASE + 91) 35 #define SYS_madvise (SYS_BASE + 220) 36 #define SYS_setitimer (SYS_BASE + 104) 37 #define SYS_mincore (SYS_BASE + 219) 38 #define SYS_gettid (SYS_BASE + 224) 39 #define SYS_tgkill (SYS_BASE + 268) 40 #define SYS_sched_yield (SYS_BASE + 158) 41 #define SYS_nanosleep (SYS_BASE + 162) 42 #define SYS_sched_getaffinity (SYS_BASE + 242) 43 #define SYS_clock_gettime (SYS_BASE + 263) 44 #define SYS_timer_create (SYS_BASE + 257) 45 #define SYS_timer_settime (SYS_BASE + 258) 46 #define SYS_timer_delete (SYS_BASE + 261) 47 #define SYS_pipe2 (SYS_BASE + 359) 48 #define SYS_access (SYS_BASE + 33) 49 #define SYS_connect (SYS_BASE + 283) 50 #define SYS_socket (SYS_BASE + 281) 51 #define SYS_brk (SYS_BASE + 45) 52 53 #define ARM_BASE (SYS_BASE + 0x0f0000) 54 55 TEXT runtime·open(SB),NOSPLIT,$0 56 MOVW name+0(FP), R0 57 MOVW mode+4(FP), R1 58 MOVW perm+8(FP), R2 59 MOVW $SYS_open, R7 60 SWI $0 61 MOVW $0xfffff001, R1 62 CMP R1, R0 63 MOVW.HI $-1, R0 64 MOVW R0, ret+12(FP) 65 RET 66 67 TEXT runtime·closefd(SB),NOSPLIT,$0 68 MOVW fd+0(FP), R0 69 MOVW $SYS_close, R7 70 SWI $0 71 MOVW $0xfffff001, R1 72 CMP R1, R0 73 MOVW.HI $-1, R0 74 MOVW R0, ret+4(FP) 75 RET 76 77 TEXT runtime·write1(SB),NOSPLIT,$0 78 MOVW fd+0(FP), R0 79 MOVW p+4(FP), R1 80 MOVW n+8(FP), R2 81 MOVW $SYS_write, R7 82 SWI $0 83 MOVW R0, ret+12(FP) 84 RET 85 86 TEXT runtime·read(SB),NOSPLIT,$0 87 MOVW fd+0(FP), R0 88 MOVW p+4(FP), R1 89 MOVW n+8(FP), R2 90 MOVW $SYS_read, R7 91 SWI $0 92 MOVW R0, ret+12(FP) 93 RET 94 95 // func pipe2(flags int32) (r, w int32, errno int32) 96 TEXT runtime·pipe2(SB),NOSPLIT,$0-16 97 MOVW $r+4(FP), R0 98 MOVW flags+0(FP), R1 99 MOVW $SYS_pipe2, R7 100 SWI $0 101 MOVW R0, errno+12(FP) 102 RET 103 104 TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0 105 MOVW code+0(FP), R0 106 MOVW $SYS_exit_group, R7 107 SWI $0 108 MOVW $1234, R0 109 MOVW $1002, R1 110 MOVW R0, (R1) // fail hard 111 112 TEXT exit1<>(SB),NOSPLIT|NOFRAME,$0 113 MOVW code+0(FP), R0 114 MOVW $SYS_exit, R7 115 SWI $0 116 MOVW $1234, R0 117 MOVW $1003, R1 118 MOVW R0, (R1) // fail hard 119 120 // func exitThread(wait *atomic.Uint32) 121 TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-4 122 MOVW wait+0(FP), R0 123 // We're done using the stack. 124 // Alas, there's no reliable way to make this write atomic 125 // without potentially using the stack. So it goes. 126 MOVW $0, R1 127 MOVW R1, (R0) 128 MOVW $0, R0 // exit code 129 MOVW $SYS_exit, R7 130 SWI $0 131 MOVW $1234, R0 132 MOVW $1004, R1 133 MOVW R0, (R1) // fail hard 134 JMP 0(PC) 135 136 TEXT runtime·gettid(SB),NOSPLIT,$0-4 137 MOVW $SYS_gettid, R7 138 SWI $0 139 MOVW R0, ret+0(FP) 140 RET 141 142 TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0 143 MOVW $SYS_getpid, R7 144 SWI $0 145 MOVW R0, R4 146 MOVW $SYS_gettid, R7 147 SWI $0 148 MOVW R0, R1 // arg 2 tid 149 MOVW R4, R0 // arg 1 pid 150 MOVW sig+0(FP), R2 // arg 3 151 MOVW $SYS_tgkill, R7 152 SWI $0 153 RET 154 155 TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0 156 MOVW $SYS_getpid, R7 157 SWI $0 158 // arg 1 tid already in R0 from getpid 159 MOVW sig+0(FP), R1 // arg 2 - signal 160 MOVW $SYS_kill, R7 161 SWI $0 162 RET 163 164 TEXT ·getpid(SB),NOSPLIT,$0-4 165 MOVW $SYS_getpid, R7 166 SWI $0 167 MOVW R0, ret+0(FP) 168 RET 169 170 TEXT ·tgkill(SB),NOSPLIT,$0-12 171 MOVW tgid+0(FP), R0 172 MOVW tid+4(FP), R1 173 MOVW sig+8(FP), R2 174 MOVW $SYS_tgkill, R7 175 SWI $0 176 RET 177 178 TEXT runtime·mmap(SB),NOSPLIT,$0 179 MOVW addr+0(FP), R0 180 MOVW n+4(FP), R1 181 MOVW prot+8(FP), R2 182 MOVW flags+12(FP), R3 183 MOVW fd+16(FP), R4 184 MOVW off+20(FP), R5 185 MOVW $SYS_mmap2, R7 186 SWI $0 187 MOVW $0xfffff001, R6 188 CMP R6, R0 189 MOVW $0, R1 190 RSB.HI $0, R0 191 MOVW.HI R0, R1 // if error, put in R1 192 MOVW.HI $0, R0 193 MOVW R0, p+24(FP) 194 MOVW R1, err+28(FP) 195 RET 196 197 TEXT runtime·munmap(SB),NOSPLIT,$0 198 MOVW addr+0(FP), R0 199 MOVW n+4(FP), R1 200 MOVW $SYS_munmap, R7 201 SWI $0 202 MOVW $0xfffff001, R6 203 CMP R6, R0 204 MOVW.HI $0, R8 // crash on syscall failure 205 MOVW.HI R8, (R8) 206 RET 207 208 TEXT runtime·madvise(SB),NOSPLIT,$0 209 MOVW addr+0(FP), R0 210 MOVW n+4(FP), R1 211 MOVW flags+8(FP), R2 212 MOVW $SYS_madvise, R7 213 SWI $0 214 MOVW R0, ret+12(FP) 215 RET 216 217 TEXT runtime·setitimer(SB),NOSPLIT,$0 218 MOVW mode+0(FP), R0 219 MOVW new+4(FP), R1 220 MOVW old+8(FP), R2 221 MOVW $SYS_setitimer, R7 222 SWI $0 223 RET 224 225 TEXT runtime·timer_create(SB),NOSPLIT,$0-16 226 MOVW clockid+0(FP), R0 227 MOVW sevp+4(FP), R1 228 MOVW timerid+8(FP), R2 229 MOVW $SYS_timer_create, R7 230 SWI $0 231 MOVW R0, ret+12(FP) 232 RET 233 234 TEXT runtime·timer_settime(SB),NOSPLIT,$0-20 235 MOVW timerid+0(FP), R0 236 MOVW flags+4(FP), R1 237 MOVW new+8(FP), R2 238 MOVW old+12(FP), R3 239 MOVW $SYS_timer_settime, R7 240 SWI $0 241 MOVW R0, ret+16(FP) 242 RET 243 244 TEXT runtime·timer_delete(SB),NOSPLIT,$0-8 245 MOVW timerid+0(FP), R0 246 MOVW $SYS_timer_delete, R7 247 SWI $0 248 MOVW R0, ret+4(FP) 249 RET 250 251 TEXT runtime·mincore(SB),NOSPLIT,$0 252 MOVW addr+0(FP), R0 253 MOVW n+4(FP), R1 254 MOVW dst+8(FP), R2 255 MOVW $SYS_mincore, R7 256 SWI $0 257 MOVW R0, ret+12(FP) 258 RET 259 260 // Call a VDSO function. 261 // 262 // R0-R3: arguments to VDSO function (C calling convention) 263 // R4: uintptr function to call 264 // 265 // There is no return value. 266 TEXT runtime·vdsoCall(SB),NOSPLIT,$8-0 267 // R0-R3 may be arguments to fn, do not touch. 268 // R4 is function to call. 269 // R5-R9 are available as locals. They are unchanged by the C call 270 // (callee-save). 271 272 // We don't know how much stack space the VDSO code will need, 273 // so switch to g0. 274 275 // Save old SP. Use R13 instead of SP to avoid linker rewriting the offsets. 276 MOVW R13, R5 277 278 MOVW g_m(g), R6 279 280 // Set vdsoPC and vdsoSP for SIGPROF traceback. 281 // Save the old values on stack and restore them on exit, 282 // so this function is reentrant. 283 MOVW m_vdsoPC(R6), R7 284 MOVW m_vdsoSP(R6), R8 285 MOVW R7, 4(R13) 286 MOVW R8, 8(R13) 287 288 MOVW $sp-4(FP), R7 // caller's SP 289 MOVW LR, m_vdsoPC(R6) 290 MOVW R7, m_vdsoSP(R6) 291 292 MOVW m_curg(R6), R7 293 294 CMP g, R7 // Only switch if on curg. 295 B.NE noswitch 296 297 MOVW m_g0(R6), R7 298 MOVW (g_sched+gobuf_sp)(R7), R13 // Set SP to g0 stack 299 300 noswitch: 301 BIC $0x7, R13 // Align for C code 302 303 // Store g on gsignal's stack, so if we receive a signal 304 // during VDSO code we can find the g. 305 306 // When using cgo, we already saved g on TLS, also don't save g here. 307 MOVB runtime·iscgo(SB), R7 308 CMP $0, R7 309 BNE nosaveg 310 // If we don't have a signal stack, we won't receive signal, so don't 311 // bother saving g. 312 MOVW m_gsignal(R6), R7 // g.m.gsignal 313 CMP $0, R7 314 BEQ nosaveg 315 // Don't save g if we are already on the signal stack, as we won't get 316 // a nested signal. 317 CMP g, R7 318 BEQ nosaveg 319 // If we don't have a signal stack, we won't receive signal, so don't 320 // bother saving g. 321 MOVW (g_stack+stack_lo)(R7), R7 // g.m.gsignal.stack.lo 322 CMP $0, R7 323 BEQ nosaveg 324 MOVW g, (R7) 325 326 BL (R4) 327 328 MOVW $0, R8 329 MOVW R8, (R7) // clear g slot 330 331 JMP finish 332 333 nosaveg: 334 BL (R4) 335 336 finish: 337 MOVW R5, R13 // Restore real SP 338 // Restore vdsoPC, vdsoSP 339 // We don't worry about being signaled between the two stores. 340 // If we are not in a signal handler, we'll restore vdsoSP to 0, 341 // and no one will care about vdsoPC. If we are in a signal handler, 342 // we cannot receive another signal. 343 MOVW 8(R13), R7 344 MOVW R7, m_vdsoSP(R6) 345 MOVW 4(R13), R7 346 MOVW R7, m_vdsoPC(R6) 347 RET 348 349 TEXT runtime·walltime(SB),NOSPLIT,$12-12 350 MOVW $CLOCK_REALTIME, R0 351 MOVW $spec-12(SP), R1 // timespec 352 353 MOVW runtime·vdsoClockgettimeSym(SB), R4 354 CMP $0, R4 355 B.EQ fallback 356 357 BL runtime·vdsoCall(SB) 358 359 JMP finish 360 361 fallback: 362 MOVW $SYS_clock_gettime, R7 363 SWI $0 364 365 finish: 366 MOVW sec-12(SP), R0 // sec 367 MOVW nsec-8(SP), R2 // nsec 368 369 MOVW R0, sec_lo+0(FP) 370 MOVW $0, R1 371 MOVW R1, sec_hi+4(FP) 372 MOVW R2, nsec+8(FP) 373 RET 374 375 // func nanotime1() int64 376 TEXT runtime·nanotime1(SB),NOSPLIT,$12-8 377 MOVW $CLOCK_MONOTONIC, R0 378 MOVW $spec-12(SP), R1 // timespec 379 380 MOVW runtime·vdsoClockgettimeSym(SB), R4 381 CMP $0, R4 382 B.EQ fallback 383 384 BL runtime·vdsoCall(SB) 385 386 JMP finish 387 388 fallback: 389 MOVW $SYS_clock_gettime, R7 390 SWI $0 391 392 finish: 393 MOVW sec-12(SP), R0 // sec 394 MOVW nsec-8(SP), R2 // nsec 395 396 MOVW $1000000000, R3 397 MULLU R0, R3, (R1, R0) 398 ADD.S R2, R0 399 ADC $0, R1 // Add carry bit to upper half. 400 401 MOVW R0, ret_lo+0(FP) 402 MOVW R1, ret_hi+4(FP) 403 404 RET 405 406 // int32 futex(int32 *uaddr, int32 op, int32 val, 407 // struct timespec *timeout, int32 *uaddr2, int32 val2); 408 TEXT runtime·futex(SB),NOSPLIT,$0 409 MOVW addr+0(FP), R0 410 MOVW op+4(FP), R1 411 MOVW val+8(FP), R2 412 MOVW ts+12(FP), R3 413 MOVW addr2+16(FP), R4 414 MOVW val3+20(FP), R5 415 MOVW $SYS_futex, R7 416 SWI $0 417 MOVW R0, ret+24(FP) 418 RET 419 420 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); 421 TEXT runtime·clone(SB),NOSPLIT,$0 422 MOVW flags+0(FP), R0 423 MOVW stk+4(FP), R1 424 MOVW $0, R2 // parent tid ptr 425 MOVW $0, R3 // tls_val 426 MOVW $0, R4 // child tid ptr 427 MOVW $0, R5 428 429 // Copy mp, gp, fn off parent stack for use by child. 430 MOVW $-16(R1), R1 431 MOVW mp+8(FP), R6 432 MOVW R6, 0(R1) 433 MOVW gp+12(FP), R6 434 MOVW R6, 4(R1) 435 MOVW fn+16(FP), R6 436 MOVW R6, 8(R1) 437 MOVW $1234, R6 438 MOVW R6, 12(R1) 439 440 MOVW $SYS_clone, R7 441 SWI $0 442 443 // In parent, return. 444 CMP $0, R0 445 BEQ 3(PC) 446 MOVW R0, ret+20(FP) 447 RET 448 449 // Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup' 450 NOP R13 // tell vet SP/R13 changed - stop checking offsets 451 MOVW 12(R13), R0 452 MOVW $1234, R1 453 CMP R0, R1 454 BEQ 2(PC) 455 BL runtime·abort(SB) 456 457 MOVW 0(R13), R8 // m 458 MOVW 4(R13), R0 // g 459 460 CMP $0, R8 461 BEQ nog 462 CMP $0, R0 463 BEQ nog 464 465 MOVW R0, g 466 MOVW R8, g_m(g) 467 468 // paranoia; check they are not nil 469 MOVW 0(R8), R0 470 MOVW 0(g), R0 471 472 BL runtime·emptyfunc(SB) // fault if stack check is wrong 473 474 // Initialize m->procid to Linux tid 475 MOVW $SYS_gettid, R7 476 SWI $0 477 MOVW g_m(g), R8 478 MOVW R0, m_procid(R8) 479 480 nog: 481 // Call fn 482 MOVW 8(R13), R0 483 MOVW $16(R13), R13 484 BL (R0) 485 486 // It shouldn't return. If it does, exit that thread. 487 SUB $16, R13 // restore the stack pointer to avoid memory corruption 488 MOVW $0, R0 489 MOVW R0, 4(R13) 490 BL exit1<>(SB) 491 492 MOVW $1234, R0 493 MOVW $1005, R1 494 MOVW R0, (R1) 495 496 TEXT runtime·sigaltstack(SB),NOSPLIT,$0 497 MOVW new+0(FP), R0 498 MOVW old+4(FP), R1 499 MOVW $SYS_sigaltstack, R7 500 SWI $0 501 MOVW $0xfffff001, R6 502 CMP R6, R0 503 MOVW.HI $0, R8 // crash on syscall failure 504 MOVW.HI R8, (R8) 505 RET 506 507 TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 508 MOVW sig+4(FP), R0 509 MOVW info+8(FP), R1 510 MOVW ctx+12(FP), R2 511 MOVW fn+0(FP), R11 512 MOVW R13, R4 513 SUB $24, R13 514 BIC $0x7, R13 // alignment for ELF ABI 515 BL (R11) 516 MOVW R4, R13 517 RET 518 519 TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$0 520 // Reserve space for callee-save registers and arguments. 521 MOVM.DB.W [R4-R11], (R13) 522 SUB $16, R13 523 524 // this might be called in external code context, 525 // where g is not set. 526 // first save R0, because runtime·load_g will clobber it 527 MOVW R0, 4(R13) 528 MOVB runtime·iscgo(SB), R0 529 CMP $0, R0 530 BL.NE runtime·load_g(SB) 531 532 MOVW R1, 8(R13) 533 MOVW R2, 12(R13) 534 MOVW $runtime·sigtrampgo(SB), R11 535 BL (R11) 536 537 // Restore callee-save registers. 538 ADD $16, R13 539 MOVM.IA.W (R13), [R4-R11] 540 541 RET 542 543 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 544 MOVW $runtime·sigtramp(SB), R11 545 B (R11) 546 547 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0 548 MOVW how+0(FP), R0 549 MOVW new+4(FP), R1 550 MOVW old+8(FP), R2 551 MOVW size+12(FP), R3 552 MOVW $SYS_rt_sigprocmask, R7 553 SWI $0 554 RET 555 556 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0 557 MOVW sig+0(FP), R0 558 MOVW new+4(FP), R1 559 MOVW old+8(FP), R2 560 MOVW size+12(FP), R3 561 MOVW $SYS_rt_sigaction, R7 562 SWI $0 563 MOVW R0, ret+16(FP) 564 RET 565 566 TEXT runtime·usleep(SB),NOSPLIT,$12 567 MOVW usec+0(FP), R0 568 CALL runtime·usplitR0(SB) 569 MOVW R0, 4(R13) 570 MOVW $1000, R0 // usec to nsec 571 MUL R0, R1 572 MOVW R1, 8(R13) 573 MOVW $4(R13), R0 574 MOVW $0, R1 575 MOVW $SYS_nanosleep, R7 576 SWI $0 577 RET 578 579 // As for cas, memory barriers are complicated on ARM, but the kernel 580 // provides a user helper. ARMv5 does not support SMP and has no 581 // memory barrier instruction at all. ARMv6 added SMP support and has 582 // a memory barrier, but it requires writing to a coprocessor 583 // register. ARMv7 introduced the DMB instruction, but it's expensive 584 // even on single-core devices. The kernel helper takes care of all of 585 // this for us. 586 587 TEXT kernelPublicationBarrier<>(SB),NOSPLIT,$0 588 // void __kuser_memory_barrier(void); 589 MOVW $0xffff0fa0, R11 590 CALL (R11) 591 RET 592 593 TEXT ·publicationBarrier(SB),NOSPLIT,$0 594 MOVB ·goarm(SB), R11 595 CMP $7, R11 596 BLT 2(PC) 597 JMP ·armPublicationBarrier(SB) 598 JMP kernelPublicationBarrier<>(SB) // extra layer so this function is leaf and no SP adjustment on GOARM=7 599 600 TEXT runtime·osyield(SB),NOSPLIT,$0 601 MOVW $SYS_sched_yield, R7 602 SWI $0 603 RET 604 605 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0 606 MOVW pid+0(FP), R0 607 MOVW len+4(FP), R1 608 MOVW buf+8(FP), R2 609 MOVW $SYS_sched_getaffinity, R7 610 SWI $0 611 MOVW R0, ret+12(FP) 612 RET 613 614 // b __kuser_get_tls @ 0xffff0fe0 615 TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0 616 MOVW $0xffff0fe0, R0 617 B (R0) 618 619 TEXT runtime·access(SB),NOSPLIT,$0 620 MOVW name+0(FP), R0 621 MOVW mode+4(FP), R1 622 MOVW $SYS_access, R7 623 SWI $0 624 MOVW R0, ret+8(FP) 625 RET 626 627 TEXT runtime·connect(SB),NOSPLIT,$0 628 MOVW fd+0(FP), R0 629 MOVW addr+4(FP), R1 630 MOVW len+8(FP), R2 631 MOVW $SYS_connect, R7 632 SWI $0 633 MOVW R0, ret+12(FP) 634 RET 635 636 TEXT runtime·socket(SB),NOSPLIT,$0 637 MOVW domain+0(FP), R0 638 MOVW typ+4(FP), R1 639 MOVW prot+8(FP), R2 640 MOVW $SYS_socket, R7 641 SWI $0 642 MOVW R0, ret+12(FP) 643 RET 644 645 // func sbrk0() uintptr 646 TEXT runtime·sbrk0(SB),NOSPLIT,$0-4 647 // Implemented as brk(NULL). 648 MOVW $0, R0 649 MOVW $SYS_brk, R7 650 SWI $0 651 MOVW R0, ret+0(FP) 652 RET