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 #include "go_asm.h" 6 #include "go_tls.h" 7 #include "funcdata.h" 8 #include "textflag.h" 9 10 // using frame size $-4 means do not save LR on stack. 11 TEXT runtimert0_go(SB),NOSPLIT,$-4 12 MOVW $0xcafebabe, R12 13 14 // copy arguments forward on an even stack 15 // use R13 instead of SP to avoid linker rewriting the offsets 16 MOVW 0(R13), R0 // argc 17 MOVW 4(R13), R1 // argv 18 SUB $64, R13 // plenty of scratch 19 AND $~7, R13 20 MOVW R0, 60(R13) // save argc, argv away 21 MOVW R1, 64(R13) 22 23 // set up g register 24 // g is R10 25 MOVW $runtimeg0(SB), g 26 MOVW $runtimem0(SB), R8 27 28 // save m->g0 = g0 29 MOVW g, m_g0(R8) 30 // save g->m = m0 31 MOVW R8, g_m(g) 32 33 // create istack out of the OS stack 34 MOVW $(-8192+104)(R13), R0 35 MOVW R0, g_stackguard0(g) 36 MOVW R0, g_stackguard1(g) 37 MOVW R0, (g_stack+stack_lo)(g) 38 MOVW R13, (g_stack+stack_hi)(g) 39 40 BL runtimeemptyfunc(SB) // fault if stack check is wrong 41 42 BL runtime_initcgo(SB) // will clobber R0-R3 43 44 // update stackguard after _cgo_init 45 MOVW (g_stack+stack_lo)(g), R0 46 ADD $const__StackGuard, R0 47 MOVW R0, g_stackguard0(g) 48 MOVW R0, g_stackguard1(g) 49 50 BL runtimecheck(SB) 51 52 // saved argc, argv 53 MOVW 60(R13), R0 54 MOVW R0, 4(R13) 55 MOVW 64(R13), R1 56 MOVW R1, 8(R13) 57 BL runtimeargs(SB) 58 BL runtimecheckgoarm(SB) 59 BL runtimeosinit(SB) 60 BL runtimeschedinit(SB) 61 62 // create a new goroutine to start program 63 MOVW $runtimemainPC(SB), R0 64 MOVW.W R0, -4(R13) 65 MOVW $8, R0 66 MOVW.W R0, -4(R13) 67 MOVW $0, R0 68 MOVW.W R0, -4(R13) // push $0 as guard 69 BL runtimenewproc(SB) 70 MOVW $12(R13), R13 // pop args and LR 71 72 // start this M 73 BL runtimemstart(SB) 74 75 MOVW $1234, R0 76 MOVW $1000, R1 77 MOVW R0, (R1) // fail hard 78 79 DATA runtimemainPC+0(SB)/4,$runtimemain(SB) 80 GLOBL runtimemainPC(SB),RODATA,$4 81 82 TEXT runtimebreakpoint(SB),NOSPLIT,$0-0 83 // gdb won't skip this breakpoint instruction automatically, 84 // so you must manually "set $pc+=4" to skip it and continue. 85 #ifdef GOOS_nacl 86 WORD $0xe125be7f // BKPT 0x5bef, NACL_INSTR_ARM_BREAKPOINT 87 #else 88 WORD $0xe7f001f0 // undefined instruction that gdb understands is a software breakpoint 89 #endif 90 RET 91 92 TEXT runtimeasminit(SB),NOSPLIT,$0-0 93 // disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5 94 MOVB runtimegoarm(SB), R11 95 CMP $5, R11 96 BLE 4(PC) 97 WORD $0xeef1ba10 // vmrs r11, fpscr 98 BIC $(1<<24), R11 99 WORD $0xeee1ba10 // vmsr fpscr, r11 100 RET 101 102 /* 103 * go-routine 104 */ 105 106 // void gosave(Gobuf*) 107 // save state in Gobuf; setjmp 108 TEXT runtimegosave(SB),NOSPLIT,$-4-4 109 MOVW buf+0(FP), R0 110 MOVW R13, gobuf_sp(R0) 111 MOVW LR, gobuf_pc(R0) 112 MOVW g, gobuf_g(R0) 113 MOVW $0, R11 114 MOVW R11, gobuf_lr(R0) 115 MOVW R11, gobuf_ret(R0) 116 MOVW R11, gobuf_ctxt(R0) 117 RET 118 119 // void gogo(Gobuf*) 120 // restore state from Gobuf; longjmp 121 TEXT runtimegogo(SB),NOSPLIT,$-4-4 122 MOVW buf+0(FP), R1 123 MOVW gobuf_g(R1), R0 124 BL setg<>(SB) 125 126 // NOTE: We updated g above, and we are about to update SP. 127 // Until LR and PC are also updated, the g/SP/LR/PC quadruple 128 // are out of sync and must not be used as the basis of a traceback. 129 // Sigprof skips the traceback when SP is not within g's bounds, 130 // and when the PC is inside this function, runtime.gogo. 131 // Since we are about to update SP, until we complete runtime.gogo 132 // we must not leave this function. In particular, no calls 133 // after this point: it must be straight-line code until the 134 // final B instruction. 135 // See large comment in sigprof for more details. 136 MOVW gobuf_sp(R1), R13 // restore SP==R13 137 MOVW gobuf_lr(R1), LR 138 MOVW gobuf_ret(R1), R0 139 MOVW gobuf_ctxt(R1), R7 140 MOVW $0, R11 141 MOVW R11, gobuf_sp(R1) // clear to help garbage collector 142 MOVW R11, gobuf_ret(R1) 143 MOVW R11, gobuf_lr(R1) 144 MOVW R11, gobuf_ctxt(R1) 145 MOVW gobuf_pc(R1), R11 146 CMP R11, R11 // set condition codes for == test, needed by stack split 147 B (R11) 148 149 // func mcall(fn func(*g)) 150 // Switch to m->g0's stack, call fn(g). 151 // Fn must never return. It should gogo(&g->sched) 152 // to keep running g. 153 TEXT runtimemcall(SB),NOSPLIT,$-4-4 154 // Save caller state in g->sched. 155 MOVW R13, (g_sched+gobuf_sp)(g) 156 MOVW LR, (g_sched+gobuf_pc)(g) 157 MOVW $0, R11 158 MOVW R11, (g_sched+gobuf_lr)(g) 159 MOVW g, (g_sched+gobuf_g)(g) 160 161 // Switch to m->g0 & its stack, call fn. 162 MOVW g, R1 163 MOVW g_m(g), R8 164 MOVW m_g0(R8), R0 165 BL setg<>(SB) 166 CMP g, R1 167 B.NE 2(PC) 168 B runtimebadmcall(SB) 169 MOVB runtimeiscgo(SB), R11 170 CMP $0, R11 171 BL.NE runtimesave_g(SB) 172 MOVW fn+0(FP), R0 173 MOVW (g_sched+gobuf_sp)(g), R13 174 SUB $8, R13 175 MOVW R1, 4(R13) 176 MOVW R0, R7 177 MOVW 0(R0), R0 178 BL (R0) 179 B runtimebadmcall2(SB) 180 RET 181 182 // systemstack_switch is a dummy routine that systemstack leaves at the bottom 183 // of the G stack. We need to distinguish the routine that 184 // lives at the bottom of the G stack from the one that lives 185 // at the top of the system stack because the one at the top of 186 // the system stack terminates the stack walk (see topofstack()). 187 TEXT runtimesystemstack_switch(SB),NOSPLIT,$0-0 188 MOVW $0, R0 189 BL (R0) // clobber lr to ensure push {lr} is kept 190 RET 191 192 // func systemstack(fn func()) 193 TEXT runtimesystemstack(SB),NOSPLIT,$0-4 194 MOVW fn+0(FP), R0 // R0 = fn 195 MOVW g_m(g), R1 // R1 = m 196 197 MOVW m_gsignal(R1), R2 // R2 = gsignal 198 CMP g, R2 199 B.EQ noswitch 200 201 MOVW m_g0(R1), R2 // R2 = g0 202 CMP g, R2 203 B.EQ noswitch 204 205 MOVW m_curg(R1), R3 206 CMP g, R3 207 B.EQ switch 208 209 // Bad: g is not gsignal, not g0, not curg. What is it? 210 // Hide call from linker nosplit analysis. 211 MOVW $runtimebadsystemstack(SB), R0 212 BL (R0) 213 214 switch: 215 // save our state in g->sched. Pretend to 216 // be systemstack_switch if the G stack is scanned. 217 MOVW $runtimesystemstack_switch(SB), R3 218 #ifdef GOOS_nacl 219 ADD $4, R3, R3 // get past nacl-insert bic instruction 220 #endif 221 ADD $4, R3, R3 // get past push {lr} 222 MOVW R3, (g_sched+gobuf_pc)(g) 223 MOVW R13, (g_sched+gobuf_sp)(g) 224 MOVW LR, (g_sched+gobuf_lr)(g) 225 MOVW g, (g_sched+gobuf_g)(g) 226 227 // switch to g0 228 MOVW R0, R5 229 MOVW R2, R0 230 BL setg<>(SB) 231 MOVW R5, R0 232 MOVW (g_sched+gobuf_sp)(R2), R3 233 // make it look like mstart called systemstack on g0, to stop traceback 234 SUB $4, R3, R3 235 MOVW $runtimemstart(SB), R4 236 MOVW R4, 0(R3) 237 MOVW R3, R13 238 239 // call target function 240 MOVW R0, R7 241 MOVW 0(R0), R0 242 BL (R0) 243 244 // switch back to g 245 MOVW g_m(g), R1 246 MOVW m_curg(R1), R0 247 BL setg<>(SB) 248 MOVW (g_sched+gobuf_sp)(g), R13 249 MOVW $0, R3 250 MOVW R3, (g_sched+gobuf_sp)(g) 251 RET 252 253 noswitch: 254 MOVW R0, R7 255 MOVW 0(R0), R0 256 BL (R0) 257 RET 258 259 /* 260 * support for morestack 261 */ 262 263 // Called during function prolog when more stack is needed. 264 // R1 frame size 265 // R3 prolog's LR 266 // NB. we do not save R0 because we've forced 5c to pass all arguments 267 // on the stack. 268 // using frame size $-4 means do not save LR on stack. 269 // 270 // The traceback routines see morestack on a g0 as being 271 // the top of a stack (for example, morestack calling newstack 272 // calling the scheduler calling newm calling gc), so we must 273 // record an argument size. For that purpose, it has no arguments. 274 TEXT runtimemorestack(SB),NOSPLIT,$-4-0 275 // Cannot grow scheduler stack (m->g0). 276 MOVW g_m(g), R8 277 MOVW m_g0(R8), R4 278 CMP g, R4 279 BL.EQ runtimeabort(SB) 280 281 // Cannot grow signal stack (m->gsignal). 282 MOVW m_gsignal(R8), R4 283 CMP g, R4 284 BL.EQ runtimeabort(SB) 285 286 // Called from f. 287 // Set g->sched to context in f. 288 MOVW R7, (g_sched+gobuf_ctxt)(g) 289 MOVW R13, (g_sched+gobuf_sp)(g) 290 MOVW LR, (g_sched+gobuf_pc)(g) 291 MOVW R3, (g_sched+gobuf_lr)(g) 292 293 // Called from f. 294 // Set m->morebuf to f's caller. 295 MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC 296 MOVW R13, (m_morebuf+gobuf_sp)(R8) // f's caller's SP 297 MOVW $4(R13), R3 // f's argument pointer 298 MOVW g, (m_morebuf+gobuf_g)(R8) 299 300 // Call newstack on m->g0's stack. 301 MOVW m_g0(R8), R0 302 BL setg<>(SB) 303 MOVW (g_sched+gobuf_sp)(g), R13 304 BL runtimenewstack(SB) 305 306 // Not reached, but make sure the return PC from the call to newstack 307 // is still in this function, and not the beginning of the next. 308 RET 309 310 TEXT runtimemorestack_noctxt(SB),NOSPLIT,$-4-0 311 MOVW $0, R7 312 B runtimemorestack(SB) 313 314 TEXT runtimestackBarrier(SB),NOSPLIT,$0 315 // We came here via a RET to an overwritten LR. 316 // R0 may be live. Other registers are available. 317 318 // Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal. 319 MOVW (g_stkbar+slice_array)(g), R4 320 MOVW g_stkbarPos(g), R5 321 MOVW $stkbar__size, R6 322 MUL R5, R6 323 ADD R4, R6 324 MOVW stkbar_savedLRVal(R6), R6 325 // Record that this stack barrier was hit. 326 ADD $1, R5 327 MOVW R5, g_stkbarPos(g) 328 // Jump to the original return PC. 329 B (R6) 330 331 // reflectcall: call a function with the given argument list 332 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32). 333 // we don't have variable-sized frames, so we use a small number 334 // of constant-sized-frame functions to encode a few bits of size in the pc. 335 // Caution: ugly multiline assembly macros in your future! 336 337 #define DISPATCH(NAME,MAXSIZE) \ 338 CMP $MAXSIZE, R0; \ 339 B.HI 3(PC); \ 340 MOVW $NAME(SB), R1; \ 341 B (R1) 342 343 TEXT reflectcall(SB), NOSPLIT, $0-0 344 B reflectcall(SB) 345 346 TEXT reflectcall(SB),NOSPLIT,$-4-20 347 MOVW argsize+12(FP), R0 348 DISPATCH(runtimecall16, 16) 349 DISPATCH(runtimecall32, 32) 350 DISPATCH(runtimecall64, 64) 351 DISPATCH(runtimecall128, 128) 352 DISPATCH(runtimecall256, 256) 353 DISPATCH(runtimecall512, 512) 354 DISPATCH(runtimecall1024, 1024) 355 DISPATCH(runtimecall2048, 2048) 356 DISPATCH(runtimecall4096, 4096) 357 DISPATCH(runtimecall8192, 8192) 358 DISPATCH(runtimecall16384, 16384) 359 DISPATCH(runtimecall32768, 32768) 360 DISPATCH(runtimecall65536, 65536) 361 DISPATCH(runtimecall131072, 131072) 362 DISPATCH(runtimecall262144, 262144) 363 DISPATCH(runtimecall524288, 524288) 364 DISPATCH(runtimecall1048576, 1048576) 365 DISPATCH(runtimecall2097152, 2097152) 366 DISPATCH(runtimecall4194304, 4194304) 367 DISPATCH(runtimecall8388608, 8388608) 368 DISPATCH(runtimecall16777216, 16777216) 369 DISPATCH(runtimecall33554432, 33554432) 370 DISPATCH(runtimecall67108864, 67108864) 371 DISPATCH(runtimecall134217728, 134217728) 372 DISPATCH(runtimecall268435456, 268435456) 373 DISPATCH(runtimecall536870912, 536870912) 374 DISPATCH(runtimecall1073741824, 1073741824) 375 MOVW $runtimebadreflectcall(SB), R1 376 B (R1) 377 378 #define CALLFN(NAME,MAXSIZE) \ 379 TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \ 380 NO_LOCAL_POINTERS; \ 381 /* copy arguments to stack */ \ 382 MOVW argptr+8(FP), R0; \ 383 MOVW argsize+12(FP), R2; \ 384 ADD $4, R13, R1; \ 385 CMP $0, R2; \ 386 B.EQ 5(PC); \ 387 MOVBU.P 1(R0), R5; \ 388 MOVBU.P R5, 1(R1); \ 389 SUB $1, R2, R2; \ 390 B -5(PC); \ 391 /* call function */ \ 392 MOVW f+4(FP), R7; \ 393 MOVW (R7), R0; \ 394 PCDATA $PCDATA_StackMapIndex, $0; \ 395 BL (R0); \ 396 /* copy return values back */ \ 397 MOVW argptr+8(FP), R0; \ 398 MOVW argsize+12(FP), R2; \ 399 MOVW retoffset+16(FP), R3; \ 400 ADD $4, R13, R1; \ 401 ADD R3, R1; \ 402 ADD R3, R0; \ 403 SUB R3, R2; \ 404 loop: \ 405 CMP $0, R2; \ 406 B.EQ end; \ 407 MOVBU.P 1(R1), R5; \ 408 MOVBU.P R5, 1(R0); \ 409 SUB $1, R2, R2; \ 410 B loop; \ 411 end: \ 412 /* execute write barrier updates */ \ 413 MOVW argtype+0(FP), R1; \ 414 MOVW argptr+8(FP), R0; \ 415 MOVW argsize+12(FP), R2; \ 416 MOVW retoffset+16(FP), R3; \ 417 MOVW R1, 4(R13); \ 418 MOVW R0, 8(R13); \ 419 MOVW R2, 12(R13); \ 420 MOVW R3, 16(R13); \ 421 BL runtimecallwritebarrier(SB); \ 422 RET 423 424 CALLFN(call16, 16) 425 CALLFN(call32, 32) 426 CALLFN(call64, 64) 427 CALLFN(call128, 128) 428 CALLFN(call256, 256) 429 CALLFN(call512, 512) 430 CALLFN(call1024, 1024) 431 CALLFN(call2048, 2048) 432 CALLFN(call4096, 4096) 433 CALLFN(call8192, 8192) 434 CALLFN(call16384, 16384) 435 CALLFN(call32768, 32768) 436 CALLFN(call65536, 65536) 437 CALLFN(call131072, 131072) 438 CALLFN(call262144, 262144) 439 CALLFN(call524288, 524288) 440 CALLFN(call1048576, 1048576) 441 CALLFN(call2097152, 2097152) 442 CALLFN(call4194304, 4194304) 443 CALLFN(call8388608, 8388608) 444 CALLFN(call16777216, 16777216) 445 CALLFN(call33554432, 33554432) 446 CALLFN(call67108864, 67108864) 447 CALLFN(call134217728, 134217728) 448 CALLFN(call268435456, 268435456) 449 CALLFN(call536870912, 536870912) 450 CALLFN(call1073741824, 1073741824) 451 452 // void jmpdefer(fn, sp); 453 // called from deferreturn. 454 // 1. grab stored LR for caller 455 // 2. sub 4 bytes to get back to BL deferreturn 456 // 3. B to fn 457 // TODO(rsc): Push things on stack and then use pop 458 // to load all registers simultaneously, so that a profiling 459 // interrupt can never see mismatched SP/LR/PC. 460 // (And double-check that pop is atomic in that way.) 461 TEXT runtimejmpdefer(SB),NOSPLIT,$0-8 462 MOVW 0(R13), LR 463 MOVW $-4(LR), LR // BL deferreturn 464 MOVW fv+0(FP), R7 465 MOVW argp+4(FP), R13 466 MOVW $-4(R13), R13 // SP is 4 below argp, due to saved LR 467 MOVW 0(R7), R1 468 B (R1) 469 470 // Save state of caller into g->sched. Smashes R11. 471 TEXT gosave<>(SB),NOSPLIT,$0 472 MOVW LR, (g_sched+gobuf_pc)(g) 473 MOVW R13, (g_sched+gobuf_sp)(g) 474 MOVW $0, R11 475 MOVW R11, (g_sched+gobuf_lr)(g) 476 MOVW R11, (g_sched+gobuf_ret)(g) 477 MOVW R11, (g_sched+gobuf_ctxt)(g) 478 RET 479 480 // func asmcgocall(fn, arg unsafe.Pointer) int32 481 // Call fn(arg) on the scheduler stack, 482 // aligned appropriately for the gcc ABI. 483 // See cgocall.go for more details. 484 TEXT asmcgocall(SB),NOSPLIT,$0-12 485 MOVW fn+0(FP), R1 486 MOVW arg+4(FP), R0 487 488 MOVW R13, R2 489 MOVW g, R4 490 491 // Figure out if we need to switch to m->g0 stack. 492 // We get called to create new OS threads too, and those 493 // come in on the m->g0 stack already. 494 MOVW g_m(g), R8 495 MOVW m_g0(R8), R3 496 CMP R3, g 497 BEQ g0 498 BL gosave<>(SB) 499 MOVW R0, R5 500 MOVW R3, R0 501 BL setg<>(SB) 502 MOVW R5, R0 503 MOVW (g_sched+gobuf_sp)(g), R13 504 505 // Now on a scheduling stack (a pthread-created stack). 506 g0: 507 SUB $24, R13 508 BIC $0x7, R13 // alignment for gcc ABI 509 MOVW R4, 20(R13) // save old g 510 MOVW (g_stack+stack_hi)(R4), R4 511 SUB R2, R4 512 MOVW R4, 16(R13) // save depth in stack (can't just save SP, as stack might be copied during a callback) 513 BL (R1) 514 515 // Restore registers, g, stack pointer. 516 MOVW R0, R5 517 MOVW 20(R13), R0 518 BL setg<>(SB) 519 MOVW (g_stack+stack_hi)(g), R1 520 MOVW 16(R13), R2 521 SUB R2, R1 522 MOVW R5, R0 523 MOVW R1, R13 524 525 MOVW R0, ret+8(FP) 526 RET 527 528 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize) 529 // Turn the fn into a Go func (by taking its address) and call 530 // cgocallback_gofunc. 531 TEXT runtimecgocallback(SB),NOSPLIT,$12-12 532 MOVW $fn+0(FP), R0 533 MOVW R0, 4(R13) 534 MOVW frame+4(FP), R0 535 MOVW R0, 8(R13) 536 MOVW framesize+8(FP), R0 537 MOVW R0, 12(R13) 538 MOVW $runtimecgocallback_gofunc(SB), R0 539 BL (R0) 540 RET 541 542 // cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize) 543 // See cgocall.go for more details. 544 TEXT cgocallback_gofunc(SB),NOSPLIT,$8-12 545 NO_LOCAL_POINTERS 546 547 // Load m and g from thread-local storage. 548 MOVB runtimeiscgo(SB), R0 549 CMP $0, R0 550 BL.NE runtimeload_g(SB) 551 552 // If g is nil, Go did not create the current thread. 553 // Call needm to obtain one for temporary use. 554 // In this case, we're running on the thread stack, so there's 555 // lots of space, but the linker doesn't know. Hide the call from 556 // the linker analysis by using an indirect call. 557 CMP $0, g 558 B.NE havem 559 MOVW g, savedm-4(SP) // g is zero, so is m. 560 MOVW $runtimeneedm(SB), R0 561 BL (R0) 562 563 // Set m->sched.sp = SP, so that if a panic happens 564 // during the function we are about to execute, it will 565 // have a valid SP to run on the g0 stack. 566 // The next few lines (after the havem label) 567 // will save this SP onto the stack and then write 568 // the same SP back to m->sched.sp. That seems redundant, 569 // but if an unrecovered panic happens, unwindm will 570 // restore the g->sched.sp from the stack location 571 // and then systemstack will try to use it. If we don't set it here, 572 // that restored SP will be uninitialized (typically 0) and 573 // will not be usable. 574 MOVW g_m(g), R8 575 MOVW m_g0(R8), R3 576 MOVW R13, (g_sched+gobuf_sp)(R3) 577 578 havem: 579 MOVW g_m(g), R8 580 MOVW R8, savedm-4(SP) 581 // Now there's a valid m, and we're running on its m->g0. 582 // Save current m->g0->sched.sp on stack and then set it to SP. 583 // Save current sp in m->g0->sched.sp in preparation for 584 // switch back to m->curg stack. 585 // NOTE: unwindm knows that the saved g->sched.sp is at 4(R13) aka savedsp-8(SP). 586 MOVW m_g0(R8), R3 587 MOVW (g_sched+gobuf_sp)(R3), R4 588 MOVW R4, savedsp-8(SP) 589 MOVW R13, (g_sched+gobuf_sp)(R3) 590 591 // Switch to m->curg stack and call runtime.cgocallbackg. 592 // Because we are taking over the execution of m->curg 593 // but *not* resuming what had been running, we need to 594 // save that information (m->curg->sched) so we can restore it. 595 // We can restore m->curg->sched.sp easily, because calling 596 // runtime.cgocallbackg leaves SP unchanged upon return. 597 // To save m->curg->sched.pc, we push it onto the stack. 598 // This has the added benefit that it looks to the traceback 599 // routine like cgocallbackg is going to return to that 600 // PC (because the frame we allocate below has the same 601 // size as cgocallback_gofunc's frame declared above) 602 // so that the traceback will seamlessly trace back into 603 // the earlier calls. 604 // 605 // In the new goroutine, -8(SP) and -4(SP) are unused. 606 MOVW m_curg(R8), R0 607 BL setg<>(SB) 608 MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 609 MOVW (g_sched+gobuf_pc)(g), R5 610 MOVW R5, -12(R4) 611 MOVW $-12(R4), R13 612 BL runtimecgocallbackg(SB) 613 614 // Restore g->sched (== m->curg->sched) from saved values. 615 MOVW 0(R13), R5 616 MOVW R5, (g_sched+gobuf_pc)(g) 617 MOVW $12(R13), R4 618 MOVW R4, (g_sched+gobuf_sp)(g) 619 620 // Switch back to m->g0's stack and restore m->g0->sched.sp. 621 // (Unlike m->curg, the g0 goroutine never uses sched.pc, 622 // so we do not have to restore it.) 623 MOVW g_m(g), R8 624 MOVW m_g0(R8), R0 625 BL setg<>(SB) 626 MOVW (g_sched+gobuf_sp)(g), R13 627 MOVW savedsp-8(SP), R4 628 MOVW R4, (g_sched+gobuf_sp)(g) 629 630 // If the m on entry was nil, we called needm above to borrow an m 631 // for the duration of the call. Since the call is over, return it with dropm. 632 MOVW savedm-4(SP), R6 633 CMP $0, R6 634 B.NE 3(PC) 635 MOVW $runtimedropm(SB), R0 636 BL (R0) 637 638 // Done! 639 RET 640 641 // void setg(G*); set g. for use by needm. 642 TEXT runtimesetg(SB),NOSPLIT,$-4-4 643 MOVW gg+0(FP), R0 644 B setg<>(SB) 645 646 TEXT setg<>(SB),NOSPLIT,$-4-0 647 MOVW R0, g 648 649 // Save g to thread-local storage. 650 MOVB runtimeiscgo(SB), R0 651 CMP $0, R0 652 B.EQ 2(PC) 653 B runtimesave_g(SB) 654 655 MOVW g, R0 656 RET 657 658 TEXT runtimegetcallerpc(SB),NOSPLIT,$4-8 659 MOVW 8(R13), R0 // LR saved by caller 660 MOVW runtimestackBarrierPC(SB), R1 661 CMP R0, R1 662 BNE nobar 663 // Get original return PC. 664 BL runtimenextBarrierPC(SB) 665 MOVW 4(R13), R0 666 nobar: 667 MOVW R0, ret+4(FP) 668 RET 669 670 TEXT runtimesetcallerpc(SB),NOSPLIT,$4-8 671 MOVW pc+4(FP), R0 672 MOVW 8(R13), R1 673 MOVW runtimestackBarrierPC(SB), R2 674 CMP R1, R2 675 BEQ setbar 676 MOVW R0, 8(R13) // set LR in caller 677 RET 678 setbar: 679 // Set the stack barrier return PC. 680 MOVW R0, 4(R13) 681 BL runtimesetNextBarrierPC(SB) 682 RET 683 684 TEXT runtimegetcallersp(SB),NOSPLIT,$-4-8 685 MOVW argp+0(FP), R0 686 MOVW $-4(R0), R0 687 MOVW R0, ret+4(FP) 688 RET 689 690 TEXT runtimeemptyfunc(SB),0,$0-0 691 RET 692 693 TEXT runtimeabort(SB),NOSPLIT,$-4-0 694 MOVW $0, R0 695 MOVW (R0), R1 696 697 // bool armcas(int32 *val, int32 old, int32 new) 698 // Atomically: 699 // if(*val == old){ 700 // *val = new; 701 // return 1; 702 // }else 703 // return 0; 704 // 705 // To implement runtimecas in sys_$GOOS_arm.s 706 // using the native instructions, use: 707 // 708 // TEXT runtimecas(SB),NOSPLIT,$0 709 // B runtimearmcas(SB) 710 // 711 TEXT runtimearmcas(SB),NOSPLIT,$0-13 712 MOVW valptr+0(FP), R1 713 MOVW old+4(FP), R2 714 MOVW new+8(FP), R3 715 casl: 716 LDREX (R1), R0 717 CMP R0, R2 718 BNE casfail 719 720 MOVB runtimegoarm(SB), R11 721 CMP $7, R11 722 BLT 2(PC) 723 WORD $0xf57ff05a // dmb ishst 724 725 STREX R3, (R1), R0 726 CMP $0, R0 727 BNE casl 728 MOVW $1, R0 729 730 MOVB runtimegoarm(SB), R11 731 CMP $7, R11 732 BLT 2(PC) 733 WORD $0xf57ff05b // dmb ish 734 735 MOVB R0, ret+12(FP) 736 RET 737 casfail: 738 MOVW $0, R0 739 MOVB R0, ret+12(FP) 740 RET 741 742 TEXT runtimecasuintptr(SB),NOSPLIT,$0-13 743 B runtimecas(SB) 744 745 TEXT runtimeatomicloaduintptr(SB),NOSPLIT,$0-8 746 B runtimeatomicload(SB) 747 748 TEXT runtimeatomicloaduint(SB),NOSPLIT,$0-8 749 B runtimeatomicload(SB) 750 751 TEXT runtimeatomicstoreuintptr(SB),NOSPLIT,$0-8 752 B runtimeatomicstore(SB) 753 754 // armPublicationBarrier is a native store/store barrier for ARMv7+. 755 // On earlier ARM revisions, armPublicationBarrier is a no-op. 756 // This will not work on SMP ARMv6 machines, if any are in use. 757 // To implement publiationBarrier in sys_$GOOS_arm.s using the native 758 // instructions, use: 759 // 760 // TEXT publicationBarrier(SB),NOSPLIT,$-4-0 761 // B runtimearmPublicationBarrier(SB) 762 // 763 TEXT runtimearmPublicationBarrier(SB),NOSPLIT,$-4-0 764 MOVB runtimegoarm(SB), R11 765 CMP $7, R11 766 BLT 2(PC) 767 WORD $0xf57ff05e // DMB ST 768 RET 769 770 // AES hashing not implemented for ARM 771 TEXT runtimeaeshash(SB),NOSPLIT,$-4-0 772 MOVW $0, R0 773 MOVW (R0), R1 774 TEXT runtimeaeshash32(SB),NOSPLIT,$-4-0 775 MOVW $0, R0 776 MOVW (R0), R1 777 TEXT runtimeaeshash64(SB),NOSPLIT,$-4-0 778 MOVW $0, R0 779 MOVW (R0), R1 780 TEXT runtimeaeshashstr(SB),NOSPLIT,$-4-0 781 MOVW $0, R0 782 MOVW (R0), R1 783 784 // memhash_varlen(p unsafe.Pointer, h seed) uintptr 785 // redirects to memhash(p, h, size) using the size 786 // stored in the closure. 787 TEXT runtimememhash_varlen(SB),NOSPLIT,$16-12 788 GO_ARGS 789 NO_LOCAL_POINTERS 790 MOVW p+0(FP), R0 791 MOVW h+4(FP), R1 792 MOVW 4(R7), R2 793 MOVW R0, 4(R13) 794 MOVW R1, 8(R13) 795 MOVW R2, 12(R13) 796 BL runtimememhash(SB) 797 MOVW 16(R13), R0 798 MOVW R0, ret+8(FP) 799 RET 800 801 TEXT runtimememeq(SB),NOSPLIT,$-4-13 802 MOVW a+0(FP), R1 803 MOVW b+4(FP), R2 804 MOVW size+8(FP), R3 805 ADD R1, R3, R6 806 MOVW $1, R0 807 MOVB R0, ret+12(FP) 808 loop: 809 CMP R1, R6 810 RET.EQ 811 MOVBU.P 1(R1), R4 812 MOVBU.P 1(R2), R5 813 CMP R4, R5 814 BEQ loop 815 816 MOVW $0, R0 817 MOVB R0, ret+12(FP) 818 RET 819 820 // memequal_varlen(a, b unsafe.Pointer) bool 821 TEXT runtimememequal_varlen(SB),NOSPLIT,$16-9 822 MOVW a+0(FP), R0 823 MOVW b+4(FP), R1 824 CMP R0, R1 825 BEQ eq 826 MOVW 4(R7), R2 // compiler stores size at offset 4 in the closure 827 MOVW R0, 4(R13) 828 MOVW R1, 8(R13) 829 MOVW R2, 12(R13) 830 BL runtimememeq(SB) 831 MOVB 16(R13), R0 832 MOVB R0, ret+8(FP) 833 RET 834 eq: 835 MOVW $1, R0 836 MOVB R0, ret+8(FP) 837 RET 838 839 TEXT runtimecmpstring(SB),NOSPLIT,$-4-20 840 MOVW s1_base+0(FP), R2 841 MOVW s1_len+4(FP), R0 842 MOVW s2_base+8(FP), R3 843 MOVW s2_len+12(FP), R1 844 ADD $20, R13, R7 845 B runtimecmpbody(SB) 846 847 TEXT bytesCompare(SB),NOSPLIT,$-4-28 848 MOVW s1+0(FP), R2 849 MOVW s1+4(FP), R0 850 MOVW s2+12(FP), R3 851 MOVW s2+16(FP), R1 852 ADD $28, R13, R7 853 B runtimecmpbody(SB) 854 855 // On entry: 856 // R0 is the length of s1 857 // R1 is the length of s2 858 // R2 points to the start of s1 859 // R3 points to the start of s2 860 // R7 points to return value (-1/0/1 will be written here) 861 // 862 // On exit: 863 // R4, R5, and R6 are clobbered 864 TEXT runtimecmpbody(SB),NOSPLIT,$-4-0 865 CMP R0, R1 866 MOVW R0, R6 867 MOVW.LT R1, R6 // R6 is min(R0, R1) 868 869 ADD R2, R6 // R2 is current byte in s1, R6 is last byte in s1 to compare 870 loop: 871 CMP R2, R6 872 BEQ samebytes // all compared bytes were the same; compare lengths 873 MOVBU.P 1(R2), R4 874 MOVBU.P 1(R3), R5 875 CMP R4, R5 876 BEQ loop 877 // bytes differed 878 MOVW.LT $1, R0 879 MOVW.GT $-1, R0 880 MOVW R0, (R7) 881 RET 882 samebytes: 883 CMP R0, R1 884 MOVW.LT $1, R0 885 MOVW.GT $-1, R0 886 MOVW.EQ $0, R0 887 MOVW R0, (R7) 888 RET 889 890 // eqstring tests whether two strings are equal. 891 // The compiler guarantees that strings passed 892 // to eqstring have equal length. 893 // See runtime_test.go:eqstring_generic for 894 // equivalent Go code. 895 TEXT runtimeeqstring(SB),NOSPLIT,$-4-17 896 MOVW s1str+0(FP), R2 897 MOVW s2str+8(FP), R3 898 MOVW $1, R8 899 MOVB R8, v+16(FP) 900 CMP R2, R3 901 RET.EQ 902 MOVW s1len+4(FP), R0 903 ADD R2, R0, R6 904 loop: 905 CMP R2, R6 906 RET.EQ 907 MOVBU.P 1(R2), R4 908 MOVBU.P 1(R3), R5 909 CMP R4, R5 910 BEQ loop 911 MOVW $0, R8 912 MOVB R8, v+16(FP) 913 RET 914 915 // TODO: share code with memeq? 916 TEXT bytesEqual(SB),NOSPLIT,$0-25 917 MOVW a_len+4(FP), R1 918 MOVW b_len+16(FP), R3 919 920 CMP R1, R3 // unequal lengths are not equal 921 B.NE notequal 922 923 MOVW a+0(FP), R0 924 MOVW b+12(FP), R2 925 ADD R0, R1 // end 926 927 loop: 928 CMP R0, R1 929 B.EQ equal // reached the end 930 MOVBU.P 1(R0), R4 931 MOVBU.P 1(R2), R5 932 CMP R4, R5 933 B.EQ loop 934 935 notequal: 936 MOVW $0, R0 937 MOVBU R0, ret+24(FP) 938 RET 939 940 equal: 941 MOVW $1, R0 942 MOVBU R0, ret+24(FP) 943 RET 944 945 TEXT bytesIndexByte(SB),NOSPLIT,$0-20 946 MOVW s+0(FP), R0 947 MOVW s_len+4(FP), R1 948 MOVBU c+12(FP), R2 // byte to find 949 MOVW R0, R4 // store base for later 950 ADD R0, R1 // end 951 952 _loop: 953 CMP R0, R1 954 B.EQ _notfound 955 MOVBU.P 1(R0), R3 956 CMP R2, R3 957 B.NE _loop 958 959 SUB $1, R0 // R0 will be one beyond the position we want 960 SUB R4, R0 // remove base 961 MOVW R0, ret+16(FP) 962 RET 963 964 _notfound: 965 MOVW $-1, R0 966 MOVW R0, ret+16(FP) 967 RET 968 969 TEXT stringsIndexByte(SB),NOSPLIT,$0-16 970 MOVW s+0(FP), R0 971 MOVW s_len+4(FP), R1 972 MOVBU c+8(FP), R2 // byte to find 973 MOVW R0, R4 // store base for later 974 ADD R0, R1 // end 975 976 _sib_loop: 977 CMP R0, R1 978 B.EQ _sib_notfound 979 MOVBU.P 1(R0), R3 980 CMP R2, R3 981 B.NE _sib_loop 982 983 SUB $1, R0 // R0 will be one beyond the position we want 984 SUB R4, R0 // remove base 985 MOVW R0, ret+12(FP) 986 RET 987 988 _sib_notfound: 989 MOVW $-1, R0 990 MOVW R0, ret+12(FP) 991 RET 992 993 TEXT runtimefastrand1(SB),NOSPLIT,$-4-4 994 MOVW g_m(g), R1 995 MOVW m_fastrand(R1), R0 996 ADD.S R0, R0 997 EOR.MI $0x88888eef, R0 998 MOVW R0, m_fastrand(R1) 999 MOVW R0, ret+0(FP) 1000 RET 1001 1002 TEXT runtimereturn0(SB),NOSPLIT,$0 1003 MOVW $0, R0 1004 RET 1005 1006 TEXT runtimeprocyield(SB),NOSPLIT,$-4 1007 MOVW cycles+0(FP), R1 1008 MOVW $0, R0 1009 yieldloop: 1010 CMP R0, R1 1011 B.NE 2(PC) 1012 RET 1013 SUB $1, R1 1014 B yieldloop 1015 1016 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. 1017 // Must obey the gcc calling convention. 1018 TEXT _cgo_topofstack(SB),NOSPLIT,$8 1019 // R11 and g register are clobbered by load_g. They are 1020 // callee-save in the gcc calling convention, so save them here. 1021 MOVW R11, saveR11-4(SP) 1022 MOVW g, saveG-8(SP) 1023 1024 BL runtimeload_g(SB) 1025 MOVW g_m(g), R0 1026 MOVW m_curg(R0), R0 1027 MOVW (g_stack+stack_hi)(R0), R0 1028 1029 MOVW saveG-8(SP), g 1030 MOVW saveR11-4(SP), R11 1031 RET 1032 1033 // The top-most function running on a goroutine 1034 // returns to goexit+PCQuantum. 1035 TEXT runtimegoexit(SB),NOSPLIT,$-4-0 1036 MOVW R0, R0 // NOP 1037 BL runtimegoexit1(SB) // does not return 1038 // traceback from goexit1 must hit code range of goexit 1039 MOVW R0, R0 // NOP 1040 1041 TEXT runtimeprefetcht0(SB),NOSPLIT,$0-4 1042 RET 1043 1044 TEXT runtimeprefetcht1(SB),NOSPLIT,$0-4 1045 RET 1046 1047 TEXT runtimeprefetcht2(SB),NOSPLIT,$0-4 1048 RET 1049 1050 TEXT runtimeprefetchnta(SB),NOSPLIT,$0-4 1051 RET 1052 1053 // x -> x/1000000, x%1000000, called from Go with args, results on stack. 1054 TEXT runtimeusplit(SB),NOSPLIT,$0-12 1055 MOVW x+0(FP), R0 1056 CALL runtimeusplitR0(SB) 1057 MOVW R0, q+4(FP) 1058 MOVW R1, r+8(FP) 1059 RET 1060 1061 // R0, R1 = R0/1000000, R0%1000000 1062 TEXT runtimeusplitR0(SB),NOSPLIT,$0 1063 // magic multiply to avoid software divide without available m. 1064 // see output of go tool compile -S for x/1000000. 1065 MOVW R0, R3 1066 MOVW $1125899907, R1 1067 MULLU R1, R0, (R0, R1) 1068 MOVW R0>>18, R0 1069 MOVW $1000000, R1 1070 MULU R0, R1 1071 SUB R1, R3, R1 1072 RET 1073