github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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  // To implement publiationBarrier in sys_$GOOS_arm.s using the native
   756  // instructions, use:
   757  //
   758  //	TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
   759  //		B	runtime·armPublicationBarrier(SB)
   760  //
   761  TEXT runtime·armPublicationBarrier(SB),NOSPLIT,$-4-0
   762  	WORD $0xf57ff05e	// DMB ST
   763  	RET
   764  
   765  // AES hashing not implemented for ARM
   766  TEXT runtime·aeshash(SB),NOSPLIT,$-4-0
   767  	MOVW	$0, R0
   768  	MOVW	(R0), R1
   769  TEXT runtime·aeshash32(SB),NOSPLIT,$-4-0
   770  	MOVW	$0, R0
   771  	MOVW	(R0), R1
   772  TEXT runtime·aeshash64(SB),NOSPLIT,$-4-0
   773  	MOVW	$0, R0
   774  	MOVW	(R0), R1
   775  TEXT runtime·aeshashstr(SB),NOSPLIT,$-4-0
   776  	MOVW	$0, R0
   777  	MOVW	(R0), R1
   778  
   779  // memhash_varlen(p unsafe.Pointer, h seed) uintptr
   780  // redirects to memhash(p, h, size) using the size
   781  // stored in the closure.
   782  TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
   783  	GO_ARGS
   784  	NO_LOCAL_POINTERS
   785  	MOVW	p+0(FP), R0
   786  	MOVW	h+4(FP), R1
   787  	MOVW	4(R7), R2
   788  	MOVW	R0, 4(R13)
   789  	MOVW	R1, 8(R13)
   790  	MOVW	R2, 12(R13)
   791  	BL	runtime·memhash(SB)
   792  	MOVW	16(R13), R0
   793  	MOVW	R0, ret+8(FP)
   794  	RET
   795  
   796  TEXT runtime·memeq(SB),NOSPLIT,$-4-13
   797  	MOVW	a+0(FP), R1
   798  	MOVW	b+4(FP), R2
   799  	MOVW	size+8(FP), R3
   800  	ADD	R1, R3, R6
   801  	MOVW	$1, R0
   802  	MOVB	R0, ret+12(FP)
   803  loop:
   804  	CMP	R1, R6
   805  	RET.EQ
   806  	MOVBU.P	1(R1), R4
   807  	MOVBU.P	1(R2), R5
   808  	CMP	R4, R5
   809  	BEQ	loop
   810  
   811  	MOVW	$0, R0
   812  	MOVB	R0, ret+12(FP)
   813  	RET
   814  
   815  // memequal_varlen(a, b unsafe.Pointer) bool
   816  TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
   817  	MOVW	a+0(FP), R0
   818  	MOVW	b+4(FP), R1
   819  	CMP	R0, R1
   820  	BEQ	eq
   821  	MOVW	4(R7), R2    // compiler stores size at offset 4 in the closure
   822  	MOVW	R0, 4(R13)
   823  	MOVW	R1, 8(R13)
   824  	MOVW	R2, 12(R13)
   825  	BL	runtime·memeq(SB)
   826  	MOVB	16(R13), R0
   827  	MOVB	R0, ret+8(FP)
   828  	RET
   829  eq:
   830  	MOVW	$1, R0
   831  	MOVB	R0, ret+8(FP)
   832  	RET
   833  
   834  TEXT runtime·cmpstring(SB),NOSPLIT,$-4-20
   835  	MOVW	s1_base+0(FP), R2
   836  	MOVW	s1_len+4(FP), R0
   837  	MOVW	s2_base+8(FP), R3
   838  	MOVW	s2_len+12(FP), R1
   839  	ADD	$20, R13, R7
   840  	B	runtime·cmpbody(SB)
   841  
   842  TEXT bytes·Compare(SB),NOSPLIT,$-4-28
   843  	MOVW	s1+0(FP), R2
   844  	MOVW	s1+4(FP), R0
   845  	MOVW	s2+12(FP), R3
   846  	MOVW	s2+16(FP), R1
   847  	ADD	$28, R13, R7
   848  	B	runtime·cmpbody(SB)
   849  
   850  // On entry:
   851  // R0 is the length of s1
   852  // R1 is the length of s2
   853  // R2 points to the start of s1
   854  // R3 points to the start of s2
   855  // R7 points to return value (-1/0/1 will be written here)
   856  //
   857  // On exit:
   858  // R4, R5, and R6 are clobbered
   859  TEXT runtime·cmpbody(SB),NOSPLIT,$-4-0
   860  	CMP 	R0, R1
   861  	MOVW 	R0, R6
   862  	MOVW.LT	R1, R6	// R6 is min(R0, R1)
   863  
   864  	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
   865  loop:
   866  	CMP	R2, R6
   867  	BEQ	samebytes // all compared bytes were the same; compare lengths
   868  	MOVBU.P	1(R2), R4
   869  	MOVBU.P	1(R3), R5
   870  	CMP	R4, R5
   871  	BEQ	loop
   872  	// bytes differed
   873  	MOVW.LT	$1, R0
   874  	MOVW.GT	$-1, R0
   875  	MOVW	R0, (R7)
   876  	RET
   877  samebytes:
   878  	CMP	R0, R1
   879  	MOVW.LT	$1, R0
   880  	MOVW.GT	$-1, R0
   881  	MOVW.EQ	$0, R0
   882  	MOVW	R0, (R7)
   883  	RET
   884  
   885  // eqstring tests whether two strings are equal.
   886  // The compiler guarantees that strings passed
   887  // to eqstring have equal length.
   888  // See runtime_test.go:eqstring_generic for
   889  // equivalent Go code.
   890  TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
   891  	MOVW	s1str+0(FP), R2
   892  	MOVW	s2str+8(FP), R3
   893  	MOVW	$1, R8
   894  	MOVB	R8, v+16(FP)
   895  	CMP	R2, R3
   896  	RET.EQ
   897  	MOVW	s1len+4(FP), R0
   898  	ADD	R2, R0, R6
   899  loop:
   900  	CMP	R2, R6
   901  	RET.EQ
   902  	MOVBU.P	1(R2), R4
   903  	MOVBU.P	1(R3), R5
   904  	CMP	R4, R5
   905  	BEQ	loop
   906  	MOVW	$0, R8
   907  	MOVB	R8, v+16(FP)
   908  	RET
   909  
   910  // TODO: share code with memeq?
   911  TEXT bytes·Equal(SB),NOSPLIT,$0-25
   912  	MOVW	a_len+4(FP), R1
   913  	MOVW	b_len+16(FP), R3
   914  	
   915  	CMP	R1, R3		// unequal lengths are not equal
   916  	B.NE	notequal
   917  
   918  	MOVW	a+0(FP), R0
   919  	MOVW	b+12(FP), R2
   920  	ADD	R0, R1		// end
   921  
   922  loop:
   923  	CMP	R0, R1
   924  	B.EQ	equal		// reached the end
   925  	MOVBU.P	1(R0), R4
   926  	MOVBU.P	1(R2), R5
   927  	CMP	R4, R5
   928  	B.EQ	loop
   929  
   930  notequal:
   931  	MOVW	$0, R0
   932  	MOVBU	R0, ret+24(FP)
   933  	RET
   934  
   935  equal:
   936  	MOVW	$1, R0
   937  	MOVBU	R0, ret+24(FP)
   938  	RET
   939  
   940  TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
   941  	MOVW	s+0(FP), R0
   942  	MOVW	s_len+4(FP), R1
   943  	MOVBU	c+12(FP), R2	// byte to find
   944  	MOVW	R0, R4		// store base for later
   945  	ADD	R0, R1		// end
   946  
   947  _loop:
   948  	CMP	R0, R1
   949  	B.EQ	_notfound
   950  	MOVBU.P	1(R0), R3
   951  	CMP	R2, R3
   952  	B.NE	_loop
   953  
   954  	SUB	$1, R0		// R0 will be one beyond the position we want
   955  	SUB	R4, R0		// remove base
   956  	MOVW    R0, ret+16(FP)
   957  	RET
   958  
   959  _notfound:
   960  	MOVW	$-1, R0
   961  	MOVW	R0, ret+16(FP)
   962  	RET
   963  
   964  TEXT strings·IndexByte(SB),NOSPLIT,$0-16
   965  	MOVW	s+0(FP), R0
   966  	MOVW	s_len+4(FP), R1
   967  	MOVBU	c+8(FP), R2	// byte to find
   968  	MOVW	R0, R4		// store base for later
   969  	ADD	R0, R1		// end
   970  
   971  _sib_loop:
   972  	CMP	R0, R1
   973  	B.EQ	_sib_notfound
   974  	MOVBU.P	1(R0), R3
   975  	CMP	R2, R3
   976  	B.NE	_sib_loop
   977  
   978  	SUB	$1, R0		// R0 will be one beyond the position we want
   979  	SUB	R4, R0		// remove base
   980  	MOVW	R0, ret+12(FP)
   981  	RET
   982  
   983  _sib_notfound:
   984  	MOVW	$-1, R0
   985  	MOVW	R0, ret+12(FP)
   986  	RET
   987  
   988  TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
   989  	MOVW	g_m(g), R1
   990  	MOVW	m_fastrand(R1), R0
   991  	ADD.S	R0, R0
   992  	EOR.MI	$0x88888eef, R0
   993  	MOVW	R0, m_fastrand(R1)
   994  	MOVW	R0, ret+0(FP)
   995  	RET
   996  
   997  TEXT runtime·return0(SB),NOSPLIT,$0
   998  	MOVW	$0, R0
   999  	RET
  1000  
  1001  TEXT runtime·procyield(SB),NOSPLIT,$-4
  1002  	MOVW	cycles+0(FP), R1
  1003  	MOVW	$0, R0
  1004  yieldloop:
  1005  	CMP	R0, R1
  1006  	B.NE	2(PC)
  1007  	RET
  1008  	SUB	$1, R1
  1009  	B yieldloop
  1010  
  1011  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
  1012  // Must obey the gcc calling convention.
  1013  TEXT _cgo_topofstack(SB),NOSPLIT,$8
  1014  	// R11 and g register are clobbered by load_g.  They are
  1015  	// callee-save in the gcc calling convention, so save them here.
  1016  	MOVW	R11, saveR11-4(SP)
  1017  	MOVW	g, saveG-8(SP)
  1018  	
  1019  	BL	runtime·load_g(SB)
  1020  	MOVW	g_m(g), R0
  1021  	MOVW	m_curg(R0), R0
  1022  	MOVW	(g_stack+stack_hi)(R0), R0
  1023  	
  1024  	MOVW	saveG-8(SP), g
  1025  	MOVW	saveR11-4(SP), R11
  1026  	RET
  1027  
  1028  // The top-most function running on a goroutine
  1029  // returns to goexit+PCQuantum.
  1030  TEXT runtime·goexit(SB),NOSPLIT,$-4-0
  1031  	MOVW	R0, R0	// NOP
  1032  	BL	runtime·goexit1(SB)	// does not return
  1033  	// traceback from goexit1 must hit code range of goexit
  1034  	MOVW	R0, R0	// NOP
  1035  
  1036  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
  1037  	RET
  1038  
  1039  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
  1040  	RET
  1041  
  1042  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
  1043  	RET
  1044  
  1045  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
  1046  	RET
  1047  
  1048  // x -> x/1000000, x%1000000, called from Go with args, results on stack.
  1049  TEXT runtime·usplit(SB),NOSPLIT,$0-12
  1050  	MOVW	x+0(FP), R0
  1051  	CALL	runtime·usplitR0(SB)
  1052  	MOVW	R0, q+4(FP)
  1053  	MOVW	R1, r+8(FP)
  1054  	RET
  1055  
  1056  // R0, R1 = R0/1000000, R0%1000000
  1057  TEXT runtime·usplitR0(SB),NOSPLIT,$0
  1058  	// magic multiply to avoid software divide without available m.
  1059  	// see output of go tool compile -S for x/1000000.
  1060  	MOVW	R0, R3
  1061  	MOVW	$1125899907, R1
  1062  	MULLU	R1, R0, (R0, R1)
  1063  	MOVW	R0>>18, R0
  1064  	MOVW	$1000000, R1
  1065  	MULU	R0, R1
  1066  	SUB	R1, R3, R1
  1067  	RET