github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/runtime/asm_mipsx.s (about)

     1  // Copyright 2016 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  // +build mips mipsle
     6  
     7  #include "go_asm.h"
     8  #include "go_tls.h"
     9  #include "funcdata.h"
    10  #include "textflag.h"
    11  
    12  #define	REGCTXT	R22
    13  
    14  TEXT runtime·rt0_go(SB),NOSPLIT,$0
    15  	// R29 = stack; R4 = argc; R5 = argv
    16  
    17  	ADDU	$-12, R29
    18  	MOVW	R4, 4(R29)	// argc
    19  	MOVW	R5, 8(R29)	// argv
    20  
    21  	// create istack out of the given (operating system) stack.
    22  	// _cgo_init may update stackguard.
    23  	MOVW	$runtime·g0(SB), g
    24  	MOVW	$(-64*1024), R23
    25  	ADD	R23, R29, R1
    26  	MOVW	R1, g_stackguard0(g)
    27  	MOVW	R1, g_stackguard1(g)
    28  	MOVW	R1, (g_stack+stack_lo)(g)
    29  	MOVW	R29, (g_stack+stack_hi)(g)
    30  
    31  	// if there is a _cgo_init, call it using the gcc ABI.
    32  	MOVW	_cgo_init(SB), R25
    33  	BEQ	R25, nocgo
    34  	ADDU	$-16, R29
    35  	MOVW	R0, R7	// arg 3: not used
    36  	MOVW	R0, R6	// arg 2: not used
    37  	MOVW	$setg_gcc<>(SB), R5	// arg 1: setg
    38  	MOVW	g, R4	// arg 0: G
    39  	JAL	(R25)
    40  	ADDU	$16, R29
    41  
    42  nocgo:
    43  	// update stackguard after _cgo_init
    44  	MOVW	(g_stack+stack_lo)(g), R1
    45  	ADD	$const__StackGuard, R1
    46  	MOVW	R1, g_stackguard0(g)
    47  	MOVW	R1, g_stackguard1(g)
    48  
    49  	// set the per-goroutine and per-mach "registers"
    50  	MOVW	$runtime·m0(SB), R1
    51  
    52  	// save m->g0 = g0
    53  	MOVW	g, m_g0(R1)
    54  	// save m0 to g0->m
    55  	MOVW	R1, g_m(g)
    56  
    57  	JAL	runtime·check(SB)
    58  
    59  	// args are already prepared
    60  	JAL	runtime·args(SB)
    61  	JAL	runtime·osinit(SB)
    62  	JAL	runtime·schedinit(SB)
    63  
    64  	// create a new goroutine to start program
    65  	MOVW	$runtime·mainPC(SB), R1	// entry
    66  	ADDU	$-12, R29
    67  	MOVW	R1, 8(R29)
    68  	MOVW	R0, 4(R29)
    69  	MOVW	R0, 0(R29)
    70  	JAL	runtime·newproc(SB)
    71  	ADDU	$12, R29
    72  
    73  	// start this M
    74  	JAL	runtime·mstart(SB)
    75  
    76  	UNDEF
    77  	RET
    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  	BREAK
    84  	RET
    85  
    86  TEXT runtime·asminit(SB),NOSPLIT,$0-0
    87  	RET
    88  
    89  /*
    90   *  go-routine
    91   */
    92  
    93  // void gosave(Gobuf*)
    94  // save state in Gobuf; setjmp
    95  TEXT runtime·gosave(SB),NOSPLIT,$-4-4
    96  	MOVW	buf+0(FP), R1
    97  	MOVW	R29, gobuf_sp(R1)
    98  	MOVW	R31, gobuf_pc(R1)
    99  	MOVW	g, gobuf_g(R1)
   100  	MOVW	R0, gobuf_lr(R1)
   101  	MOVW	R0, gobuf_ret(R1)
   102  	// Assert ctxt is zero. See func save.
   103  	MOVW	gobuf_ctxt(R1), R1
   104  	BEQ	R1, 2(PC)
   105  	JAL	runtime·badctxt(SB)
   106  	RET
   107  
   108  // void gogo(Gobuf*)
   109  // restore state from Gobuf; longjmp
   110  TEXT runtime·gogo(SB),NOSPLIT,$8-4
   111  	MOVW	buf+0(FP), R3
   112  
   113  	// If ctxt is not nil, invoke deletion barrier before overwriting.
   114  	MOVW	gobuf_ctxt(R3), R1
   115  	BEQ	R1, nilctxt
   116  	MOVW	$gobuf_ctxt(R3), R1
   117  	MOVW	R1, 4(R29)
   118  	MOVW	R0, 8(R29)
   119  	JAL	runtime·writebarrierptr_prewrite(SB)
   120  	MOVW	buf+0(FP), R3
   121  
   122  nilctxt:
   123  	MOVW	gobuf_g(R3), g	// make sure g is not nil
   124  	JAL	runtime·save_g(SB)
   125  
   126  	MOVW	0(g), R2
   127  	MOVW	gobuf_sp(R3), R29
   128  	MOVW	gobuf_lr(R3), R31
   129  	MOVW	gobuf_ret(R3), R1
   130  	MOVW	gobuf_ctxt(R3), REGCTXT
   131  	MOVW	R0, gobuf_sp(R3)
   132  	MOVW	R0, gobuf_ret(R3)
   133  	MOVW	R0, gobuf_lr(R3)
   134  	MOVW	R0, gobuf_ctxt(R3)
   135  	MOVW	gobuf_pc(R3), R4
   136  	JMP	(R4)
   137  
   138  // void mcall(fn func(*g))
   139  // Switch to m->g0's stack, call fn(g).
   140  // Fn must never return. It should gogo(&g->sched)
   141  // to keep running g.
   142  TEXT runtime·mcall(SB),NOSPLIT,$-4-4
   143  	// Save caller state in g->sched
   144  	MOVW	R29, (g_sched+gobuf_sp)(g)
   145  	MOVW	R31, (g_sched+gobuf_pc)(g)
   146  	MOVW	R0, (g_sched+gobuf_lr)(g)
   147  	MOVW	g, (g_sched+gobuf_g)(g)
   148  
   149  	// Switch to m->g0 & its stack, call fn.
   150  	MOVW	g, R1
   151  	MOVW	g_m(g), R3
   152  	MOVW	m_g0(R3), g
   153  	JAL	runtime·save_g(SB)
   154  	BNE	g, R1, 2(PC)
   155  	JMP	runtime·badmcall(SB)
   156  	MOVW	fn+0(FP), REGCTXT	// context
   157  	MOVW	0(REGCTXT), R4	// code pointer
   158  	MOVW	(g_sched+gobuf_sp)(g), R29	// sp = m->g0->sched.sp
   159  	ADDU	$-8, R29	// make room for 1 arg and fake LR
   160  	MOVW	R1, 4(R29)
   161  	MOVW	R0, 0(R29)
   162  	JAL	(R4)
   163  	JMP	runtime·badmcall2(SB)
   164  
   165  // systemstack_switch is a dummy routine that systemstack leaves at the bottom
   166  // of the G stack.  We need to distinguish the routine that
   167  // lives at the bottom of the G stack from the one that lives
   168  // at the top of the system stack because the one at the top of
   169  // the system stack terminates the stack walk (see topofstack()).
   170  TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0
   171  	UNDEF
   172  	JAL	(R31)	// make sure this function is not leaf
   173  	RET
   174  
   175  // func systemstack(fn func())
   176  TEXT runtime·systemstack(SB),NOSPLIT,$0-4
   177  	MOVW	fn+0(FP), R1	// R1 = fn
   178  	MOVW	R1, REGCTXT	// context
   179  	MOVW	g_m(g), R2	// R2 = m
   180  
   181  	MOVW	m_gsignal(R2), R3	// R3 = gsignal
   182  	BEQ	g, R3, noswitch
   183  
   184  	MOVW	m_g0(R2), R3	// R3 = g0
   185  	BEQ	g, R3, noswitch
   186  
   187  	MOVW	m_curg(R2), R4
   188  	BEQ	g, R4, switch
   189  
   190  	// Bad: g is not gsignal, not g0, not curg. What is it?
   191  	// Hide call from linker nosplit analysis.
   192  	MOVW	$runtime·badsystemstack(SB), R4
   193  	JAL	(R4)
   194  
   195  switch:
   196  	// save our state in g->sched.  Pretend to
   197  	// be systemstack_switch if the G stack is scanned.
   198  	MOVW	$runtime·systemstack_switch(SB), R4
   199  	ADDU	$8, R4	// get past prologue
   200  	MOVW	R4, (g_sched+gobuf_pc)(g)
   201  	MOVW	R29, (g_sched+gobuf_sp)(g)
   202  	MOVW	R0, (g_sched+gobuf_lr)(g)
   203  	MOVW	g, (g_sched+gobuf_g)(g)
   204  
   205  	// switch to g0
   206  	MOVW	R3, g
   207  	JAL	runtime·save_g(SB)
   208  	MOVW	(g_sched+gobuf_sp)(g), R1
   209  	// make it look like mstart called systemstack on g0, to stop traceback
   210  	ADDU	$-4, R1
   211  	MOVW	$runtime·mstart(SB), R2
   212  	MOVW	R2, 0(R1)
   213  	MOVW	R1, R29
   214  
   215  	// call target function
   216  	MOVW	0(REGCTXT), R4	// code pointer
   217  	JAL	(R4)
   218  
   219  	// switch back to g
   220  	MOVW	g_m(g), R1
   221  	MOVW	m_curg(R1), g
   222  	JAL	runtime·save_g(SB)
   223  	MOVW	(g_sched+gobuf_sp)(g), R29
   224  	MOVW	R0, (g_sched+gobuf_sp)(g)
   225  	RET
   226  
   227  noswitch:
   228  	// already on m stack, just call directly
   229  	MOVW	0(REGCTXT), R4	// code pointer
   230  	JAL	(R4)
   231  	RET
   232  
   233  /*
   234   * support for morestack
   235   */
   236  
   237  // Called during function prolog when more stack is needed.
   238  // Caller has already loaded:
   239  // R1: framesize, R2: argsize, R3: LR
   240  //
   241  // The traceback routines see morestack on a g0 as being
   242  // the top of a stack (for example, morestack calling newstack
   243  // calling the scheduler calling newm calling gc), so we must
   244  // record an argument size. For that purpose, it has no arguments.
   245  TEXT runtime·morestack(SB),NOSPLIT,$-4-0
   246  	// Cannot grow scheduler stack (m->g0).
   247  	MOVW	g_m(g), R7
   248  	MOVW	m_g0(R7), R8
   249  	BNE	g, R8, 3(PC)
   250  	JAL	runtime·badmorestackg0(SB)
   251  	JAL	runtime·abort(SB)
   252  
   253  	// Cannot grow signal stack (m->gsignal).
   254  	MOVW	m_gsignal(R7), R8
   255  	BNE	g, R8, 3(PC)
   256  	JAL	runtime·badmorestackgsignal(SB)
   257  	JAL	runtime·abort(SB)
   258  
   259  	// Called from f.
   260  	// Set g->sched to context in f.
   261  	MOVW	R29, (g_sched+gobuf_sp)(g)
   262  	MOVW	R31, (g_sched+gobuf_pc)(g)
   263  	MOVW	R3, (g_sched+gobuf_lr)(g)
   264  	// newstack will fill gobuf.ctxt.
   265  
   266  	// Called from f.
   267  	// Set m->morebuf to f's caller.
   268  	MOVW	R3, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
   269  	MOVW	R29, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
   270  	MOVW	g, (m_morebuf+gobuf_g)(R7)
   271  
   272  	// Call newstack on m->g0's stack.
   273  	MOVW	m_g0(R7), g
   274  	JAL	runtime·save_g(SB)
   275  	MOVW	(g_sched+gobuf_sp)(g), R29
   276  	// Create a stack frame on g0 to call newstack.
   277  	MOVW	R0, -8(R29)	// Zero saved LR in frame
   278  	ADDU	$-8, R29
   279  	MOVW	REGCTXT, 4(R29)	// ctxt argument
   280  	JAL	runtime·newstack(SB)
   281  
   282  	// Not reached, but make sure the return PC from the call to newstack
   283  	// is still in this function, and not the beginning of the next.
   284  	UNDEF
   285  
   286  TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
   287  	MOVW	R0, REGCTXT
   288  	JMP	runtime·morestack(SB)
   289  
   290  // reflectcall: call a function with the given argument list
   291  // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
   292  // we don't have variable-sized frames, so we use a small number
   293  // of constant-sized-frame functions to encode a few bits of size in the pc.
   294  
   295  #define DISPATCH(NAME,MAXSIZE)	\
   296  	MOVW	$MAXSIZE, R23;	\
   297  	SGTU	R1, R23, R23;	\
   298  	BNE	R23, 3(PC);	\
   299  	MOVW	$NAME(SB), R4;	\
   300  	JMP	(R4)
   301  
   302  TEXT reflect·call(SB),NOSPLIT,$0-20
   303  	JMP	·reflectcall(SB)
   304  
   305  TEXT ·reflectcall(SB),NOSPLIT,$-4-20
   306  	MOVW	argsize+12(FP), R1
   307  
   308  	DISPATCH(runtime·call16, 16)
   309  	DISPATCH(runtime·call32, 32)
   310  	DISPATCH(runtime·call64, 64)
   311  	DISPATCH(runtime·call128, 128)
   312  	DISPATCH(runtime·call256, 256)
   313  	DISPATCH(runtime·call512, 512)
   314  	DISPATCH(runtime·call1024, 1024)
   315  	DISPATCH(runtime·call2048, 2048)
   316  	DISPATCH(runtime·call4096, 4096)
   317  	DISPATCH(runtime·call8192, 8192)
   318  	DISPATCH(runtime·call16384, 16384)
   319  	DISPATCH(runtime·call32768, 32768)
   320  	DISPATCH(runtime·call65536, 65536)
   321  	DISPATCH(runtime·call131072, 131072)
   322  	DISPATCH(runtime·call262144, 262144)
   323  	DISPATCH(runtime·call524288, 524288)
   324  	DISPATCH(runtime·call1048576, 1048576)
   325  	DISPATCH(runtime·call2097152, 2097152)
   326  	DISPATCH(runtime·call4194304, 4194304)
   327  	DISPATCH(runtime·call8388608, 8388608)
   328  	DISPATCH(runtime·call16777216, 16777216)
   329  	DISPATCH(runtime·call33554432, 33554432)
   330  	DISPATCH(runtime·call67108864, 67108864)
   331  	DISPATCH(runtime·call134217728, 134217728)
   332  	DISPATCH(runtime·call268435456, 268435456)
   333  	DISPATCH(runtime·call536870912, 536870912)
   334  	DISPATCH(runtime·call1073741824, 1073741824)
   335  	MOVW	$runtime·badreflectcall(SB), R4
   336  	JMP	(R4)
   337  
   338  #define CALLFN(NAME,MAXSIZE)	\
   339  TEXT NAME(SB),WRAPPER,$MAXSIZE-20;	\
   340  	NO_LOCAL_POINTERS;	\
   341  	/* copy arguments to stack */		\
   342  	MOVW	arg+8(FP), R1;	\
   343  	MOVW	argsize+12(FP), R2;	\
   344  	MOVW	R29, R3;	\
   345  	ADDU	$4, R3;	\
   346  	ADDU	R3, R2;	\
   347  	BEQ	R3, R2, 6(PC);	\
   348  	MOVBU	(R1), R4;	\
   349  	ADDU	$1, R1;	\
   350  	MOVBU	R4, (R3);	\
   351  	ADDU	$1, R3;	\
   352  	JMP	-5(PC);	\
   353  	/* call function */			\
   354  	MOVW	f+4(FP), REGCTXT;	\
   355  	MOVW	(REGCTXT), R4;	\
   356  	PCDATA	$PCDATA_StackMapIndex, $0;	\
   357  	JAL	(R4);	\
   358  	/* copy return values back */		\
   359  	MOVW	argtype+0(FP), R5;	\
   360  	MOVW	arg+8(FP), R1;	\
   361  	MOVW	n+12(FP), R2;	\
   362  	MOVW	retoffset+16(FP), R4;	\
   363  	ADDU	$4, R29, R3;	\
   364  	ADDU	R4, R3;	\
   365  	ADDU	R4, R1;	\
   366  	SUBU	R4, R2;	\
   367  	JAL	callRet<>(SB);		\
   368  	RET
   369  
   370  // callRet copies return values back at the end of call*. This is a
   371  // separate function so it can allocate stack space for the arguments
   372  // to reflectcallmove. It does not follow the Go ABI; it expects its
   373  // arguments in registers.
   374  TEXT callRet<>(SB), NOSPLIT, $16-0
   375  	MOVW	R5, 4(R29)
   376  	MOVW	R1, 8(R29)
   377  	MOVW	R3, 12(R29)
   378  	MOVW	R2, 16(R29)
   379  	JAL	runtime·reflectcallmove(SB)
   380  	RET
   381  
   382  CALLFN(·call16, 16)
   383  CALLFN(·call32, 32)
   384  CALLFN(·call64, 64)
   385  CALLFN(·call128, 128)
   386  CALLFN(·call256, 256)
   387  CALLFN(·call512, 512)
   388  CALLFN(·call1024, 1024)
   389  CALLFN(·call2048, 2048)
   390  CALLFN(·call4096, 4096)
   391  CALLFN(·call8192, 8192)
   392  CALLFN(·call16384, 16384)
   393  CALLFN(·call32768, 32768)
   394  CALLFN(·call65536, 65536)
   395  CALLFN(·call131072, 131072)
   396  CALLFN(·call262144, 262144)
   397  CALLFN(·call524288, 524288)
   398  CALLFN(·call1048576, 1048576)
   399  CALLFN(·call2097152, 2097152)
   400  CALLFN(·call4194304, 4194304)
   401  CALLFN(·call8388608, 8388608)
   402  CALLFN(·call16777216, 16777216)
   403  CALLFN(·call33554432, 33554432)
   404  CALLFN(·call67108864, 67108864)
   405  CALLFN(·call134217728, 134217728)
   406  CALLFN(·call268435456, 268435456)
   407  CALLFN(·call536870912, 536870912)
   408  CALLFN(·call1073741824, 1073741824)
   409  
   410  TEXT runtime·procyield(SB),NOSPLIT,$0-4
   411  	RET
   412  
   413  // void jmpdefer(fv, sp);
   414  // called from deferreturn.
   415  // 1. grab stored LR for caller
   416  // 2. sub 8 bytes to get back to JAL deferreturn
   417  // 3. JMP to fn
   418  TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
   419  	MOVW	0(R29), R31
   420  	ADDU	$-8, R31
   421  
   422  	MOVW	fv+0(FP), REGCTXT
   423  	MOVW	argp+4(FP), R29
   424  	ADDU	$-4, R29
   425  	NOR	R0, R0	// prevent scheduling
   426  	MOVW	0(REGCTXT), R4
   427  	JMP	(R4)
   428  
   429  // Save state of caller into g->sched. Smashes R1.
   430  TEXT gosave<>(SB),NOSPLIT,$-4
   431  	MOVW	R31, (g_sched+gobuf_pc)(g)
   432  	MOVW	R29, (g_sched+gobuf_sp)(g)
   433  	MOVW	R0, (g_sched+gobuf_lr)(g)
   434  	MOVW	R0, (g_sched+gobuf_ret)(g)
   435  	// Assert ctxt is zero. See func save.
   436  	MOVW	(g_sched+gobuf_ctxt)(g), R1
   437  	BEQ	R1, 2(PC)
   438  	JAL	runtime·badctxt(SB)
   439  	RET
   440  
   441  // func asmcgocall(fn, arg unsafe.Pointer) int32
   442  // Call fn(arg) on the scheduler stack,
   443  // aligned appropriately for the gcc ABI.
   444  // See cgocall.go for more details.
   445  TEXT ·asmcgocall(SB),NOSPLIT,$0-12
   446  	MOVW	fn+0(FP), R25
   447  	MOVW	arg+4(FP), R4
   448  
   449  	MOVW	R29, R3	// save original stack pointer
   450  	MOVW	g, R2
   451  
   452  	// Figure out if we need to switch to m->g0 stack.
   453  	// We get called to create new OS threads too, and those
   454  	// come in on the m->g0 stack already.
   455  	MOVW	g_m(g), R5
   456  	MOVW	m_g0(R5), R6
   457  	BEQ	R6, g, g0
   458  
   459  	JAL	gosave<>(SB)
   460  	MOVW	R6, g
   461  	JAL	runtime·save_g(SB)
   462  	MOVW	(g_sched+gobuf_sp)(g), R29
   463  
   464  	// Now on a scheduling stack (a pthread-created stack).
   465  g0:
   466  	// Save room for two of our pointers and O32 frame.
   467  	ADDU	$-24, R29
   468  	AND	$~7, R29	// O32 ABI expects 8-byte aligned stack on function entry
   469  	MOVW	R2, 16(R29)	// save old g on stack
   470  	MOVW	(g_stack+stack_hi)(R2), R2
   471  	SUBU	R3, R2
   472  	MOVW	R2, 20(R29)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
   473  	JAL	(R25)
   474  
   475  	// Restore g, stack pointer. R2 is return value.
   476  	MOVW	16(R29), g
   477  	JAL	runtime·save_g(SB)
   478  	MOVW	(g_stack+stack_hi)(g), R5
   479  	MOVW	20(R29), R6
   480  	SUBU	R6, R5
   481  	MOVW	R5, R29
   482  
   483  	MOVW	R2, ret+8(FP)
   484  	RET
   485  
   486  // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
   487  // Turn the fn into a Go func (by taking its address) and call
   488  // cgocallback_gofunc.
   489  TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
   490  	MOVW	$fn+0(FP), R1
   491  	MOVW	R1, 4(R29)
   492  	MOVW	frame+4(FP), R1
   493  	MOVW	R1, 8(R29)
   494  	MOVW	framesize+8(FP), R1
   495  	MOVW	R1, 12(R29)
   496  	MOVW	ctxt+12(FP), R1
   497  	MOVW	R1, 16(R29)
   498  	MOVW	$runtime·cgocallback_gofunc(SB), R1
   499  	JAL	(R1)
   500  	RET
   501  
   502  // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
   503  // See cgocall.go for more details.
   504  TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-16
   505  	NO_LOCAL_POINTERS
   506  
   507  	// Load m and g from thread-local storage.
   508  	MOVB	runtime·iscgo(SB), R1
   509  	BEQ	R1, nocgo
   510  	JAL	runtime·load_g(SB)
   511  nocgo:
   512  
   513  	// If g is nil, Go did not create the current thread.
   514  	// Call needm to obtain one for temporary use.
   515  	// In this case, we're running on the thread stack, so there's
   516  	// lots of space, but the linker doesn't know. Hide the call from
   517  	// the linker analysis by using an indirect call.
   518  	BEQ	g, needm
   519  
   520  	MOVW	g_m(g), R3
   521  	MOVW	R3, savedm-4(SP)
   522  	JMP	havem
   523  
   524  needm:
   525  	MOVW	g, savedm-4(SP) // g is zero, so is m.
   526  	MOVW	$runtime·needm(SB), R4
   527  	JAL	(R4)
   528  
   529  	// Set m->sched.sp = SP, so that if a panic happens
   530  	// during the function we are about to execute, it will
   531  	// have a valid SP to run on the g0 stack.
   532  	// The next few lines (after the havem label)
   533  	// will save this SP onto the stack and then write
   534  	// the same SP back to m->sched.sp. That seems redundant,
   535  	// but if an unrecovered panic happens, unwindm will
   536  	// restore the g->sched.sp from the stack location
   537  	// and then systemstack will try to use it. If we don't set it here,
   538  	// that restored SP will be uninitialized (typically 0) and
   539  	// will not be usable.
   540  	MOVW	g_m(g), R3
   541  	MOVW	m_g0(R3), R1
   542  	MOVW	R29, (g_sched+gobuf_sp)(R1)
   543  
   544  havem:
   545  	// Now there's a valid m, and we're running on its m->g0.
   546  	// Save current m->g0->sched.sp on stack and then set it to SP.
   547  	// Save current sp in m->g0->sched.sp in preparation for
   548  	// switch back to m->curg stack.
   549  	// NOTE: unwindm knows that the saved g->sched.sp is at 4(R29) aka savedsp-8(SP).
   550  	MOVW	m_g0(R3), R1
   551  	MOVW	(g_sched+gobuf_sp)(R1), R2
   552  	MOVW	R2, savedsp-8(SP)
   553  	MOVW	R29, (g_sched+gobuf_sp)(R1)
   554  
   555  	// Switch to m->curg stack and call runtime.cgocallbackg.
   556  	// Because we are taking over the execution of m->curg
   557  	// but *not* resuming what had been running, we need to
   558  	// save that information (m->curg->sched) so we can restore it.
   559  	// We can restore m->curg->sched.sp easily, because calling
   560  	// runtime.cgocallbackg leaves SP unchanged upon return.
   561  	// To save m->curg->sched.pc, we push it onto the stack.
   562  	// This has the added benefit that it looks to the traceback
   563  	// routine like cgocallbackg is going to return to that
   564  	// PC (because the frame we allocate below has the same
   565  	// size as cgocallback_gofunc's frame declared above)
   566  	// so that the traceback will seamlessly trace back into
   567  	// the earlier calls.
   568  	//
   569  	// In the new goroutine, -4(SP) is unused (where SP refers to
   570  	// m->curg's SP while we're setting it up, before we've adjusted it).
   571  	MOVW	m_curg(R3), g
   572  	JAL	runtime·save_g(SB)
   573  	MOVW	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
   574  	MOVW	(g_sched+gobuf_pc)(g), R4
   575  	MOVW	R4, -12(R2)
   576  	MOVW    ctxt+12(FP), R1
   577  	MOVW    R1, -8(R2)
   578  	MOVW	$-12(R2), R29
   579  	JAL	runtime·cgocallbackg(SB)
   580  
   581  	// Restore g->sched (== m->curg->sched) from saved values.
   582  	MOVW	0(R29), R4
   583  	MOVW	R4, (g_sched+gobuf_pc)(g)
   584  	MOVW	$12(R29), R2
   585  	MOVW	R2, (g_sched+gobuf_sp)(g)
   586  
   587  	// Switch back to m->g0's stack and restore m->g0->sched.sp.
   588  	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
   589  	// so we do not have to restore it.)
   590  	MOVW	g_m(g), R3
   591  	MOVW	m_g0(R3), g
   592  	JAL	runtime·save_g(SB)
   593  	MOVW	(g_sched+gobuf_sp)(g), R29
   594  	MOVW	savedsp-8(SP), R2
   595  	MOVW	R2, (g_sched+gobuf_sp)(g)
   596  
   597  	// If the m on entry was nil, we called needm above to borrow an m
   598  	// for the duration of the call. Since the call is over, return it with dropm.
   599  	MOVW	savedm-4(SP), R3
   600  	BNE	R3, droppedm
   601  	MOVW	$runtime·dropm(SB), R4
   602  	JAL	(R4)
   603  droppedm:
   604  
   605  	// Done!
   606  	RET
   607  
   608  // void setg(G*); set g. for use by needm.
   609  // This only happens if iscgo, so jump straight to save_g
   610  TEXT runtime·setg(SB),NOSPLIT,$0-4
   611  	MOVW	gg+0(FP), g
   612  	JAL	runtime·save_g(SB)
   613  	RET
   614  
   615  // void setg_gcc(G*); set g in C TLS.
   616  // Must obey the gcc calling convention.
   617  TEXT setg_gcc<>(SB),NOSPLIT,$0
   618  	MOVW	R4, g
   619  	JAL	runtime·save_g(SB)
   620  	RET
   621  
   622  TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
   623  	MOVW	8(R29), R1	// LR saved by caller
   624  	MOVW	R1, ret+4(FP)
   625  	RET
   626  
   627  TEXT runtime·abort(SB),NOSPLIT,$0-0
   628  	UNDEF
   629  
   630  // memhash_varlen(p unsafe.Pointer, h seed) uintptr
   631  // redirects to memhash(p, h, size) using the size
   632  // stored in the closure.
   633  TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
   634  	GO_ARGS
   635  	NO_LOCAL_POINTERS
   636  	MOVW	p+0(FP), R1
   637  	MOVW	h+4(FP), R2
   638  	MOVW	4(REGCTXT), R3
   639  	MOVW	R1, 4(R29)
   640  	MOVW	R2, 8(R29)
   641  	MOVW	R3, 12(R29)
   642  	JAL	runtime·memhash(SB)
   643  	MOVW	16(R29), R1
   644  	MOVW	R1, ret+8(FP)
   645  	RET
   646  
   647  // Not implemented.
   648  TEXT runtime·aeshash(SB),NOSPLIT,$0
   649  	UNDEF
   650  
   651  // Not implemented.
   652  TEXT runtime·aeshash32(SB),NOSPLIT,$0
   653  	UNDEF
   654  
   655  // Not implemented.
   656  TEXT runtime·aeshash64(SB),NOSPLIT,$0
   657  	UNDEF
   658  
   659  // Not implemented.
   660  TEXT runtime·aeshashstr(SB),NOSPLIT,$0
   661  	UNDEF
   662  
   663  // memequal(a, b unsafe.Pointer, size uintptr) bool
   664  TEXT runtime·memequal(SB),NOSPLIT,$0-13
   665  	MOVW	a+0(FP), R1
   666  	MOVW	b+4(FP), R2
   667  	BEQ	R1, R2, eq
   668  	MOVW	size+8(FP), R3
   669  	ADDU	R1, R3, R4
   670  loop:
   671  	BNE	R1, R4, test
   672  	MOVW	$1, R1
   673  	MOVB	R1, ret+12(FP)
   674  	RET
   675  test:
   676  	MOVBU	(R1), R6
   677  	ADDU	$1, R1
   678  	MOVBU	(R2), R7
   679  	ADDU	$1, R2
   680  	BEQ	R6, R7, loop
   681  
   682  	MOVB	R0, ret+12(FP)
   683  	RET
   684  eq:
   685  	MOVW	$1, R1
   686  	MOVB	R1, ret+12(FP)
   687  	RET
   688  
   689  // memequal_varlen(a, b unsafe.Pointer) bool
   690  TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
   691  	MOVW	a+0(FP), R1
   692  	MOVW	b+4(FP), R2
   693  	BEQ	R1, R2, eq
   694  	MOVW	4(REGCTXT), R3	// compiler stores size at offset 4 in the closure
   695  	ADDU	R1, R3, R4
   696  loop:
   697  	BNE	R1, R4, test
   698  	MOVW	$1, R1
   699  	MOVB	R1, ret+8(FP)
   700  	RET
   701  test:
   702  	MOVBU	(R1), R6
   703  	ADDU	$1, R1
   704  	MOVBU	(R2), R7
   705  	ADDU	$1, R2
   706  	BEQ	R6, R7, loop
   707  
   708  	MOVB	R0, ret+8(FP)
   709  	RET
   710  eq:
   711  	MOVW	$1, R1
   712  	MOVB	R1, ret+8(FP)
   713  	RET
   714  
   715  // eqstring tests whether two strings are equal.
   716  // The compiler guarantees that strings passed
   717  // to eqstring have equal length.
   718  // See runtime_test.go:eqstring_generic for
   719  // equivalent Go code.
   720  TEXT runtime·eqstring(SB),NOSPLIT,$0-17
   721  	MOVW	s1_base+0(FP), R1
   722  	MOVW	s2_base+8(FP), R2
   723  	MOVW	$1, R3
   724  	MOVBU	R3, ret+16(FP)
   725  	BNE	R1, R2, 2(PC)
   726  	RET
   727  	MOVW	s1_len+4(FP), R3
   728  	ADDU	R1, R3, R4
   729  loop:
   730  	BNE	R1, R4, 2(PC)
   731  	RET
   732  	MOVBU	(R1), R6
   733  	ADDU	$1, R1
   734  	MOVBU	(R2), R7
   735  	ADDU	$1, R2
   736  	BEQ	R6, R7, loop
   737  	MOVB	R0, ret+16(FP)
   738  	RET
   739  
   740  TEXT bytes·Equal(SB),NOSPLIT,$0-25
   741  	MOVW	a_len+4(FP), R3
   742  	MOVW	b_len+16(FP), R4
   743  	BNE	R3, R4, noteq	// unequal lengths are not equal
   744  
   745  	MOVW	a+0(FP), R1
   746  	MOVW	b+12(FP), R2
   747  	ADDU	R1, R3	// end
   748  
   749  loop:
   750  	BEQ	R1, R3, equal	// reached the end
   751  	MOVBU	(R1), R6
   752  	ADDU	$1, R1
   753  	MOVBU	(R2), R7
   754  	ADDU	$1, R2
   755  	BEQ	R6, R7, loop
   756  
   757  noteq:
   758  	MOVB	R0, ret+24(FP)
   759  	RET
   760  
   761  equal:
   762  	MOVW	$1, R1
   763  	MOVB	R1, ret+24(FP)
   764  	RET
   765  
   766  TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
   767  	MOVW	s+0(FP), R1
   768  	MOVW	s_len+4(FP), R2
   769  	MOVBU	c+12(FP), R3	// byte to find
   770  	ADDU	$1, R1, R4	// store base+1 for later
   771  	ADDU	R1, R2	// end
   772  
   773  loop:
   774  	BEQ	R1, R2, notfound
   775  	MOVBU	(R1), R5
   776  	ADDU	$1, R1
   777  	BNE	R3, R5, loop
   778  
   779  	SUBU	R4, R1	// R1 will be one beyond the position we want so remove (base+1)
   780  	MOVW	R1, ret+16(FP)
   781  	RET
   782  
   783  notfound:
   784  	MOVW	$-1, R1
   785  	MOVW	R1, ret+16(FP)
   786  	RET
   787  
   788  TEXT strings·IndexByte(SB),NOSPLIT,$0-16
   789  	MOVW	s_base+0(FP), R1
   790  	MOVW	s_len+4(FP), R2
   791  	MOVBU	c+8(FP), R3	// byte to find
   792  	ADDU	$1, R1, R4	// store base+1 for later
   793  	ADDU	R1, R2	// end
   794  
   795  loop:
   796  	BEQ	R1, R2, notfound
   797  	MOVBU	(R1), R5
   798  	ADDU	$1, R1
   799  	BNE	R3, R5, loop
   800  
   801  	SUBU	R4, R1	// remove (base+1)
   802  	MOVW	R1, ret+12(FP)
   803  	RET
   804  
   805  notfound:
   806  	MOVW	$-1, R1
   807  	MOVW	R1, ret+12(FP)
   808  	RET
   809  
   810  TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
   811  	MOVW	s1_base+0(FP), R3
   812  	MOVW	s1_len+4(FP), R1
   813  	MOVW	s2_base+8(FP), R4
   814  	MOVW	s2_len+12(FP), R2
   815  	BEQ	R3, R4, samebytes
   816  	SGTU	R1, R2, R7
   817  	MOVW	R1, R8
   818  	CMOVN	R7, R2, R8	// R8 is min(R1, R2)
   819  
   820  	ADDU	R3, R8	// R3 is current byte in s1, R8 is last byte in s1 to compare
   821  loop:
   822  	BEQ	R3, R8, samebytes	// all compared bytes were the same; compare lengths
   823  
   824  	MOVBU	(R3), R6
   825  	ADDU	$1, R3
   826  	MOVBU	(R4), R7
   827  	ADDU	$1, R4
   828  	BEQ	R6, R7 , loop
   829  	// bytes differed
   830  	SGTU	R6, R7, R8
   831  	MOVW	$-1, R6
   832  	CMOVZ	R8, R6, R8
   833  	JMP	cmp_ret
   834  samebytes:
   835  	SGTU	R1, R2, R6
   836  	SGTU	R2, R1, R7
   837  	SUBU	R7, R6, R8
   838  cmp_ret:
   839  	MOVW	R8, ret+16(FP)
   840  	RET
   841  
   842  TEXT bytes·Compare(SB),NOSPLIT,$0-28
   843  	MOVW	s1_base+0(FP), R3
   844  	MOVW	s2_base+12(FP), R4
   845  	MOVW	s1_len+4(FP), R1
   846  	MOVW	s2_len+16(FP), R2
   847  	BEQ	R3, R4, samebytes
   848  	SGTU	R1, R2, R7
   849  	MOVW	R1, R8
   850  	CMOVN	R7, R2, R8	// R8 is min(R1, R2)
   851  
   852  	ADDU	R3, R8	// R3 is current byte in s1, R8 is last byte in s1 to compare
   853  loop:
   854  	BEQ	R3, R8, samebytes
   855  
   856  	MOVBU	(R3), R6
   857  	ADDU	$1, R3
   858  	MOVBU	(R4), R7
   859  	ADDU	$1, R4
   860  	BEQ	R6, R7 , loop
   861  
   862  	SGTU	R6, R7, R8
   863  	MOVW	$-1, R6
   864  	CMOVZ	R8, R6, R8
   865  	JMP	cmp_ret
   866  samebytes:
   867  	SGTU	R1, R2, R6
   868  	SGTU	R2, R1, R7
   869  	SUBU	R7, R6, R8
   870  cmp_ret:
   871  	MOVW	R8, ret+24(FP)
   872  	RET
   873  
   874  TEXT runtime·return0(SB),NOSPLIT,$0
   875  	MOVW	$0, R1
   876  	RET
   877  
   878  // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
   879  // Must obey the gcc calling convention.
   880  TEXT _cgo_topofstack(SB),NOSPLIT,$-4
   881  	// g (R30), R3 and REGTMP (R23) might be clobbered by load_g. R30 and R23
   882  	// are callee-save in the gcc calling convention, so save them.
   883  	MOVW	R23, R8
   884  	MOVW	g, R9
   885  	MOVW	R31, R10 // this call frame does not save LR
   886  
   887  	JAL	runtime·load_g(SB)
   888  	MOVW	g_m(g), R1
   889  	MOVW	m_curg(R1), R1
   890  	MOVW	(g_stack+stack_hi)(R1), R2 // return value in R2
   891  
   892  	MOVW	R8, R23
   893  	MOVW	R9, g
   894  	MOVW	R10, R31
   895  
   896  	RET
   897  
   898  // The top-most function running on a goroutine
   899  // returns to goexit+PCQuantum.
   900  TEXT runtime·goexit(SB),NOSPLIT,$-4-0
   901  	NOR	R0, R0	// NOP
   902  	JAL	runtime·goexit1(SB)	// does not return
   903  	// traceback from goexit1 must hit code range of goexit
   904  	NOR	R0, R0	// NOP
   905  
   906  TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
   907  	RET
   908  
   909  TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
   910  	RET
   911  
   912  TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
   913  	RET
   914  
   915  TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
   916  	RET
   917  
   918  TEXT ·checkASM(SB),NOSPLIT,$0-1
   919  	MOVW	$1, R1
   920  	MOVB	R1, ret+0(FP)
   921  	RET