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