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//go: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
14TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$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	$runtime·g0(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
41nocgo:
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	$runtime·m0(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	runtime·check(SB)
57
58	// args are already prepared
59	JAL	runtime·args(SB)
60	JAL	runtime·osinit(SB)
61	JAL	runtime·schedinit(SB)
62
63	// create a new goroutine to start program
64	MOVV	$runtime·mainPC(SB), R1		// entry
65	ADDV	$-16, R29
66	MOVV	R1, 8(R29)
67	MOVV	R0, 0(R29)
68	JAL	runtime·newproc(SB)
69	ADDV	$16, R29
70
71	// start this M
72	JAL	runtime·mstart(SB)
73
74	MOVV	R0, 1(R0)
75	RET
76
77DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
78GLOBL	runtime·mainPC(SB),RODATA,$8
79
80TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
81	MOVV	R0, 2(R0) // TODO: TD
82	RET
83
84TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
85	RET
86
87TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0
88	JAL	runtime·mstart0(SB)
89	RET // not reached
90
91/*
92 *  go-routine
93 */
94
95// void gogo(Gobuf*)
96// restore state from Gobuf; longjmp
97TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8
98	MOVV	buf+0(FP), R3
99	MOVV	gobuf_g(R3), R4
100	MOVV	0(R4), R0	// make sure g != nil
101	JMP	gogo<>(SB)
102
103TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
104	MOVV	R4, g
105	JAL	runtime·save_g(SB)
106
107	MOVV	0(g), R2
108	MOVV	gobuf_sp(R3), R29
109	MOVV	gobuf_lr(R3), R31
110	MOVV	gobuf_ret(R3), R1
111	MOVV	gobuf_ctxt(R3), REGCTXT
112	MOVV	R0, gobuf_sp(R3)
113	MOVV	R0, gobuf_ret(R3)
114	MOVV	R0, gobuf_lr(R3)
115	MOVV	R0, gobuf_ctxt(R3)
116	MOVV	gobuf_pc(R3), R4
117	JMP	(R4)
118
119// void mcall(fn func(*g))
120// Switch to m->g0's stack, call fn(g).
121// Fn must never return. It should gogo(&g->sched)
122// to keep running g.
123TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
124	// Save caller state in g->sched
125	MOVV	R29, (g_sched+gobuf_sp)(g)
126	MOVV	R31, (g_sched+gobuf_pc)(g)
127	MOVV	R0, (g_sched+gobuf_lr)(g)
128
129	// Switch to m->g0 & its stack, call fn.
130	MOVV	g, R1
131	MOVV	g_m(g), R3
132	MOVV	m_g0(R3), g
133	JAL	runtime·save_g(SB)
134	BNE	g, R1, 2(PC)
135	JMP	runtime·badmcall(SB)
136	MOVV	fn+0(FP), REGCTXT			// context
137	MOVV	0(REGCTXT), R4			// code pointer
138	MOVV	(g_sched+gobuf_sp)(g), R29	// sp = m->g0->sched.sp
139	ADDV	$-16, R29
140	MOVV	R1, 8(R29)
141	MOVV	R0, 0(R29)
142	JAL	(R4)
143	JMP	runtime·badmcall2(SB)
144
145// systemstack_switch is a dummy routine that systemstack leaves at the bottom
146// of the G stack. We need to distinguish the routine that
147// lives at the bottom of the G stack from the one that lives
148// at the top of the system stack because the one at the top of
149// the system stack terminates the stack walk (see topofstack()).
150TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
151	UNDEF
152	JAL	(R31)	// make sure this function is not leaf
153	RET
154
155// func systemstack(fn func())
156TEXT runtime·systemstack(SB), NOSPLIT, $0-8
157	MOVV	fn+0(FP), R1	// R1 = fn
158	MOVV	R1, REGCTXT		// context
159	MOVV	g_m(g), R2	// R2 = m
160
161	MOVV	m_gsignal(R2), R3	// R3 = gsignal
162	BEQ	g, R3, noswitch
163
164	MOVV	m_g0(R2), R3	// R3 = g0
165	BEQ	g, R3, noswitch
166
167	MOVV	m_curg(R2), R4
168	BEQ	g, R4, switch
169
170	// Bad: g is not gsignal, not g0, not curg. What is it?
171	// Hide call from linker nosplit analysis.
172	MOVV	$runtime·badsystemstack(SB), R4
173	JAL	(R4)
174	JAL	runtime·abort(SB)
175
176switch:
177	// save our state in g->sched. Pretend to
178	// be systemstack_switch if the G stack is scanned.
179	JAL	gosave_systemstack_switch<>(SB)
180
181	// switch to g0
182	MOVV	R3, g
183	JAL	runtime·save_g(SB)
184	MOVV	(g_sched+gobuf_sp)(g), R1
185	MOVV	R1, R29
186
187	// call target function
188	MOVV	0(REGCTXT), R4	// code pointer
189	JAL	(R4)
190
191	// switch back to g
192	MOVV	g_m(g), R1
193	MOVV	m_curg(R1), g
194	JAL	runtime·save_g(SB)
195	MOVV	(g_sched+gobuf_sp)(g), R29
196	MOVV	R0, (g_sched+gobuf_sp)(g)
197	RET
198
199noswitch:
200	// already on m stack, just call directly
201	// Using a tail call here cleans up tracebacks since we won't stop
202	// at an intermediate systemstack.
203	MOVV	0(REGCTXT), R4	// code pointer
204	MOVV	0(R29), R31	// restore LR
205	ADDV	$8, R29
206	JMP	(R4)
207
208// func switchToCrashStack0(fn func())
209TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8
210	MOVV	fn+0(FP), REGCTXT	// context register
211	MOVV	g_m(g), R2	// curm
212
213	// set g to gcrash
214	MOVV	$runtime·gcrash(SB), g	// g = &gcrash
215	CALL	runtime·save_g(SB)
216	MOVV	R2, g_m(g)	// g.m = curm
217	MOVV	g, m_g0(R2)	// curm.g0 = g
218
219	// switch to crashstack
220	MOVV	(g_stack+stack_hi)(g), R2
221	ADDV	$(-4*8), R2, R29
222
223	// call target function
224	MOVV	0(REGCTXT), R25
225	JAL	(R25)
226
227	// should never return
228	CALL	runtime·abort(SB)
229	UNDEF
230
231/*
232 * support for morestack
233 */
234
235// Called during function prolog when more stack is needed.
236// Caller has already loaded:
237// R1: framesize, R2: argsize, R3: LR
238//
239// The traceback routines see morestack on a g0 as being
240// the top of a stack (for example, morestack calling newstack
241// calling the scheduler calling newm calling gc), so we must
242// record an argument size. For that purpose, it has no arguments.
243TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
244	// Called from f.
245	// Set g->sched to context in f.
246	MOVV	R29, (g_sched+gobuf_sp)(g)
247	MOVV	R31, (g_sched+gobuf_pc)(g)
248	MOVV	R3, (g_sched+gobuf_lr)(g)
249	MOVV	REGCTXT, (g_sched+gobuf_ctxt)(g)
250
251	// Cannot grow scheduler stack (m->g0).
252	MOVV	g_m(g), R7
253	MOVV	m_g0(R7), R8
254	BNE	g, R8, 3(PC)
255	JAL	runtime·badmorestackg0(SB)
256	JAL	runtime·abort(SB)
257
258	// Cannot grow signal stack (m->gsignal).
259	MOVV	m_gsignal(R7), R8
260	BNE	g, R8, 3(PC)
261	JAL	runtime·badmorestackgsignal(SB)
262	JAL	runtime·abort(SB)
263
264	// Called from f.
265	// Set m->morebuf to f's caller.
266	MOVV	R3, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
267	MOVV	R29, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
268	MOVV	g, (m_morebuf+gobuf_g)(R7)
269
270	// Call newstack on m->g0's stack.
271	MOVV	m_g0(R7), g
272	JAL	runtime·save_g(SB)
273	MOVV	(g_sched+gobuf_sp)(g), R29
274	// Create a stack frame on g0 to call newstack.
275	MOVV	R0, -8(R29)	// Zero saved LR in frame
276	ADDV	$-8, R29
277	JAL	runtime·newstack(SB)
278
279	// Not reached, but make sure the return PC from the call to newstack
280	// is still in this function, and not the beginning of the next.
281	UNDEF
282
283TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0
284	// Force SPWRITE. This function doesn't actually write SP,
285	// but it is called with a special calling convention where
286	// the caller doesn't save LR on stack but passes it as a
287	// register (R3), and the unwinder currently doesn't understand.
288	// Make it SPWRITE to stop unwinding. (See issue 54332)
289	MOVV	R29, R29
290
291	MOVV	R0, REGCTXT
292	JMP	runtime·morestack(SB)
293
294// reflectcall: call a function with the given argument list
295// func call(stackArgsType *_type, f *FuncVal, stackArgs *byte, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs).
296// we don't have variable-sized frames, so we use a small number
297// of constant-sized-frame functions to encode a few bits of size in the pc.
298// Caution: ugly multiline assembly macros in your future!
299
300#define DISPATCH(NAME,MAXSIZE)		\
301	MOVV	$MAXSIZE, R23;		\
302	SGTU	R1, R23, R23;		\
303	BNE	R23, 3(PC);			\
304	MOVV	$NAME(SB), R4;	\
305	JMP	(R4)
306// Note: can't just "BR NAME(SB)" - bad inlining results.
307
308TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-48
309	MOVWU	frameSize+32(FP), R1
310	DISPATCH(runtime·call16, 16)
311	DISPATCH(runtime·call32, 32)
312	DISPATCH(runtime·call64, 64)
313	DISPATCH(runtime·call128, 128)
314	DISPATCH(runtime·call256, 256)
315	DISPATCH(runtime·call512, 512)
316	DISPATCH(runtime·call1024, 1024)
317	DISPATCH(runtime·call2048, 2048)
318	DISPATCH(runtime·call4096, 4096)
319	DISPATCH(runtime·call8192, 8192)
320	DISPATCH(runtime·call16384, 16384)
321	DISPATCH(runtime·call32768, 32768)
322	DISPATCH(runtime·call65536, 65536)
323	DISPATCH(runtime·call131072, 131072)
324	DISPATCH(runtime·call262144, 262144)
325	DISPATCH(runtime·call524288, 524288)
326	DISPATCH(runtime·call1048576, 1048576)
327	DISPATCH(runtime·call2097152, 2097152)
328	DISPATCH(runtime·call4194304, 4194304)
329	DISPATCH(runtime·call8388608, 8388608)
330	DISPATCH(runtime·call16777216, 16777216)
331	DISPATCH(runtime·call33554432, 33554432)
332	DISPATCH(runtime·call67108864, 67108864)
333	DISPATCH(runtime·call134217728, 134217728)
334	DISPATCH(runtime·call268435456, 268435456)
335	DISPATCH(runtime·call536870912, 536870912)
336	DISPATCH(runtime·call1073741824, 1073741824)
337	MOVV	$runtime·badreflectcall(SB), R4
338	JMP	(R4)
339
340#define CALLFN(NAME,MAXSIZE)			\
341TEXT NAME(SB), WRAPPER, $MAXSIZE-48;		\
342	NO_LOCAL_POINTERS;			\
343	/* copy arguments to stack */		\
344	MOVV	stackArgs+16(FP), R1;			\
345	MOVWU	stackArgsSize+24(FP), R2;			\
346	MOVV	R29, R3;				\
347	ADDV	$8, R3;			\
348	ADDV	R3, R2;				\
349	BEQ	R3, R2, 6(PC);				\
350	MOVBU	(R1), R4;			\
351	ADDV	$1, R1;			\
352	MOVBU	R4, (R3);			\
353	ADDV	$1, R3;			\
354	JMP	-5(PC);				\
355	/* call function */			\
356	MOVV	f+8(FP), REGCTXT;			\
357	MOVV	(REGCTXT), R4;			\
358	PCDATA  $PCDATA_StackMapIndex, $0;	\
359	JAL	(R4);				\
360	/* copy return values back */		\
361	MOVV	stackArgsType+0(FP), R5;		\
362	MOVV	stackArgs+16(FP), R1;			\
363	MOVWU	stackArgsSize+24(FP), R2;			\
364	MOVWU	stackRetOffset+28(FP), R4;		\
365	ADDV	$8, R29, R3;				\
366	ADDV	R4, R3; 			\
367	ADDV	R4, R1;				\
368	SUBVU	R4, R2;				\
369	JAL	callRet<>(SB);			\
370	RET
371
372// callRet copies return values back at the end of call*. This is a
373// separate function so it can allocate stack space for the arguments
374// to reflectcallmove. It does not follow the Go ABI; it expects its
375// arguments in registers.
376TEXT callRet<>(SB), NOSPLIT, $40-0
377	MOVV	R5, 8(R29)
378	MOVV	R1, 16(R29)
379	MOVV	R3, 24(R29)
380	MOVV	R2, 32(R29)
381	MOVV	$0, 40(R29)
382	JAL	runtime·reflectcallmove(SB)
383	RET
384
385CALLFNcall16, 16)
386CALLFNcall32, 32)
387CALLFNcall64, 64)
388CALLFNcall128, 128)
389CALLFNcall256, 256)
390CALLFNcall512, 512)
391CALLFNcall1024, 1024)
392CALLFNcall2048, 2048)
393CALLFNcall4096, 4096)
394CALLFNcall8192, 8192)
395CALLFNcall16384, 16384)
396CALLFNcall32768, 32768)
397CALLFNcall65536, 65536)
398CALLFNcall131072, 131072)
399CALLFNcall262144, 262144)
400CALLFNcall524288, 524288)
401CALLFNcall1048576, 1048576)
402CALLFNcall2097152, 2097152)
403CALLFNcall4194304, 4194304)
404CALLFNcall8388608, 8388608)
405CALLFNcall16777216, 16777216)
406CALLFNcall33554432, 33554432)
407CALLFNcall67108864, 67108864)
408CALLFNcall134217728, 134217728)
409CALLFNcall268435456, 268435456)
410CALLFNcall536870912, 536870912)
411CALLFNcall1073741824, 1073741824)
412
413TEXT runtime·procyield(SB),NOSPLIT,$0-0
414	RET
415
416// Save state of caller into g->sched,
417// but using fake PC from systemstack_switch.
418// Must only be called from functions with no locals ($0)
419// or else unwinding from systemstack_switch is incorrect.
420// Smashes R1.
421TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0
422	MOVV	$runtime·systemstack_switch(SB), R1
423	ADDV	$8, R1	// get past prologue
424	MOVV	R1, (g_sched+gobuf_pc)(g)
425	MOVV	R29, (g_sched+gobuf_sp)(g)
426	MOVV	R0, (g_sched+gobuf_lr)(g)
427	MOVV	R0, (g_sched+gobuf_ret)(g)
428	// Assert ctxt is zero. See func save.
429	MOVV	(g_sched+gobuf_ctxt)(g), R1
430	BEQ	R1, 2(PC)
431	JAL	runtime·abort(SB)
432	RET
433
434// func asmcgocall_no_g(fn, arg unsafe.Pointer)
435// Call fn(arg) aligned appropriately for the gcc ABI.
436// Called on a system stack, and there may be no g yet (during needm).
437TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16
438	MOVV	fn+0(FP), R25
439	MOVV	arg+8(FP), R4
440	JAL	(R25)
441	RET
442
443// func asmcgocall(fn, arg unsafe.Pointer) int32
444// Call fn(arg) on the scheduler stack,
445// aligned appropriately for the gcc ABI.
446// See cgocall.go for more details.
447TEXT ·asmcgocall(SB),NOSPLIT,$0-20
448	MOVV	fn+0(FP), R25
449	MOVV	arg+8(FP), R4
450
451	MOVV	R29, R3	// save original stack pointer
452	MOVV	g, R2
453
454	// Figure out if we need to switch to m->g0 stack.
455	// We get called to create new OS threads too, and those
456	// come in on the m->g0 stack already. Or we might already
457	// be on the m->gsignal stack.
458	MOVV	g_m(g), R5
459	MOVV	m_gsignal(R5), R6
460	BEQ	R6, g, g0
461	MOVV	m_g0(R5), R6
462	BEQ	R6, g, g0
463
464	JAL	gosave_systemstack_switch<>(SB)
465	MOVV	R6, g
466	JAL	runtime·save_g(SB)
467	MOVV	(g_sched+gobuf_sp)(g), R29
468
469	// Now on a scheduling stack (a pthread-created stack).
470g0:
471	// Save room for two of our pointers.
472	ADDV	$-16, R29
473	MOVV	R2, 0(R29)	// save old g on stack
474	MOVV	(g_stack+stack_hi)(R2), R2
475	SUBVU	R3, R2
476	MOVV	R2, 8(R29)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
477	JAL	(R25)
478
479	// Restore g, stack pointer. R2 is return value.
480	MOVV	0(R29), g
481	JAL	runtime·save_g(SB)
482	MOVV	(g_stack+stack_hi)(g), R5
483	MOVV	8(R29), R6
484	SUBVU	R6, R5
485	MOVV	R5, R29
486
487	MOVW	R2, ret+16(FP)
488	RET
489
490// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
491// See cgocall.go for more details.
492TEXT ·cgocallback(SB),NOSPLIT,$24-24
493	NO_LOCAL_POINTERS
494
495	// Skip cgocallbackg, just dropm when fn is nil, and frame is the saved g.
496	// It is used to dropm while thread is exiting.
497	MOVV	fn+0(FP), R5
498	BNE	R5, loadg
499	// Restore the g from frame.
500	MOVV	frame+8(FP), g
501	JMP	dropm
502
503loadg:
504	// Load m and g from thread-local storage.
505	MOVB	runtime·iscgo(SB), R1
506	BEQ	R1, nocgo
507	JAL	runtime·load_g(SB)
508nocgo:
509
510	// If g is nil, Go did not create the current thread,
511	// or if this thread never called into Go on pthread platforms.
512	// Call needm to obtain one for temporary use.
513	// In this case, we're running on the thread stack, so there's
514	// lots of space, but the linker doesn't know. Hide the call from
515	// the linker analysis by using an indirect call.
516	BEQ	g, needm
517
518	MOVV	g_m(g), R3
519	MOVV	R3, savedm-8(SP)
520	JMP	havem
521
522needm:
523	MOVV	g, savedm-8(SP) // g is zero, so is m.
524	MOVV	$runtime·needAndBindM(SB), R4
525	JAL	(R4)
526
527	// Set m->sched.sp = SP, so that if a panic happens
528	// during the function we are about to execute, it will
529	// have a valid SP to run on the g0 stack.
530	// The next few lines (after the havem label)
531	// will save this SP onto the stack and then write
532	// the same SP back to m->sched.sp. That seems redundant,
533	// but if an unrecovered panic happens, unwindm will
534	// restore the g->sched.sp from the stack location
535	// and then systemstack will try to use it. If we don't set it here,
536	// that restored SP will be uninitialized (typically 0) and
537	// will not be usable.
538	MOVV	g_m(g), R3
539	MOVV	m_g0(R3), R1
540	MOVV	R29, (g_sched+gobuf_sp)(R1)
541
542havem:
543	// Now there's a valid m, and we're running on its m->g0.
544	// Save current m->g0->sched.sp on stack and then set it to SP.
545	// Save current sp in m->g0->sched.sp in preparation for
546	// switch back to m->curg stack.
547	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R29) aka savedsp-16(SP).
548	MOVV	m_g0(R3), R1
549	MOVV	(g_sched+gobuf_sp)(R1), R2
550	MOVV	R2, savedsp-24(SP)	// must match frame size
551	MOVV	R29, (g_sched+gobuf_sp)(R1)
552
553	// Switch to m->curg stack and call runtime.cgocallbackg.
554	// Because we are taking over the execution of m->curg
555	// but *not* resuming what had been running, we need to
556	// save that information (m->curg->sched) so we can restore it.
557	// We can restore m->curg->sched.sp easily, because calling
558	// runtime.cgocallbackg leaves SP unchanged upon return.
559	// To save m->curg->sched.pc, we push it onto the curg stack and
560	// open a frame the same size as cgocallback's g0 frame.
561	// Once we switch to the curg stack, the pushed PC will appear
562	// to be the return PC of cgocallback, so that the traceback
563	// will seamlessly trace back into the earlier calls.
564	MOVV	m_curg(R3), g
565	JAL	runtime·save_g(SB)
566	MOVV	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
567	MOVV	(g_sched+gobuf_pc)(g), R4
568	MOVV	R4, -(24+8)(R2)	// "saved LR"; must match frame size
569	// Gather our arguments into registers.
570	MOVV	fn+0(FP), R5
571	MOVV	frame+8(FP), R6
572	MOVV	ctxt+16(FP), R7
573	MOVV	$-(24+8)(R2), R29	// switch stack; must match frame size
574	MOVV	R5, 8(R29)
575	MOVV	R6, 16(R29)
576	MOVV	R7, 24(R29)
577	JAL	runtime·cgocallbackg(SB)
578
579	// Restore g->sched (== m->curg->sched) from saved values.
580	MOVV	0(R29), R4
581	MOVV	R4, (g_sched+gobuf_pc)(g)
582	MOVV	$(24+8)(R29), R2	// must match frame size
583	MOVV	R2, (g_sched+gobuf_sp)(g)
584
585	// Switch back to m->g0's stack and restore m->g0->sched.sp.
586	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
587	// so we do not have to restore it.)
588	MOVV	g_m(g), R3
589	MOVV	m_g0(R3), g
590	JAL	runtime·save_g(SB)
591	MOVV	(g_sched+gobuf_sp)(g), R29
592	MOVV	savedsp-24(SP), R2	// must match frame size
593	MOVV	R2, (g_sched+gobuf_sp)(g)
594
595	// If the m on entry was nil, we called needm above to borrow an m,
596	// 1. for the duration of the call on non-pthread platforms,
597	// 2. or the duration of the C thread alive on pthread platforms.
598	// If the m on entry wasn't nil,
599	// 1. the thread might be a Go thread,
600	// 2. or it wasn't the first call from a C thread on pthread platforms,
601	//    since then we skip dropm to reuse the m in the first call.
602	MOVV	savedm-8(SP), R3
603	BNE	R3, droppedm
604
605	// Skip dropm to reuse it in the next call, when a pthread key has been created.
606	MOVV	_cgo_pthread_key_created(SB), R3
607	// It means cgo is disabled when _cgo_pthread_key_created is a nil pointer, need dropm.
608	BEQ	R3, dropm
609	MOVV	(R3), R3
610	BNE	R3, droppedm
611
612dropm:
613	MOVV	$runtime·dropm(SB), R4
614	JAL	(R4)
615droppedm:
616
617	// Done!
618	RET
619
620// void setg(G*); set g. for use by needm.
621TEXT runtime·setg(SB), NOSPLIT, $0-8
622	MOVV	gg+0(FP), g
623	// This only happens if iscgo, so jump straight to save_g
624	JAL	runtime·save_g(SB)
625	RET
626
627// void setg_gcc(G*); set g called from gcc with g in R1
628TEXT setg_gcc<>(SB),NOSPLIT,$0-0
629	MOVV	R1, g
630	JAL	runtime·save_g(SB)
631	RET
632
633TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
634	MOVW	(R0), R0
635	UNDEF
636
637// AES hashing not implemented for mips64
638TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
639	JMP	runtime·memhashFallback(SB)
640TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
641	JMP	runtime·strhashFallback(SB)
642TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
643	JMP	runtime·memhash32Fallback(SB)
644TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
645	JMP	runtime·memhash64Fallback(SB)
646
647TEXT runtime·return0(SB), NOSPLIT, $0
648	MOVW	$0, R1
649	RET
650
651// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
652// Must obey the gcc calling convention.
653TEXT _cgo_topofstack(SB),NOSPLIT,$16
654	// g (R30) and REGTMP (R23)  might be clobbered by load_g. They
655	// are callee-save in the gcc calling convention, so save them.
656	MOVV	R23, savedR23-16(SP)
657	MOVV	g, savedG-8(SP)
658
659	JAL	runtime·load_g(SB)
660	MOVV	g_m(g), R1
661	MOVV	m_curg(R1), R1
662	MOVV	(g_stack+stack_hi)(R1), R2 // return value in R2
663
664	MOVV	savedG-8(SP), g
665	MOVV	savedR23-16(SP), R23
666	RET
667
668// The top-most function running on a goroutine
669// returns to goexit+PCQuantum.
670TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0
671	NOR	R0, R0	// NOP
672	JAL	runtime·goexit1(SB)	// does not return
673	// traceback from goexit1 must hit code range of goexit
674	NOR	R0, R0	// NOP
675
676TEXT ·checkASM(SB),NOSPLIT,$0-1
677	MOVW	$1, R1
678	MOVB	R1, ret+0(FP)
679	RET
680
681// gcWriteBarrier informs the GC about heap pointer writes.
682//
683// gcWriteBarrier does NOT follow the Go ABI. It accepts the
684// number of bytes of buffer needed in R25, and returns a pointer
685// to the buffer space in R25.
686// It clobbers R23 (the linker temp register).
687// The act of CALLing gcWriteBarrier will clobber R31 (LR).
688// It does not clobber any other general-purpose registers,
689// but may clobber others (e.g., floating point registers).
690TEXT gcWriteBarrier<>(SB),NOSPLIT,$192
691	// Save the registers clobbered by the fast path.
692	MOVV	R1, 184(R29)
693	MOVV	R2, 192(R29)
694retry:
695	MOVV	g_m(g), R1
696	MOVV	m_p(R1), R1
697	MOVV	(p_wbBuf+wbBuf_next)(R1), R2
698	MOVV	(p_wbBuf+wbBuf_end)(R1), R23 // R23 is linker temp register
699	// Increment wbBuf.next position.
700	ADDV	R25, R2
701	// Is the buffer full?
702	SGTU	R2, R23, R23
703	BNE	R23, flush
704	// Commit to the larger buffer.
705	MOVV	R2, (p_wbBuf+wbBuf_next)(R1)
706	// Make return value (the original next position)
707	SUBV	R25, R2, R25
708	// Restore registers.
709	MOVV	184(R29), R1
710	MOVV	192(R29), R2
711	RET
712
713flush:
714	// Save all general purpose registers since these could be
715	// clobbered by wbBufFlush and were not saved by the caller.
716	MOVV	R20, 8(R29)
717	MOVV	R21, 16(R29)
718	// R1 already saved
719	// R2 already saved
720	MOVV	R3, 24(R29)
721	MOVV	R4, 32(R29)
722	MOVV	R5, 40(R29)
723	MOVV	R6, 48(R29)
724	MOVV	R7, 56(R29)
725	MOVV	R8, 64(R29)
726	MOVV	R9, 72(R29)
727	MOVV	R10, 80(R29)
728	MOVV	R11, 88(R29)
729	MOVV	R12, 96(R29)
730	MOVV	R13, 104(R29)
731	MOVV	R14, 112(R29)
732	MOVV	R15, 120(R29)
733	MOVV	R16, 128(R29)
734	MOVV	R17, 136(R29)
735	MOVV	R18, 144(R29)
736	MOVV	R19, 152(R29)
737	// R20 already saved
738	// R21 already saved.
739	MOVV	R22, 160(R29)
740	// R23 is tmp register.
741	MOVV	R24, 168(R29)
742	MOVV	R25, 176(R29)
743	// R26 is reserved by kernel.
744	// R27 is reserved by kernel.
745	// R28 is REGSB (not modified by Go code).
746	// R29 is SP.
747	// R30 is g.
748	// R31 is LR, which was saved by the prologue.
749
750	CALL	runtime·wbBufFlush(SB)
751
752	MOVV	8(R29), R20
753	MOVV	16(R29), R21
754	MOVV	24(R29), R3
755	MOVV	32(R29), R4
756	MOVV	40(R29), R5
757	MOVV	48(R29), R6
758	MOVV	56(R29), R7
759	MOVV	64(R29), R8
760	MOVV	72(R29), R9
761	MOVV	80(R29), R10
762	MOVV	88(R29), R11
763	MOVV	96(R29), R12
764	MOVV	104(R29), R13
765	MOVV	112(R29), R14
766	MOVV	120(R29), R15
767	MOVV	128(R29), R16
768	MOVV	136(R29), R17
769	MOVV	144(R29), R18
770	MOVV	152(R29), R19
771	MOVV	160(R29), R22
772	MOVV	168(R29), R24
773	MOVV	176(R29), R25
774	JMP	retry
775
776TEXT runtime·gcWriteBarrier1<ABIInternal>(SB),NOSPLIT,$0
777	MOVV	$8, R25
778	JMP	gcWriteBarrier<>(SB)
779TEXT runtime·gcWriteBarrier2<ABIInternal>(SB),NOSPLIT,$0
780	MOVV	$16, R25
781	JMP	gcWriteBarrier<>(SB)
782TEXT runtime·gcWriteBarrier3<ABIInternal>(SB),NOSPLIT,$0
783	MOVV	$24, R25
784	JMP	gcWriteBarrier<>(SB)
785TEXT runtime·gcWriteBarrier4<ABIInternal>(SB),NOSPLIT,$0
786	MOVV	$32, R25
787	JMP	gcWriteBarrier<>(SB)
788TEXT runtime·gcWriteBarrier5<ABIInternal>(SB),NOSPLIT,$0
789	MOVV	$40, R25
790	JMP	gcWriteBarrier<>(SB)
791TEXT runtime·gcWriteBarrier6<ABIInternal>(SB),NOSPLIT,$0
792	MOVV	$48, R25
793	JMP	gcWriteBarrier<>(SB)
794TEXT runtime·gcWriteBarrier7<ABIInternal>(SB),NOSPLIT,$0
795	MOVV	$56, R25
796	JMP	gcWriteBarrier<>(SB)
797TEXT runtime·gcWriteBarrier8<ABIInternal>(SB),NOSPLIT,$0
798	MOVV	$64, R25
799	JMP	gcWriteBarrier<>(SB)
800
801// Note: these functions use a special calling convention to save generated code space.
802// Arguments are passed in registers, but the space for those arguments are allocated
803// in the caller's stack frame. These stubs write the args into that stack space and
804// then tail call to the corresponding runtime handler.
805// The tail call makes these stubs disappear in backtraces.
806TEXT runtime·panicIndex(SB),NOSPLIT,$0-16
807	MOVV	R1, x+0(FP)
808	MOVV	R2, y+8(FP)
809	JMP	runtime·goPanicIndex(SB)
810TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16
811	MOVV	R1, x+0(FP)
812	MOVV	R2, y+8(FP)
813	JMP	runtime·goPanicIndexU(SB)
814TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16
815	MOVV	R2, x+0(FP)
816	MOVV	R3, y+8(FP)
817	JMP	runtime·goPanicSliceAlen(SB)
818TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16
819	MOVV	R2, x+0(FP)
820	MOVV	R3, y+8(FP)
821	JMP	runtime·goPanicSliceAlenU(SB)
822TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16
823	MOVV	R2, x+0(FP)
824	MOVV	R3, y+8(FP)
825	JMP	runtime·goPanicSliceAcap(SB)
826TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16
827	MOVV	R2, x+0(FP)
828	MOVV	R3, y+8(FP)
829	JMP	runtime·goPanicSliceAcapU(SB)
830TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16
831	MOVV	R1, x+0(FP)
832	MOVV	R2, y+8(FP)
833	JMP	runtime·goPanicSliceB(SB)
834TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16
835	MOVV	R1, x+0(FP)
836	MOVV	R2, y+8(FP)
837	JMP	runtime·goPanicSliceBU(SB)
838TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16
839	MOVV	R3, x+0(FP)
840	MOVV	R4, y+8(FP)
841	JMP	runtime·goPanicSlice3Alen(SB)
842TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16
843	MOVV	R3, x+0(FP)
844	MOVV	R4, y+8(FP)
845	JMP	runtime·goPanicSlice3AlenU(SB)
846TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16
847	MOVV	R3, x+0(FP)
848	MOVV	R4, y+8(FP)
849	JMP	runtime·goPanicSlice3Acap(SB)
850TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16
851	MOVV	R3, x+0(FP)
852	MOVV	R4, y+8(FP)
853	JMP	runtime·goPanicSlice3AcapU(SB)
854TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16
855	MOVV	R2, x+0(FP)
856	MOVV	R3, y+8(FP)
857	JMP	runtime·goPanicSlice3B(SB)
858TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16
859	MOVV	R2, x+0(FP)
860	MOVV	R3, y+8(FP)
861	JMP	runtime·goPanicSlice3BU(SB)
862TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16
863	MOVV	R1, x+0(FP)
864	MOVV	R2, y+8(FP)
865	JMP	runtime·goPanicSlice3C(SB)
866TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16
867	MOVV	R1, x+0(FP)
868	MOVV	R2, y+8(FP)
869	JMP	runtime·goPanicSlice3CU(SB)
870TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16
871	MOVV	R3, x+0(FP)
872	MOVV	R4, y+8(FP)
873	JMP	runtime·goPanicSliceConvert(SB)
874