Home | History | Annotate | Download | only in runtime
      1 // Copyright 2015 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 mips64 mips64le
      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 runtimert0_go(SB),NOSPLIT,$0
     15 	// R29 = stack; R4 = argc; R5 = argv
     16 
     17 	ADDV	$-24, R29
     18 	MOVW	R4, 8(R29) // argc
     19 	MOVV	R5, 16(R29) // argv
     20 
     21 	// create istack out of the given (operating system) stack.
     22 	// _cgo_init may update stackguard.
     23 	MOVV	$runtimeg0(SB), g
     24 	MOVV	$(-64*1024), R23
     25 	ADDV	R23, R29, R1
     26 	MOVV	R1, g_stackguard0(g)
     27 	MOVV	R1, g_stackguard1(g)
     28 	MOVV	R1, (g_stack+stack_lo)(g)
     29 	MOVV	R29, (g_stack+stack_hi)(g)
     30 
     31 	// if there is a _cgo_init, call it using the gcc ABI.
     32 	MOVV	_cgo_init(SB), R25
     33 	BEQ	R25, nocgo
     34 
     35 	MOVV	R0, R7	// arg 3: not used
     36 	MOVV	R0, R6	// arg 2: not used
     37 	MOVV	$setg_gcc<>(SB), R5	// arg 1: setg
     38 	MOVV	g, R4	// arg 0: G
     39 	JAL	(R25)
     40 
     41 nocgo:
     42 	// update stackguard after _cgo_init
     43 	MOVV	(g_stack+stack_lo)(g), R1
     44 	ADDV	$const__StackGuard, R1
     45 	MOVV	R1, g_stackguard0(g)
     46 	MOVV	R1, g_stackguard1(g)
     47 
     48 	// set the per-goroutine and per-mach "registers"
     49 	MOVV	$runtimem0(SB), R1
     50 
     51 	// save m->g0 = g0
     52 	MOVV	g, m_g0(R1)
     53 	// save m0 to g0->m
     54 	MOVV	R1, g_m(g)
     55 
     56 	JAL	runtimecheck(SB)
     57 
     58 	// args are already prepared
     59 	JAL	runtimeargs(SB)
     60 	JAL	runtimeosinit(SB)
     61 	JAL	runtimeschedinit(SB)
     62 
     63 	// create a new goroutine to start program
     64 	MOVV	$runtimemainPC(SB), R1		// entry
     65 	ADDV	$-24, R29
     66 	MOVV	R1, 16(R29)
     67 	MOVV	R0, 8(R29)
     68 	MOVV	R0, 0(R29)
     69 	JAL	runtimenewproc(SB)
     70 	ADDV	$24, R29
     71 
     72 	// start this M
     73 	JAL	runtimemstart(SB)
     74 
     75 	MOVV	R0, 1(R0)
     76 	RET
     77 
     78 DATA	runtimemainPC+0(SB)/8,$runtimemain(SB)
     79 GLOBL	runtimemainPC(SB),RODATA,$8
     80 
     81 TEXT runtimebreakpoint(SB),NOSPLIT,$-8-0
     82 	MOVV	R0, 2(R0) // TODO: TD
     83 	RET
     84 
     85 TEXT runtimeasminit(SB),NOSPLIT,$-8-0
     86 	RET
     87 
     88 /*
     89  *  go-routine
     90  */
     91 
     92 // void gosave(Gobuf*)
     93 // save state in Gobuf; setjmp
     94 TEXT runtimegosave(SB), NOSPLIT, $-8-8
     95 	MOVV	buf+0(FP), R1
     96 	MOVV	R29, gobuf_sp(R1)
     97 	MOVV	R31, gobuf_pc(R1)
     98 	MOVV	g, gobuf_g(R1)
     99 	MOVV	R0, gobuf_lr(R1)
    100 	MOVV	R0, gobuf_ret(R1)
    101 	// Assert ctxt is zero. See func save.
    102 	MOVV	gobuf_ctxt(R1), R1
    103 	BEQ	R1, 2(PC)
    104 	JAL	runtimebadctxt(SB)
    105 	RET
    106 
    107 // void gogo(Gobuf*)
    108 // restore state from Gobuf; longjmp
    109 TEXT runtimegogo(SB), NOSPLIT, $16-8
    110 	MOVV	buf+0(FP), R3
    111 	MOVV	gobuf_g(R3), g	// make sure g is not nil
    112 	JAL	runtimesave_g(SB)
    113 
    114 	MOVV	0(g), R2
    115 	MOVV	gobuf_sp(R3), R29
    116 	MOVV	gobuf_lr(R3), R31
    117 	MOVV	gobuf_ret(R3), R1
    118 	MOVV	gobuf_ctxt(R3), REGCTXT
    119 	MOVV	R0, gobuf_sp(R3)
    120 	MOVV	R0, gobuf_ret(R3)
    121 	MOVV	R0, gobuf_lr(R3)
    122 	MOVV	R0, gobuf_ctxt(R3)
    123 	MOVV	gobuf_pc(R3), R4
    124 	JMP	(R4)
    125 
    126 // void mcall(fn func(*g))
    127 // Switch to m->g0's stack, call fn(g).
    128 // Fn must never return. It should gogo(&g->sched)
    129 // to keep running g.
    130 TEXT runtimemcall(SB), NOSPLIT, $-8-8
    131 	// Save caller state in g->sched
    132 	MOVV	R29, (g_sched+gobuf_sp)(g)
    133 	MOVV	R31, (g_sched+gobuf_pc)(g)
    134 	MOVV	R0, (g_sched+gobuf_lr)(g)
    135 	MOVV	g, (g_sched+gobuf_g)(g)
    136 
    137 	// Switch to m->g0 & its stack, call fn.
    138 	MOVV	g, R1
    139 	MOVV	g_m(g), R3
    140 	MOVV	m_g0(R3), g
    141 	JAL	runtimesave_g(SB)
    142 	BNE	g, R1, 2(PC)
    143 	JMP	runtimebadmcall(SB)
    144 	MOVV	fn+0(FP), REGCTXT			// context
    145 	MOVV	0(REGCTXT), R4			// code pointer
    146 	MOVV	(g_sched+gobuf_sp)(g), R29	// sp = m->g0->sched.sp
    147 	ADDV	$-16, R29
    148 	MOVV	R1, 8(R29)
    149 	MOVV	R0, 0(R29)
    150 	JAL	(R4)
    151 	JMP	runtimebadmcall2(SB)
    152 
    153 // systemstack_switch is a dummy routine that systemstack leaves at the bottom
    154 // of the G stack. We need to distinguish the routine that
    155 // lives at the bottom of the G stack from the one that lives
    156 // at the top of the system stack because the one at the top of
    157 // the system stack terminates the stack walk (see topofstack()).
    158 TEXT runtimesystemstack_switch(SB), NOSPLIT, $0-0
    159 	UNDEF
    160 	JAL	(R31)	// make sure this function is not leaf
    161 	RET
    162 
    163 // func systemstack(fn func())
    164 TEXT runtimesystemstack(SB), NOSPLIT, $0-8
    165 	MOVV	fn+0(FP), R1	// R1 = fn
    166 	MOVV	R1, REGCTXT		// context
    167 	MOVV	g_m(g), R2	// R2 = m
    168 
    169 	MOVV	m_gsignal(R2), R3	// R3 = gsignal
    170 	BEQ	g, R3, noswitch
    171 
    172 	MOVV	m_g0(R2), R3	// R3 = g0
    173 	BEQ	g, R3, noswitch
    174 
    175 	MOVV	m_curg(R2), R4
    176 	BEQ	g, R4, switch
    177 
    178 	// Bad: g is not gsignal, not g0, not curg. What is it?
    179 	// Hide call from linker nosplit analysis.
    180 	MOVV	$runtimebadsystemstack(SB), R4
    181 	JAL	(R4)
    182 
    183 switch:
    184 	// save our state in g->sched. Pretend to
    185 	// be systemstack_switch if the G stack is scanned.
    186 	MOVV	$runtimesystemstack_switch(SB), R4
    187 	ADDV	$8, R4	// get past prologue
    188 	MOVV	R4, (g_sched+gobuf_pc)(g)
    189 	MOVV	R29, (g_sched+gobuf_sp)(g)
    190 	MOVV	R0, (g_sched+gobuf_lr)(g)
    191 	MOVV	g, (g_sched+gobuf_g)(g)
    192 
    193 	// switch to g0
    194 	MOVV	R3, g
    195 	JAL	runtimesave_g(SB)
    196 	MOVV	(g_sched+gobuf_sp)(g), R1
    197 	// make it look like mstart called systemstack on g0, to stop traceback
    198 	ADDV	$-8, R1
    199 	MOVV	$runtimemstart(SB), R2
    200 	MOVV	R2, 0(R1)
    201 	MOVV	R1, R29
    202 
    203 	// call target function
    204 	MOVV	0(REGCTXT), R4	// code pointer
    205 	JAL	(R4)
    206 
    207 	// switch back to g
    208 	MOVV	g_m(g), R1
    209 	MOVV	m_curg(R1), g
    210 	JAL	runtimesave_g(SB)
    211 	MOVV	(g_sched+gobuf_sp)(g), R29
    212 	MOVV	R0, (g_sched+gobuf_sp)(g)
    213 	RET
    214 
    215 noswitch:
    216 	// already on m stack, just call directly
    217 	// Using a tail call here cleans up tracebacks since we won't stop
    218 	// at an intermediate systemstack.
    219 	MOVV	0(REGCTXT), R4	// code pointer
    220 	MOVV	0(R29), R31	// restore LR
    221 	ADDV	$8, R29
    222 	JMP	(R4)
    223 
    224 /*
    225  * support for morestack
    226  */
    227 
    228 // Called during function prolog when more stack is needed.
    229 // Caller has already loaded:
    230 // R1: framesize, R2: argsize, R3: LR
    231 //
    232 // The traceback routines see morestack on a g0 as being
    233 // the top of a stack (for example, morestack calling newstack
    234 // calling the scheduler calling newm calling gc), so we must
    235 // record an argument size. For that purpose, it has no arguments.
    236 TEXT runtimemorestack(SB),NOSPLIT,$-8-0
    237 	// Cannot grow scheduler stack (m->g0).
    238 	MOVV	g_m(g), R7
    239 	MOVV	m_g0(R7), R8
    240 	BNE	g, R8, 3(PC)
    241 	JAL	runtimebadmorestackg0(SB)
    242 	JAL	runtimeabort(SB)
    243 
    244 	// Cannot grow signal stack (m->gsignal).
    245 	MOVV	m_gsignal(R7), R8
    246 	BNE	g, R8, 3(PC)
    247 	JAL	runtimebadmorestackgsignal(SB)
    248 	JAL	runtimeabort(SB)
    249 
    250 	// Called from f.
    251 	// Set g->sched to context in f.
    252 	MOVV	R29, (g_sched+gobuf_sp)(g)
    253 	MOVV	R31, (g_sched+gobuf_pc)(g)
    254 	MOVV	R3, (g_sched+gobuf_lr)(g)
    255 	MOVV	REGCTXT, (g_sched+gobuf_ctxt)(g)
    256 
    257 	// Called from f.
    258 	// Set m->morebuf to f's caller.
    259 	MOVV	R3, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
    260 	MOVV	R29, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
    261 	MOVV	g, (m_morebuf+gobuf_g)(R7)
    262 
    263 	// Call newstack on m->g0's stack.
    264 	MOVV	m_g0(R7), g
    265 	JAL	runtimesave_g(SB)
    266 	MOVV	(g_sched+gobuf_sp)(g), R29
    267 	// Create a stack frame on g0 to call newstack.
    268 	MOVV	R0, -8(R29)	// Zero saved LR in frame
    269 	ADDV	$-8, R29
    270 	JAL	runtimenewstack(SB)
    271 
    272 	// Not reached, but make sure the return PC from the call to newstack
    273 	// is still in this function, and not the beginning of the next.
    274 	UNDEF
    275 
    276 TEXT runtimemorestack_noctxt(SB),NOSPLIT,$-8-0
    277 	MOVV	R0, REGCTXT
    278 	JMP	runtimemorestack(SB)
    279 
    280 // reflectcall: call a function with the given argument list
    281 // func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
    282 // we don't have variable-sized frames, so we use a small number
    283 // of constant-sized-frame functions to encode a few bits of size in the pc.
    284 // Caution: ugly multiline assembly macros in your future!
    285 
    286 #define DISPATCH(NAME,MAXSIZE)		\
    287 	MOVV	$MAXSIZE, R23;		\
    288 	SGTU	R1, R23, R23;		\
    289 	BNE	R23, 3(PC);			\
    290 	MOVV	$NAME(SB), R4;	\
    291 	JMP	(R4)
    292 // Note: can't just "BR NAME(SB)" - bad inlining results.
    293 
    294 TEXT reflectcall(SB), NOSPLIT, $0-0
    295 	JMP	reflectcall(SB)
    296 
    297 TEXT reflectcall(SB), NOSPLIT, $-8-32
    298 	MOVWU argsize+24(FP), R1
    299 	DISPATCH(runtimecall32, 32)
    300 	DISPATCH(runtimecall64, 64)
    301 	DISPATCH(runtimecall128, 128)
    302 	DISPATCH(runtimecall256, 256)
    303 	DISPATCH(runtimecall512, 512)
    304 	DISPATCH(runtimecall1024, 1024)
    305 	DISPATCH(runtimecall2048, 2048)
    306 	DISPATCH(runtimecall4096, 4096)
    307 	DISPATCH(runtimecall8192, 8192)
    308 	DISPATCH(runtimecall16384, 16384)
    309 	DISPATCH(runtimecall32768, 32768)
    310 	DISPATCH(runtimecall65536, 65536)
    311 	DISPATCH(runtimecall131072, 131072)
    312 	DISPATCH(runtimecall262144, 262144)
    313 	DISPATCH(runtimecall524288, 524288)
    314 	DISPATCH(runtimecall1048576, 1048576)
    315 	DISPATCH(runtimecall2097152, 2097152)
    316 	DISPATCH(runtimecall4194304, 4194304)
    317 	DISPATCH(runtimecall8388608, 8388608)
    318 	DISPATCH(runtimecall16777216, 16777216)
    319 	DISPATCH(runtimecall33554432, 33554432)
    320 	DISPATCH(runtimecall67108864, 67108864)
    321 	DISPATCH(runtimecall134217728, 134217728)
    322 	DISPATCH(runtimecall268435456, 268435456)
    323 	DISPATCH(runtimecall536870912, 536870912)
    324 	DISPATCH(runtimecall1073741824, 1073741824)
    325 	MOVV	$runtimebadreflectcall(SB), R4
    326 	JMP	(R4)
    327 
    328 #define CALLFN(NAME,MAXSIZE)			\
    329 TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
    330 	NO_LOCAL_POINTERS;			\
    331 	/* copy arguments to stack */		\
    332 	MOVV	arg+16(FP), R1;			\
    333 	MOVWU	argsize+24(FP), R2;			\
    334 	MOVV	R29, R3;				\
    335 	ADDV	$8, R3;			\
    336 	ADDV	R3, R2;				\
    337 	BEQ	R3, R2, 6(PC);				\
    338 	MOVBU	(R1), R4;			\
    339 	ADDV	$1, R1;			\
    340 	MOVBU	R4, (R3);			\
    341 	ADDV	$1, R3;			\
    342 	JMP	-5(PC);				\
    343 	/* call function */			\
    344 	MOVV	f+8(FP), REGCTXT;			\
    345 	MOVV	(REGCTXT), R4;			\
    346 	PCDATA  $PCDATA_StackMapIndex, $0;	\
    347 	JAL	(R4);				\
    348 	/* copy return values back */		\
    349 	MOVV	argtype+0(FP), R5;		\
    350 	MOVV	arg+16(FP), R1;			\
    351 	MOVWU	n+24(FP), R2;			\
    352 	MOVWU	retoffset+28(FP), R4;		\
    353 	ADDV	$8, R29, R3;				\
    354 	ADDV	R4, R3; 			\
    355 	ADDV	R4, R1;				\
    356 	SUBVU	R4, R2;				\
    357 	JAL	callRet<>(SB);			\
    358 	RET
    359 
    360 // callRet copies return values back at the end of call*. This is a
    361 // separate function so it can allocate stack space for the arguments
    362 // to reflectcallmove. It does not follow the Go ABI; it expects its
    363 // arguments in registers.
    364 TEXT callRet<>(SB), NOSPLIT, $32-0
    365 	MOVV	R5, 8(R29)
    366 	MOVV	R1, 16(R29)
    367 	MOVV	R3, 24(R29)
    368 	MOVV	R2, 32(R29)
    369 	JAL	runtimereflectcallmove(SB)
    370 	RET
    371 
    372 CALLFN(call16, 16)
    373 CALLFN(call32, 32)
    374 CALLFN(call64, 64)
    375 CALLFN(call128, 128)
    376 CALLFN(call256, 256)
    377 CALLFN(call512, 512)
    378 CALLFN(call1024, 1024)
    379 CALLFN(call2048, 2048)
    380 CALLFN(call4096, 4096)
    381 CALLFN(call8192, 8192)
    382 CALLFN(call16384, 16384)
    383 CALLFN(call32768, 32768)
    384 CALLFN(call65536, 65536)
    385 CALLFN(call131072, 131072)
    386 CALLFN(call262144, 262144)
    387 CALLFN(call524288, 524288)
    388 CALLFN(call1048576, 1048576)
    389 CALLFN(call2097152, 2097152)
    390 CALLFN(call4194304, 4194304)
    391 CALLFN(call8388608, 8388608)
    392 CALLFN(call16777216, 16777216)
    393 CALLFN(call33554432, 33554432)
    394 CALLFN(call67108864, 67108864)
    395 CALLFN(call134217728, 134217728)
    396 CALLFN(call268435456, 268435456)
    397 CALLFN(call536870912, 536870912)
    398 CALLFN(call1073741824, 1073741824)
    399 
    400 TEXT runtimeprocyield(SB),NOSPLIT,$0-0
    401 	RET
    402 
    403 // void jmpdefer(fv, sp);
    404 // called from deferreturn.
    405 // 1. grab stored LR for caller
    406 // 2. sub 8 bytes to get back to JAL deferreturn
    407 // 3. JMP to fn
    408 TEXT runtimejmpdefer(SB), NOSPLIT, $-8-16
    409 	MOVV	0(R29), R31
    410 	ADDV	$-8, R31
    411 
    412 	MOVV	fv+0(FP), REGCTXT
    413 	MOVV	argp+8(FP), R29
    414 	ADDV	$-8, R29
    415 	NOR	R0, R0	// prevent scheduling
    416 	MOVV	0(REGCTXT), R4
    417 	JMP	(R4)
    418 
    419 // Save state of caller into g->sched. Smashes R1.
    420 TEXT gosave<>(SB),NOSPLIT,$-8
    421 	MOVV	R31, (g_sched+gobuf_pc)(g)
    422 	MOVV	R29, (g_sched+gobuf_sp)(g)
    423 	MOVV	R0, (g_sched+gobuf_lr)(g)
    424 	MOVV	R0, (g_sched+gobuf_ret)(g)
    425 	// Assert ctxt is zero. See func save.
    426 	MOVV	(g_sched+gobuf_ctxt)(g), R1
    427 	BEQ	R1, 2(PC)
    428 	JAL	runtimebadctxt(SB)
    429 	RET
    430 
    431 // func asmcgocall(fn, arg unsafe.Pointer) int32
    432 // Call fn(arg) on the scheduler stack,
    433 // aligned appropriately for the gcc ABI.
    434 // See cgocall.go for more details.
    435 TEXT asmcgocall(SB),NOSPLIT,$0-20
    436 	MOVV	fn+0(FP), R25
    437 	MOVV	arg+8(FP), R4
    438 
    439 	MOVV	R29, R3	// save original stack pointer
    440 	MOVV	g, R2
    441 
    442 	// Figure out if we need to switch to m->g0 stack.
    443 	// We get called to create new OS threads too, and those
    444 	// come in on the m->g0 stack already.
    445 	MOVV	g_m(g), R5
    446 	MOVV	m_g0(R5), R6
    447 	BEQ	R6, g, g0
    448 
    449 	JAL	gosave<>(SB)
    450 	MOVV	R6, g
    451 	JAL	runtimesave_g(SB)
    452 	MOVV	(g_sched+gobuf_sp)(g), R29
    453 
    454 	// Now on a scheduling stack (a pthread-created stack).
    455 g0:
    456 	// Save room for two of our pointers.
    457 	ADDV	$-16, R29
    458 	MOVV	R2, 0(R29)	// save old g on stack
    459 	MOVV	(g_stack+stack_hi)(R2), R2
    460 	SUBVU	R3, R2
    461 	MOVV	R2, 8(R29)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
    462 	JAL	(R25)
    463 
    464 	// Restore g, stack pointer. R2 is return value.
    465 	MOVV	0(R29), g
    466 	JAL	runtimesave_g(SB)
    467 	MOVV	(g_stack+stack_hi)(g), R5
    468 	MOVV	8(R29), R6
    469 	SUBVU	R6, R5
    470 	MOVV	R5, R29
    471 
    472 	MOVW	R2, ret+16(FP)
    473 	RET
    474 
    475 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
    476 // Turn the fn into a Go func (by taking its address) and call
    477 // cgocallback_gofunc.
    478 TEXT runtimecgocallback(SB),NOSPLIT,$32-32
    479 	MOVV	$fn+0(FP), R1
    480 	MOVV	R1, 8(R29)
    481 	MOVV	frame+8(FP), R1
    482 	MOVV	R1, 16(R29)
    483 	MOVV	framesize+16(FP), R1
    484 	MOVV	R1, 24(R29)
    485 	MOVV	ctxt+24(FP), R1
    486 	MOVV	R1, 32(R29)
    487 	MOVV	$runtimecgocallback_gofunc(SB), R1
    488 	JAL	(R1)
    489 	RET
    490 
    491 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
    492 // See cgocall.go for more details.
    493 TEXT cgocallback_gofunc(SB),NOSPLIT,$16-32
    494 	NO_LOCAL_POINTERS
    495 
    496 	// Load m and g from thread-local storage.
    497 	MOVB	runtimeiscgo(SB), R1
    498 	BEQ	R1, nocgo
    499 	JAL	runtimeload_g(SB)
    500 nocgo:
    501 
    502 	// If g is nil, Go did not create the current thread.
    503 	// Call needm to obtain one for temporary use.
    504 	// In this case, we're running on the thread stack, so there's
    505 	// lots of space, but the linker doesn't know. Hide the call from
    506 	// the linker analysis by using an indirect call.
    507 	BEQ	g, needm
    508 
    509 	MOVV	g_m(g), R3
    510 	MOVV	R3, savedm-8(SP)
    511 	JMP	havem
    512 
    513 needm:
    514 	MOVV	g, savedm-8(SP) // g is zero, so is m.
    515 	MOVV	$runtimeneedm(SB), R4
    516 	JAL	(R4)
    517 
    518 	// Set m->sched.sp = SP, so that if a panic happens
    519 	// during the function we are about to execute, it will
    520 	// have a valid SP to run on the g0 stack.
    521 	// The next few lines (after the havem label)
    522 	// will save this SP onto the stack and then write
    523 	// the same SP back to m->sched.sp. That seems redundant,
    524 	// but if an unrecovered panic happens, unwindm will
    525 	// restore the g->sched.sp from the stack location
    526 	// and then systemstack will try to use it. If we don't set it here,
    527 	// that restored SP will be uninitialized (typically 0) and
    528 	// will not be usable.
    529 	MOVV	g_m(g), R3
    530 	MOVV	m_g0(R3), R1
    531 	MOVV	R29, (g_sched+gobuf_sp)(R1)
    532 
    533 havem:
    534 	// Now there's a valid m, and we're running on its m->g0.
    535 	// Save current m->g0->sched.sp on stack and then set it to SP.
    536 	// Save current sp in m->g0->sched.sp in preparation for
    537 	// switch back to m->curg stack.
    538 	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R29) aka savedsp-16(SP).
    539 	MOVV	m_g0(R3), R1
    540 	MOVV	(g_sched+gobuf_sp)(R1), R2
    541 	MOVV	R2, savedsp-16(SP)
    542 	MOVV	R29, (g_sched+gobuf_sp)(R1)
    543 
    544 	// Switch to m->curg stack and call runtime.cgocallbackg.
    545 	// Because we are taking over the execution of m->curg
    546 	// but *not* resuming what had been running, we need to
    547 	// save that information (m->curg->sched) so we can restore it.
    548 	// We can restore m->curg->sched.sp easily, because calling
    549 	// runtime.cgocallbackg leaves SP unchanged upon return.
    550 	// To save m->curg->sched.pc, we push it onto the stack.
    551 	// This has the added benefit that it looks to the traceback
    552 	// routine like cgocallbackg is going to return to that
    553 	// PC (because the frame we allocate below has the same
    554 	// size as cgocallback_gofunc's frame declared above)
    555 	// so that the traceback will seamlessly trace back into
    556 	// the earlier calls.
    557 	//
    558 	// In the new goroutine, -8(SP) is unused (where SP refers to
    559 	// m->curg's SP while we're setting it up, before we've adjusted it).
    560 	MOVV	m_curg(R3), g
    561 	JAL	runtimesave_g(SB)
    562 	MOVV	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
    563 	MOVV	(g_sched+gobuf_pc)(g), R4
    564 	MOVV	R4, -24(R2)
    565 	MOVV    ctxt+24(FP), R1
    566 	MOVV    R1, -16(R2)
    567 	MOVV	$-24(R2), R29
    568 	JAL	runtimecgocallbackg(SB)
    569 
    570 	// Restore g->sched (== m->curg->sched) from saved values.
    571 	MOVV	0(R29), R4
    572 	MOVV	R4, (g_sched+gobuf_pc)(g)
    573 	MOVV	$24(R29), R2
    574 	MOVV	R2, (g_sched+gobuf_sp)(g)
    575 
    576 	// Switch back to m->g0's stack and restore m->g0->sched.sp.
    577 	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
    578 	// so we do not have to restore it.)
    579 	MOVV	g_m(g), R3
    580 	MOVV	m_g0(R3), g
    581 	JAL	runtimesave_g(SB)
    582 	MOVV	(g_sched+gobuf_sp)(g), R29
    583 	MOVV	savedsp-16(SP), R2
    584 	MOVV	R2, (g_sched+gobuf_sp)(g)
    585 
    586 	// If the m on entry was nil, we called needm above to borrow an m
    587 	// for the duration of the call. Since the call is over, return it with dropm.
    588 	MOVV	savedm-8(SP), R3
    589 	BNE	R3, droppedm
    590 	MOVV	$runtimedropm(SB), R4
    591 	JAL	(R4)
    592 droppedm:
    593 
    594 	// Done!
    595 	RET
    596 
    597 // void setg(G*); set g. for use by needm.
    598 TEXT runtimesetg(SB), NOSPLIT, $0-8
    599 	MOVV	gg+0(FP), g
    600 	// This only happens if iscgo, so jump straight to save_g
    601 	JAL	runtimesave_g(SB)
    602 	RET
    603 
    604 // void setg_gcc(G*); set g called from gcc with g in R1
    605 TEXT setg_gcc<>(SB),NOSPLIT,$0-0
    606 	MOVV	R1, g
    607 	JAL	runtimesave_g(SB)
    608 	RET
    609 
    610 TEXT runtimegetcallerpc(SB),NOSPLIT,$-8-8
    611 	MOVV	0(R29), R1		// LR saved by caller
    612 	MOVV	R1, ret+0(FP)
    613 	RET
    614 
    615 TEXT runtimeabort(SB),NOSPLIT,$-8-0
    616 	MOVW	(R0), R0
    617 	UNDEF
    618 
    619 // AES hashing not implemented for mips64
    620 TEXT runtimeaeshash(SB),NOSPLIT,$-8-0
    621 	MOVW	(R0), R1
    622 TEXT runtimeaeshash32(SB),NOSPLIT,$-8-0
    623 	MOVW	(R0), R1
    624 TEXT runtimeaeshash64(SB),NOSPLIT,$-8-0
    625 	MOVW	(R0), R1
    626 TEXT runtimeaeshashstr(SB),NOSPLIT,$-8-0
    627 	MOVW	(R0), R1
    628 
    629 // memequal(p, q unsafe.Pointer, size uintptr) bool
    630 TEXT runtimememequal(SB),NOSPLIT,$-8-25
    631 	MOVV	a+0(FP), R1
    632 	MOVV	b+8(FP), R2
    633 	BEQ	R1, R2, eq
    634 	MOVV	size+16(FP), R3
    635 	ADDV	R1, R3, R4
    636 loop:
    637 	BNE	R1, R4, test
    638 	MOVV	$1, R1
    639 	MOVB	R1, ret+24(FP)
    640 	RET
    641 test:
    642 	MOVBU	(R1), R6
    643 	ADDV	$1, R1
    644 	MOVBU	(R2), R7
    645 	ADDV	$1, R2
    646 	BEQ	R6, R7, loop
    647 
    648 	MOVB	R0, ret+24(FP)
    649 	RET
    650 eq:
    651 	MOVV	$1, R1
    652 	MOVB	R1, ret+24(FP)
    653 	RET
    654 
    655 // memequal_varlen(a, b unsafe.Pointer) bool
    656 TEXT runtimememequal_varlen(SB),NOSPLIT,$40-17
    657 	MOVV	a+0(FP), R1
    658 	MOVV	b+8(FP), R2
    659 	BEQ	R1, R2, eq
    660 	MOVV	8(REGCTXT), R3    // compiler stores size at offset 8 in the closure
    661 	MOVV	R1, 8(R29)
    662 	MOVV	R2, 16(R29)
    663 	MOVV	R3, 24(R29)
    664 	JAL	runtimememequal(SB)
    665 	MOVBU	32(R29), R1
    666 	MOVB	R1, ret+16(FP)
    667 	RET
    668 eq:
    669 	MOVV	$1, R1
    670 	MOVB	R1, ret+16(FP)
    671 	RET
    672 
    673 // TODO: share code with memequal?
    674 TEXT bytesEqual(SB),NOSPLIT,$0-49
    675 	MOVV	a_len+8(FP), R3
    676 	MOVV	b_len+32(FP), R4
    677 	BNE	R3, R4, noteq		// unequal lengths are not equal
    678 
    679 	MOVV	a+0(FP), R1
    680 	MOVV	b+24(FP), R2
    681 	ADDV	R1, R3		// end
    682 
    683 loop:
    684 	BEQ	R1, R3, equal		// reached the end
    685 	MOVBU	(R1), R6
    686 	ADDV	$1, R1
    687 	MOVBU	(R2), R7
    688 	ADDV	$1, R2
    689 	BEQ	R6, R7, loop
    690 
    691 noteq:
    692 	MOVB	R0, ret+48(FP)
    693 	RET
    694 
    695 equal:
    696 	MOVV	$1, R1
    697 	MOVB	R1, ret+48(FP)
    698 	RET
    699 
    700 TEXT bytesIndexByte(SB),NOSPLIT,$0-40
    701 	MOVV	s+0(FP), R1
    702 	MOVV	s_len+8(FP), R2
    703 	MOVBU	c+24(FP), R3	// byte to find
    704 	MOVV	R1, R4		// store base for later
    705 	ADDV	R1, R2		// end
    706 	ADDV	$-1, R1
    707 
    708 loop:
    709 	ADDV	$1, R1
    710 	BEQ	R1, R2, notfound
    711 	MOVBU	(R1), R5
    712 	BNE	R3, R5, loop
    713 
    714 	SUBV	R4, R1		// remove base
    715 	MOVV	R1, ret+32(FP)
    716 	RET
    717 
    718 notfound:
    719 	MOVV	$-1, R1
    720 	MOVV	R1, ret+32(FP)
    721 	RET
    722 
    723 TEXT stringsIndexByte(SB),NOSPLIT,$0-32
    724 	MOVV	p+0(FP), R1
    725 	MOVV	b_len+8(FP), R2
    726 	MOVBU	c+16(FP), R3	// byte to find
    727 	MOVV	R1, R4		// store base for later
    728 	ADDV	R1, R2		// end
    729 	ADDV	$-1, R1
    730 
    731 loop:
    732 	ADDV	$1, R1
    733 	BEQ	R1, R2, notfound
    734 	MOVBU	(R1), R5
    735 	BNE	R3, R5, loop
    736 
    737 	SUBV	R4, R1		// remove base
    738 	MOVV	R1, ret+24(FP)
    739 	RET
    740 
    741 notfound:
    742 	MOVV	$-1, R1
    743 	MOVV	R1, ret+24(FP)
    744 	RET
    745 
    746 TEXT runtimereturn0(SB), NOSPLIT, $0
    747 	MOVW	$0, R1
    748 	RET
    749 
    750 // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
    751 // Must obey the gcc calling convention.
    752 TEXT _cgo_topofstack(SB),NOSPLIT,$16
    753 	// g (R30) and REGTMP (R23)  might be clobbered by load_g. They
    754 	// are callee-save in the gcc calling convention, so save them.
    755 	MOVV	R23, savedR23-16(SP)
    756 	MOVV	g, savedG-8(SP)
    757 
    758 	JAL	runtimeload_g(SB)
    759 	MOVV	g_m(g), R1
    760 	MOVV	m_curg(R1), R1
    761 	MOVV	(g_stack+stack_hi)(R1), R2 // return value in R2
    762 
    763 	MOVV	savedG-8(SP), g
    764 	MOVV	savedR23-16(SP), R23
    765 	RET
    766 
    767 // The top-most function running on a goroutine
    768 // returns to goexit+PCQuantum.
    769 TEXT runtimegoexit(SB),NOSPLIT,$-8-0
    770 	NOR	R0, R0	// NOP
    771 	JAL	runtimegoexit1(SB)	// does not return
    772 	// traceback from goexit1 must hit code range of goexit
    773 	NOR	R0, R0	// NOP
    774 
    775 TEXT checkASM(SB),NOSPLIT,$0-1
    776 	MOVW	$1, R1
    777 	MOVB	R1, ret+0(FP)
    778 	RET
    779