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