github.com/jonasi/go@v0.0.0-20150930005915-e78e654c1de0/src/runtime/asm_arm.s (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #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 runtime·rt0_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	$runtime·g0(SB), g
    26  	MOVW	$runtime·m0(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	runtime·emptyfunc(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	runtime·check(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	runtime·args(SB)
    58  	BL	runtime·checkgoarm(SB)
    59  	BL	runtime·osinit(SB)
    60  	BL	runtime·schedinit(SB)
    61  
    62  	// create a new goroutine to start program
    63  	MOVW	$runtime·mainPC(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	runtime·newproc(SB)
    70  	MOVW	$12(R13), R13	// pop args and LR
    71  
    72  	// start this M
    73  	BL	runtime·mstart(SB)
    74  
    75  	MOVW	$1234, R0
    76  	MOVW	$1000, R1
    77  	MOVW	R0, (R1)	// fail hard
    78  
    79  DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
    80  GLOBL	runtime·mainPC(SB),RODATA,$4
    81  
    82  TEXT runtime·breakpoint(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 runtime·asminit(SB),NOSPLIT,$0-0
    93  	// disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
    94  	MOVB	runtime·goarm(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 runtime·gosave(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 runtime·gogo(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 runtime·mcall(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	runtime·badmcall(SB)
   169  	MOVB	runtime·iscgo(SB), R11
   170  	CMP	$0, R11
   171  	BL.NE	runtime·save_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	runtime·badmcall2(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 runtime·systemstack_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 runtime·systemstack(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	$runtime·badsystemstack(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	$runtime·systemstack_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	$runtime·mstart(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 runtime·morestack(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	runtime·abort(SB)
   280  
   281  	// Cannot grow signal stack (m->gsignal).
   282  	MOVW	m_gsignal(R8), R4
   283  	CMP	g, R4
   284  	BL.EQ	runtime·abort(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	runtime·newstack(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 runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
   311  	MOVW	$0, R7
   312  	B runtime·morestack(SB)
   313  
   314  TEXT runtime·stackBarrier(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 reflect·call(SB), NOSPLIT, $0-0
   344  	B	·reflectcall(SB)
   345  
   346  TEXT ·reflectcall(SB),NOSPLIT,$-4-20
   347  	MOVW	argsize+12(FP), R0
   348  	DISPATCH(runtime·call16, 16)
   349  	DISPATCH(runtime·call32, 32)
   350  	DISPATCH(runtime·call64, 64)
   351  	DISPATCH(runtime·call128, 128)
   352  	DISPATCH(runtime·call256, 256)
   353  	DISPATCH(runtime·call512, 512)
   354  	DISPATCH(runtime·call1024, 1024)
   355  	DISPATCH(runtime·call2048, 2048)
   356  	DISPATCH(runtime·call4096, 4096)
   357  	DISPATCH(runtime·call8192, 8192)
   358  	DISPATCH(runtime·call16384, 16384)
   359  	DISPATCH(runtime·call32768, 32768)
   360  	DISPATCH(runtime·call65536, 65536)
   361  	DISPATCH(runtime·call131072, 131072)
   362  	DISPATCH(runtime·call262144, 262144)
   363  	DISPATCH(runtime·call524288, 524288)
   364  	DISPATCH(runtime·call1048576, 1048576)
   365  	DISPATCH(runtime·call2097152, 2097152)
   366  	DISPATCH(runtime·call4194304, 4194304)
   367  	DISPATCH(runtime·call8388608, 8388608)
   368  	DISPATCH(runtime·call16777216, 16777216)
   369  	DISPATCH(runtime·call33554432, 33554432)
   370  	DISPATCH(runtime·call67108864, 67108864)
   371  	DISPATCH(runtime·call134217728, 134217728)
   372  	DISPATCH(runtime·call268435456, 268435456)
   373  	DISPATCH(runtime·call536870912, 536870912)
   374  	DISPATCH(runtime·call1073741824, 1073741824)
   375  	MOVW	$runtime·badreflectcall(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	runtime·callwritebarrier(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 runtime·jmpdefer(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 runtime·cgocallback(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	$runtime·cgocallback_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	runtime·iscgo(SB), R0
   549  	CMP	$0, R0
   550  	BL.NE	runtime·load_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	$runtime·needm(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	runtime·cgocallbackg(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	$runtime·dropm(SB), R0
   636  	BL	(R0)
   637  
   638  	// Done!
   639  	RET
   640  
   641  // void setg(G*); set g. for use by needm.
   642  TEXT runtime·setg(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	runtime·iscgo(SB), R0
   651  	CMP	$0, R0
   652  	B.EQ	2(PC)
   653  	B	runtime·save_g(SB)
   654  
   655  	MOVW	g, R0
   656  	RET
   657  
   658  TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
   659  	MOVW	8(R13), R0		// LR saved by caller
   660  	MOVW	runtime·stackBarrierPC(SB), R1
   661  	CMP	R0, R1
   662  	BNE	nobar
   663  	// Get original return PC.
   664  	BL	runtime·nextBarrierPC(SB)
   665  	MOVW	4(R13), R0
   666  nobar:
   667  	MOVW	R0, ret+4(FP)
   668  	RET
   669  
   670  TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
   671  	MOVW	pc+4(FP), R0
   672  	MOVW	8(R13), R1
   673  	MOVW	runtime·stackBarrierPC(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	runtime·setNextBarrierPC(SB)
   682  	RET
   683  
   684  TEXT runtime·getcallersp(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 runtime·emptyfunc(SB),0,$0-0
   691  	RET
   692  
   693  TEXT runtime·abort(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 runtime·cas in sys_$GOOS_arm.s
   706  // using the native instructions, use:
   707  //
   708  //	TEXT runtime·cas(SB),NOSPLIT,$0
   709  //		B	runtime·armcas(SB)
   710  //
   711  TEXT runtime·armcas(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	runtime·goarm(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	runtime·goarm(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 runtime·casuintptr(SB),NOSPLIT,$0-13
   743  	B	runtime·cas(SB)
   744  
   745  TEXT runtime·atomicloaduintptr(SB),NOSPLIT,$0-8
   746  	B	runtime·atomicload(SB)
   747  
   748  TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8
   749  	B	runtime·atomicload(SB)
   750  
   751  TEXT runtime·atomicstoreuintptr(SB),NOSPLIT,$0-8
   752  	B	runtime·atomicstore(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	runtime·armPublicationBarrier(SB)
   762  //
   763  TEXT runtime·armPublicationBarrier(SB),NOSPLIT,$-4-0
   764  	MOVB	runtime·goarm(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 runtime·aeshash(SB),NOSPLIT,$-4-0
   772  	MOVW	$0, R0
   773  	MOVW	(R0), R1
   774  TEXT runtime·aeshash32(SB),NOSPLIT,$-4-0
   775  	MOVW	$0, R0
   776  	MOVW	(R0), R1
   777  TEXT runtime·aeshash64(SB),NOSPLIT,$-4-0
   778  	MOVW	$0, R0
   779  	MOVW	(R0), R1
   780  TEXT runtime·aeshashstr(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 runtime·memhash_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	runtime·memhash(SB)
   797  	MOVW	16(R13), R0
   798  	MOVW	R0, ret+8(FP)
   799  	RET
   800  
   801  TEXT runtime·memeq(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 runtime·memequal_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	runtime·memeq(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 runtime·cmpstring(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	runtime·cmpbody(SB)
   846  
   847  TEXT bytes·Compare(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	runtime·cmpbody(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 runtime·cmpbody(SB),NOSPLIT,$-4-0
   865  	CMP	R2, R3
   866  	BEQ	samebytes
   867  	CMP 	R0, R1
   868  	MOVW 	R0, R6
   869  	MOVW.LT	R1, R6	// R6 is min(R0, R1)
   870  
   871  	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
   872  loop:
   873  	CMP	R2, R6
   874  	BEQ	samebytes // all compared bytes were the same; compare lengths
   875  	MOVBU.P	1(R2), R4
   876  	MOVBU.P	1(R3), R5
   877  	CMP	R4, R5
   878  	BEQ	loop
   879  	// bytes differed
   880  	MOVW.LT	$1, R0
   881  	MOVW.GT	$-1, R0
   882  	MOVW	R0, (R7)
   883  	RET
   884  samebytes:
   885  	CMP	R0, R1
   886  	MOVW.LT	$1, R0
   887  	MOVW.GT	$-1, R0
   888  	MOVW.EQ	$0, R0
   889  	MOVW	R0, (R7)
   890  	RET
   891  
   892  // eqstring tests whether two strings are equal.
   893  // The compiler guarantees that strings passed
   894  // to eqstring have equal length.
   895  // See runtime_test.go:eqstring_generic for
   896  // equivalent Go code.
   897  TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
   898  	MOVW	s1str+0(FP), R2
   899  	MOVW	s2str+8(FP), R3
   900  	MOVW	$1, R8
   901  	MOVB	R8, v+16(FP)
   902  	CMP	R2, R3
   903  	RET.EQ
   904  	MOVW	s1len+4(FP), R0
   905  	ADD	R2, R0, R6
   906  loop:
   907  	CMP	R2, R6
   908  	RET.EQ
   909  	MOVBU.P	1(R2), R4
   910  	MOVBU.P	1(R3), R5
   911  	CMP	R4, R5
   912  	BEQ	loop
   913  	MOVW	$0, R8
   914  	MOVB	R8, v+16(FP)
   915  	RET
   916  
   917  // TODO: share code with memeq?
   918  TEXT bytes·Equal(SB),NOSPLIT,$0-25
   919  	MOVW	a_len+4(FP), R1
   920  	MOVW	b_len+16(FP), R3
   921  	
   922  	CMP	R1, R3		// unequal lengths are not equal
   923  	B.NE	notequal
   924  
   925  	MOVW	a+0(FP), R0
   926  	MOVW	b+12(FP), R2
   927  	ADD	R0, R1		// end
   928  
   929  loop:
   930  	CMP	R0, R1
   931  	B.EQ	equal		// reached the end
   932  	MOVBU.P	1(R0), R4
   933  	MOVBU.P	1(R2), R5
   934  	CMP	R4, R5
   935  	B.EQ	loop
   936  
   937  notequal:
   938  	MOVW	$0, R0
   939  	MOVBU	R0, ret+24(FP)
   940  	RET
   941  
   942  equal:
   943  	MOVW	$1, R0
   944  	MOVBU	R0, ret+24(FP)
   945  	RET
   946  
   947  TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
   948  	MOVW	s+0(FP), R0
   949  	MOVW	s_len+4(FP), R1
   950  	MOVBU	c+12(FP), R2	// byte to find
   951  	MOVW	R0, R4		// store base for later
   952  	ADD	R0, R1		// end
   953  
   954  _loop:
   955  	CMP	R0, R1
   956  	B.EQ	_notfound
   957  	MOVBU.P	1(R0), R3
   958  	CMP	R2, R3
   959  	B.NE	_loop
   960  
   961  	SUB	$1, R0		// R0 will be one beyond the position we want
   962  	SUB	R4, R0		// remove base
   963  	MOVW    R0, ret+16(FP)
   964  	RET
   965  
   966  _notfound:
   967  	MOVW	$-1, R0
   968  	MOVW	R0, ret+16(FP)
   969  	RET
   970  
   971  TEXT strings·IndexByte(SB),NOSPLIT,$0-16
   972  	MOVW	s+0(FP), R0
   973  	MOVW	s_len+4(FP), R1
   974  	MOVBU	c+8(FP), R2	// byte to find
   975  	MOVW	R0, R4		// store base for later
   976  	ADD	R0, R1		// end
   977  
   978  _sib_loop:
   979  	CMP	R0, R1
   980  	B.EQ	_sib_notfound
   981  	MOVBU.P	1(R0), R3
   982  	CMP	R2, R3
   983  	B.NE	_sib_loop
   984  
   985  	SUB	$1, R0		// R0 will be one beyond the position we want
   986  	SUB	R4, R0		// remove base
   987  	MOVW	R0, ret+12(FP)
   988  	RET
   989  
   990  _sib_notfound:
   991  	MOVW	$-1, R0
   992  	MOVW	R0, ret+12(FP)
   993  	RET
   994  
   995  TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
   996  	MOVW	g_m(g), R1
   997  	MOVW	m_fastrand(R1), R0
   998  	ADD.S	R0, R0
   999  	EOR.MI	$0x88888eef, R0
  1000  	MOVW	R0, m_fastrand(R1)
  1001  	MOVW	R0, ret+0(FP)
  1002  	RET
  1003  
  1004  TEXT runtime·return0(SB),NOSPLIT,$0
  1005  	MOVW	$0, R0
  1006  	RET
  1007  
  1008  TEXT runtime·procyield(SB),NOSPLIT,$-4
  1009  	MOVW	cycles+0(FP), R1
  1010  	MOVW	$0, R0
  1011  yieldloop:
  1012  	CMP	R0, R1
  1013  	B.NE	2(PC)
  1014  	RET
  1015  	SUB	$1, R1
  1016  	B yieldloop
  1017  
  1018  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
  1019  // Must obey the gcc calling convention.
  1020  TEXT _cgo_topofstack(SB),NOSPLIT,$8
  1021  	// R11 and g register are clobbered by load_g.  They are
  1022  	// callee-save in the gcc calling convention, so save them here.
  1023  	MOVW	R11, saveR11-4(SP)
  1024  	MOVW	g, saveG-8(SP)
  1025  	
  1026  	BL	runtime·load_g(SB)
  1027  	MOVW	g_m(g), R0
  1028  	MOVW	m_curg(R0), R0
  1029  	MOVW	(g_stack+stack_hi)(R0), R0
  1030  	
  1031  	MOVW	saveG-8(SP), g
  1032  	MOVW	saveR11-4(SP), R11
  1033  	RET
  1034  
  1035  // The top-most function running on a goroutine
  1036  // returns to goexit+PCQuantum.
  1037  TEXT runtime·goexit(SB),NOSPLIT,$-4-0
  1038  	MOVW	R0, R0	// NOP
  1039  	BL	runtime·goexit1(SB)	// does not return
  1040  	// traceback from goexit1 must hit code range of goexit
  1041  	MOVW	R0, R0	// NOP
  1042  
  1043  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
  1044  	RET
  1045  
  1046  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
  1047  	RET
  1048  
  1049  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
  1050  	RET
  1051  
  1052  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
  1053  	RET
  1054  
  1055  // x -> x/1000000, x%1000000, called from Go with args, results on stack.
  1056  TEXT runtime·usplit(SB),NOSPLIT,$0-12
  1057  	MOVW	x+0(FP), R0
  1058  	CALL	runtime·usplitR0(SB)
  1059  	MOVW	R0, q+4(FP)
  1060  	MOVW	R1, r+8(FP)
  1061  	RET
  1062  
  1063  // R0, R1 = R0/1000000, R0%1000000
  1064  TEXT runtime·usplitR0(SB),NOSPLIT,$0
  1065  	// magic multiply to avoid software divide without available m.
  1066  	// see output of go tool compile -S for x/1000000.
  1067  	MOVW	R0, R3
  1068  	MOVW	$1125899907, R1
  1069  	MULLU	R1, R0, (R0, R1)
  1070  	MOVW	R0>>18, R0
  1071  	MOVW	$1000000, R1
  1072  	MULU	R0, R1
  1073  	SUB	R1, R3, R1
  1074  	RET
  1075  
  1076  TEXT runtime·sigreturn(SB),NOSPLIT,$0-4
  1077          RET