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