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