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
14TEXT runtime·rt0_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	$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	$-24, R29
66	MOVV	R1, 16(R29)
67	MOVV	R0, 8(R29)
68	MOVV	R0, 0(R29)
69	JAL	runtime·newproc(SB)
70	ADDV	$24, R29
71
72	// start this M
73	JAL	runtime·mstart(SB)
74
75	MOVV	R0, 1(R0)
76	RET
77
78DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
79GLOBL	runtime·mainPC(SB),RODATA,$8
80
81TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
82	MOVV	R0, 2(R0) // TODO: TD
83	RET
84
85TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
86	RET
87
88/*
89 *  go-routine
90 */
91
92// void gosave(Gobuf*)
93// save state in Gobuf; setjmp
94TEXT runtime·gosave(SB), NOSPLIT|NOFRAME, $0-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	runtime·badctxt(SB)
105	RET
106
107// void gogo(Gobuf*)
108// restore state from Gobuf; longjmp
109TEXT runtime·gogo(SB), NOSPLIT, $16-8
110	MOVV	buf+0(FP), R3
111	MOVV	gobuf_g(R3), g	// make sure g is not nil
112	JAL	runtime·save_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.
130TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-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	runtime·save_g(SB)
142	BNE	g, R1, 2(PC)
143	JMP	runtime·badmcall(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	runtime·badmcall2(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()).
158TEXT runtime·systemstack_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())
164TEXT runtime·systemstack(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	$runtime·badsystemstack(SB), R4
181	JAL	(R4)
182	JAL	runtime·abort(SB)
183
184switch:
185	// save our state in g->sched. Pretend to
186	// be systemstack_switch if the G stack is scanned.
187	MOVV	$runtime·systemstack_switch(SB), R4
188	ADDV	$8, R4	// get past prologue
189	MOVV	R4, (g_sched+gobuf_pc)(g)
190	MOVV	R29, (g_sched+gobuf_sp)(g)
191	MOVV	R0, (g_sched+gobuf_lr)(g)
192	MOVV	g, (g_sched+gobuf_g)(g)
193
194	// switch to g0
195	MOVV	R3, g
196	JAL	runtime·save_g(SB)
197	MOVV	(g_sched+gobuf_sp)(g), R1
198	// make it look like mstart called systemstack on g0, to stop traceback
199	ADDV	$-8, R1
200	MOVV	$runtime·mstart(SB), R2
201	MOVV	R2, 0(R1)
202	MOVV	R1, R29
203
204	// call target function
205	MOVV	0(REGCTXT), R4	// code pointer
206	JAL	(R4)
207
208	// switch back to g
209	MOVV	g_m(g), R1
210	MOVV	m_curg(R1), g
211	JAL	runtime·save_g(SB)
212	MOVV	(g_sched+gobuf_sp)(g), R29
213	MOVV	R0, (g_sched+gobuf_sp)(g)
214	RET
215
216noswitch:
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	MOVV	0(REGCTXT), R4	// code pointer
221	MOVV	0(R29), R31	// restore LR
222	ADDV	$8, 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.
237TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
238	// Cannot grow scheduler stack (m->g0).
239	MOVV	g_m(g), R7
240	MOVV	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	MOVV	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	MOVV	R29, (g_sched+gobuf_sp)(g)
254	MOVV	R31, (g_sched+gobuf_pc)(g)
255	MOVV	R3, (g_sched+gobuf_lr)(g)
256	MOVV	REGCTXT, (g_sched+gobuf_ctxt)(g)
257
258	// Called from f.
259	// Set m->morebuf to f's caller.
260	MOVV	R3, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
261	MOVV	R29, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
262	MOVV	g, (m_morebuf+gobuf_g)(R7)
263
264	// Call newstack on m->g0's stack.
265	MOVV	m_g0(R7), g
266	JAL	runtime·save_g(SB)
267	MOVV	(g_sched+gobuf_sp)(g), R29
268	// Create a stack frame on g0 to call newstack.
269	MOVV	R0, -8(R29)	// Zero saved LR in frame
270	ADDV	$-8, 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
277TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0
278	MOVV	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// Caution: ugly multiline assembly macros in your future!
286
287#define DISPATCH(NAME,MAXSIZE)		\
288	MOVV	$MAXSIZE, R23;		\
289	SGTU	R1, R23, R23;		\
290	BNE	R23, 3(PC);			\
291	MOVV	$NAME(SB), R4;	\
292	JMP	(R4)
293// Note: can't just "BR NAME(SB)" - bad inlining results.
294
295TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-32
296	MOVWU argsize+24(FP), R1
297	DISPATCH(runtime·call32, 32)
298	DISPATCH(runtime·call64, 64)
299	DISPATCH(runtime·call128, 128)
300	DISPATCH(runtime·call256, 256)
301	DISPATCH(runtime·call512, 512)
302	DISPATCH(runtime·call1024, 1024)
303	DISPATCH(runtime·call2048, 2048)
304	DISPATCH(runtime·call4096, 4096)
305	DISPATCH(runtime·call8192, 8192)
306	DISPATCH(runtime·call16384, 16384)
307	DISPATCH(runtime·call32768, 32768)
308	DISPATCH(runtime·call65536, 65536)
309	DISPATCH(runtime·call131072, 131072)
310	DISPATCH(runtime·call262144, 262144)
311	DISPATCH(runtime·call524288, 524288)
312	DISPATCH(runtime·call1048576, 1048576)
313	DISPATCH(runtime·call2097152, 2097152)
314	DISPATCH(runtime·call4194304, 4194304)
315	DISPATCH(runtime·call8388608, 8388608)
316	DISPATCH(runtime·call16777216, 16777216)
317	DISPATCH(runtime·call33554432, 33554432)
318	DISPATCH(runtime·call67108864, 67108864)
319	DISPATCH(runtime·call134217728, 134217728)
320	DISPATCH(runtime·call268435456, 268435456)
321	DISPATCH(runtime·call536870912, 536870912)
322	DISPATCH(runtime·call1073741824, 1073741824)
323	MOVV	$runtime·badreflectcall(SB), R4
324	JMP	(R4)
325
326#define CALLFN(NAME,MAXSIZE)			\
327TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
328	NO_LOCAL_POINTERS;			\
329	/* copy arguments to stack */		\
330	MOVV	arg+16(FP), R1;			\
331	MOVWU	argsize+24(FP), R2;			\
332	MOVV	R29, R3;				\
333	ADDV	$8, R3;			\
334	ADDV	R3, R2;				\
335	BEQ	R3, R2, 6(PC);				\
336	MOVBU	(R1), R4;			\
337	ADDV	$1, R1;			\
338	MOVBU	R4, (R3);			\
339	ADDV	$1, R3;			\
340	JMP	-5(PC);				\
341	/* call function */			\
342	MOVV	f+8(FP), REGCTXT;			\
343	MOVV	(REGCTXT), R4;			\
344	PCDATA  $PCDATA_StackMapIndex, $0;	\
345	JAL	(R4);				\
346	/* copy return values back */		\
347	MOVV	argtype+0(FP), R5;		\
348	MOVV	arg+16(FP), R1;			\
349	MOVWU	n+24(FP), R2;			\
350	MOVWU	retoffset+28(FP), R4;		\
351	ADDV	$8, R29, R3;				\
352	ADDV	R4, R3; 			\
353	ADDV	R4, R1;				\
354	SUBVU	R4, R2;				\
355	JAL	callRet<>(SB);			\
356	RET
357
358// callRet copies return values back at the end of call*. This is a
359// separate function so it can allocate stack space for the arguments
360// to reflectcallmove. It does not follow the Go ABI; it expects its
361// arguments in registers.
362TEXT callRet<>(SB), NOSPLIT, $32-0
363	MOVV	R5, 8(R29)
364	MOVV	R1, 16(R29)
365	MOVV	R3, 24(R29)
366	MOVV	R2, 32(R29)
367	JAL	runtime·reflectcallmove(SB)
368	RET
369
370CALLFNcall16, 16)
371CALLFNcall32, 32)
372CALLFNcall64, 64)
373CALLFNcall128, 128)
374CALLFNcall256, 256)
375CALLFNcall512, 512)
376CALLFNcall1024, 1024)
377CALLFNcall2048, 2048)
378CALLFNcall4096, 4096)
379CALLFNcall8192, 8192)
380CALLFNcall16384, 16384)
381CALLFNcall32768, 32768)
382CALLFNcall65536, 65536)
383CALLFNcall131072, 131072)
384CALLFNcall262144, 262144)
385CALLFNcall524288, 524288)
386CALLFNcall1048576, 1048576)
387CALLFNcall2097152, 2097152)
388CALLFNcall4194304, 4194304)
389CALLFNcall8388608, 8388608)
390CALLFNcall16777216, 16777216)
391CALLFNcall33554432, 33554432)
392CALLFNcall67108864, 67108864)
393CALLFNcall134217728, 134217728)
394CALLFNcall268435456, 268435456)
395CALLFNcall536870912, 536870912)
396CALLFNcall1073741824, 1073741824)
397
398TEXT runtime·procyield(SB),NOSPLIT,$0-0
399	RET
400
401// void jmpdefer(fv, sp);
402// called from deferreturn.
403// 1. grab stored LR for caller
404// 2. sub 8 bytes to get back to JAL deferreturn
405// 3. JMP to fn
406TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
407	MOVV	0(R29), R31
408	ADDV	$-8, R31
409
410	MOVV	fv+0(FP), REGCTXT
411	MOVV	argp+8(FP), R29
412	ADDV	$-8, R29
413	NOR	R0, R0	// prevent scheduling
414	MOVV	0(REGCTXT), R4
415	JMP	(R4)
416
417// Save state of caller into g->sched. Smashes R1.
418TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
419	MOVV	R31, (g_sched+gobuf_pc)(g)
420	MOVV	R29, (g_sched+gobuf_sp)(g)
421	MOVV	R0, (g_sched+gobuf_lr)(g)
422	MOVV	R0, (g_sched+gobuf_ret)(g)
423	// Assert ctxt is zero. See func save.
424	MOVV	(g_sched+gobuf_ctxt)(g), R1
425	BEQ	R1, 2(PC)
426	JAL	runtime·badctxt(SB)
427	RET
428
429// func asmcgocall(fn, arg unsafe.Pointer) int32
430// Call fn(arg) on the scheduler stack,
431// aligned appropriately for the gcc ABI.
432// See cgocall.go for more details.
433TEXT ·asmcgocall(SB),NOSPLIT,$0-20
434	MOVV	fn+0(FP), R25
435	MOVV	arg+8(FP), R4
436
437	MOVV	R29, R3	// save original stack pointer
438	MOVV	g, R2
439
440	// Figure out if we need to switch to m->g0 stack.
441	// We get called to create new OS threads too, and those
442	// come in on the m->g0 stack already.
443	MOVV	g_m(g), R5
444	MOVV	m_g0(R5), R6
445	BEQ	R6, g, g0
446
447	JAL	gosave<>(SB)
448	MOVV	R6, g
449	JAL	runtime·save_g(SB)
450	MOVV	(g_sched+gobuf_sp)(g), R29
451
452	// Now on a scheduling stack (a pthread-created stack).
453g0:
454	// Save room for two of our pointers.
455	ADDV	$-16, R29
456	MOVV	R2, 0(R29)	// save old g on stack
457	MOVV	(g_stack+stack_hi)(R2), R2
458	SUBVU	R3, R2
459	MOVV	R2, 8(R29)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
460	JAL	(R25)
461
462	// Restore g, stack pointer. R2 is return value.
463	MOVV	0(R29), g
464	JAL	runtime·save_g(SB)
465	MOVV	(g_stack+stack_hi)(g), R5
466	MOVV	8(R29), R6
467	SUBVU	R6, R5
468	MOVV	R5, R29
469
470	MOVW	R2, ret+16(FP)
471	RET
472
473// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
474// Turn the fn into a Go func (by taking its address) and call
475// cgocallback_gofunc.
476TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
477	MOVV	$fn+0(FP), R1
478	MOVV	R1, 8(R29)
479	MOVV	frame+8(FP), R1
480	MOVV	R1, 16(R29)
481	MOVV	framesize+16(FP), R1
482	MOVV	R1, 24(R29)
483	MOVV	ctxt+24(FP), R1
484	MOVV	R1, 32(R29)
485	MOVV	$runtime·cgocallback_gofunc(SB), R1
486	JAL	(R1)
487	RET
488
489// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
490// See cgocall.go for more details.
491TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
492	NO_LOCAL_POINTERS
493
494	// Load m and g from thread-local storage.
495	MOVB	runtime·iscgo(SB), R1
496	BEQ	R1, nocgo
497	JAL	runtime·load_g(SB)
498nocgo:
499
500	// If g is nil, Go did not create the current thread.
501	// Call needm to obtain one for temporary use.
502	// In this case, we're running on the thread stack, so there's
503	// lots of space, but the linker doesn't know. Hide the call from
504	// the linker analysis by using an indirect call.
505	BEQ	g, needm
506
507	MOVV	g_m(g), R3
508	MOVV	R3, savedm-8(SP)
509	JMP	havem
510
511needm:
512	MOVV	g, savedm-8(SP) // g is zero, so is m.
513	MOVV	$runtime·needm(SB), R4
514	JAL	(R4)
515
516	// Set m->sched.sp = SP, so that if a panic happens
517	// during the function we are about to execute, it will
518	// have a valid SP to run on the g0 stack.
519	// The next few lines (after the havem label)
520	// will save this SP onto the stack and then write
521	// the same SP back to m->sched.sp. That seems redundant,
522	// but if an unrecovered panic happens, unwindm will
523	// restore the g->sched.sp from the stack location
524	// and then systemstack will try to use it. If we don't set it here,
525	// that restored SP will be uninitialized (typically 0) and
526	// will not be usable.
527	MOVV	g_m(g), R3
528	MOVV	m_g0(R3), R1
529	MOVV	R29, (g_sched+gobuf_sp)(R1)
530
531havem:
532	// Now there's a valid m, and we're running on its m->g0.
533	// Save current m->g0->sched.sp on stack and then set it to SP.
534	// Save current sp in m->g0->sched.sp in preparation for
535	// switch back to m->curg stack.
536	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R29) aka savedsp-16(SP).
537	MOVV	m_g0(R3), R1
538	MOVV	(g_sched+gobuf_sp)(R1), R2
539	MOVV	R2, savedsp-16(SP)
540	MOVV	R29, (g_sched+gobuf_sp)(R1)
541
542	// Switch to m->curg stack and call runtime.cgocallbackg.
543	// Because we are taking over the execution of m->curg
544	// but *not* resuming what had been running, we need to
545	// save that information (m->curg->sched) so we can restore it.
546	// We can restore m->curg->sched.sp easily, because calling
547	// runtime.cgocallbackg leaves SP unchanged upon return.
548	// To save m->curg->sched.pc, we push it onto the stack.
549	// This has the added benefit that it looks to the traceback
550	// routine like cgocallbackg is going to return to that
551	// PC (because the frame we allocate below has the same
552	// size as cgocallback_gofunc's frame declared above)
553	// so that the traceback will seamlessly trace back into
554	// the earlier calls.
555	//
556	// In the new goroutine, -8(SP) is unused (where SP refers to
557	// m->curg's SP while we're setting it up, before we've adjusted it).
558	MOVV	m_curg(R3), g
559	JAL	runtime·save_g(SB)
560	MOVV	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
561	MOVV	(g_sched+gobuf_pc)(g), R4
562	MOVV	R4, -24(R2)
563	MOVV    ctxt+24(FP), R1
564	MOVV    R1, -16(R2)
565	MOVV	$-24(R2), R29
566	JAL	runtime·cgocallbackg(SB)
567
568	// Restore g->sched (== m->curg->sched) from saved values.
569	MOVV	0(R29), R4
570	MOVV	R4, (g_sched+gobuf_pc)(g)
571	MOVV	$24(R29), R2
572	MOVV	R2, (g_sched+gobuf_sp)(g)
573
574	// Switch back to m->g0's stack and restore m->g0->sched.sp.
575	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
576	// so we do not have to restore it.)
577	MOVV	g_m(g), R3
578	MOVV	m_g0(R3), g
579	JAL	runtime·save_g(SB)
580	MOVV	(g_sched+gobuf_sp)(g), R29
581	MOVV	savedsp-16(SP), R2
582	MOVV	R2, (g_sched+gobuf_sp)(g)
583
584	// If the m on entry was nil, we called needm above to borrow an m
585	// for the duration of the call. Since the call is over, return it with dropm.
586	MOVV	savedm-8(SP), R3
587	BNE	R3, droppedm
588	MOVV	$runtime·dropm(SB), R4
589	JAL	(R4)
590droppedm:
591
592	// Done!
593	RET
594
595// void setg(G*); set g. for use by needm.
596TEXT runtime·setg(SB), NOSPLIT, $0-8
597	MOVV	gg+0(FP), g
598	// This only happens if iscgo, so jump straight to save_g
599	JAL	runtime·save_g(SB)
600	RET
601
602// void setg_gcc(G*); set g called from gcc with g in R1
603TEXT setg_gcc<>(SB),NOSPLIT,$0-0
604	MOVV	R1, g
605	JAL	runtime·save_g(SB)
606	RET
607
608TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
609	MOVW	(R0), R0
610	UNDEF
611
612// AES hashing not implemented for mips64
613TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
614	JMP	runtime·memhashFallback(SB)
615TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
616	JMP	runtime·strhashFallback(SB)
617TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
618	JMP	runtime·memhash32Fallback(SB)
619TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
620	JMP	runtime·memhash64Fallback(SB)
621
622TEXT runtime·return0(SB), NOSPLIT, $0
623	MOVW	$0, R1
624	RET
625
626// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
627// Must obey the gcc calling convention.
628TEXT _cgo_topofstack(SB),NOSPLIT,$16
629	// g (R30) and REGTMP (R23)  might be clobbered by load_g. They
630	// are callee-save in the gcc calling convention, so save them.
631	MOVV	R23, savedR23-16(SP)
632	MOVV	g, savedG-8(SP)
633
634	JAL	runtime·load_g(SB)
635	MOVV	g_m(g), R1
636	MOVV	m_curg(R1), R1
637	MOVV	(g_stack+stack_hi)(R1), R2 // return value in R2
638
639	MOVV	savedG-8(SP), g
640	MOVV	savedR23-16(SP), R23
641	RET
642
643// The top-most function running on a goroutine
644// returns to goexit+PCQuantum.
645TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0
646	NOR	R0, R0	// NOP
647	JAL	runtime·goexit1(SB)	// does not return
648	// traceback from goexit1 must hit code range of goexit
649	NOR	R0, R0	// NOP
650
651TEXT ·checkASM(SB),NOSPLIT,$0-1
652	MOVW	$1, R1
653	MOVB	R1, ret+0(FP)
654	RET
655
656// gcWriteBarrier performs a heap pointer write and informs the GC.
657//
658// gcWriteBarrier does NOT follow the Go ABI. It takes two arguments:
659// - R20 is the destination of the write
660// - R21 is the value being written at R20.
661// It clobbers R23 (the linker temp register).
662// The act of CALLing gcWriteBarrier will clobber R31 (LR).
663// It does not clobber any other general-purpose registers,
664// but may clobber others (e.g., floating point registers).
665TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$192
666	// Save the registers clobbered by the fast path.
667	MOVV	R1, 184(R29)
668	MOVV	R2, 192(R29)
669	MOVV	g_m(g), R1
670	MOVV	m_p(R1), R1
671	MOVV	(p_wbBuf+wbBuf_next)(R1), R2
672	// Increment wbBuf.next position.
673	ADDV	$16, R2
674	MOVV	R2, (p_wbBuf+wbBuf_next)(R1)
675	MOVV	(p_wbBuf+wbBuf_end)(R1), R1
676	MOVV	R1, R23		// R23 is linker temp register
677	// Record the write.
678	MOVV	R21, -16(R2)	// Record value
679	MOVV	(R20), R1	// TODO: This turns bad writes into bad reads.
680	MOVV	R1, -8(R2)	// Record *slot
681	// Is the buffer full?
682	BEQ	R2, R23, flush
683ret:
684	MOVV	184(R29), R1
685	MOVV	192(R29), R2
686	// Do the write.
687	MOVV	R21, (R20)
688	RET
689
690flush:
691	// Save all general purpose registers since these could be
692	// clobbered by wbBufFlush and were not saved by the caller.
693	MOVV	R20, 8(R29)	// Also first argument to wbBufFlush
694	MOVV	R21, 16(R29)	// Also second argument to wbBufFlush
695	// R1 already saved
696	// R2 already saved
697	MOVV	R3, 24(R29)
698	MOVV	R4, 32(R29)
699	MOVV	R5, 40(R29)
700	MOVV	R6, 48(R29)
701	MOVV	R7, 56(R29)
702	MOVV	R8, 64(R29)
703	MOVV	R9, 72(R29)
704	MOVV	R10, 80(R29)
705	MOVV	R11, 88(R29)
706	MOVV	R12, 96(R29)
707	MOVV	R13, 104(R29)
708	MOVV	R14, 112(R29)
709	MOVV	R15, 120(R29)
710	MOVV	R16, 128(R29)
711	MOVV	R17, 136(R29)
712	MOVV	R18, 144(R29)
713	MOVV	R19, 152(R29)
714	// R20 already saved
715	// R21 already saved.
716	MOVV	R22, 160(R29)
717	// R23 is tmp register.
718	MOVV	R24, 168(R29)
719	MOVV	R25, 176(R29)
720	// R26 is reserved by kernel.
721	// R27 is reserved by kernel.
722	// R28 is REGSB (not modified by Go code).
723	// R29 is SP.
724	// R30 is g.
725	// R31 is LR, which was saved by the prologue.
726
727	// This takes arguments R20 and R21.
728	CALL	runtime·wbBufFlush(SB)
729
730	MOVV	8(R29), R20
731	MOVV	16(R29), R21
732	MOVV	24(R29), R3
733	MOVV	32(R29), R4
734	MOVV	40(R29), R5
735	MOVV	48(R29), R6
736	MOVV	56(R29), R7
737	MOVV	64(R29), R8
738	MOVV	72(R29), R9
739	MOVV	80(R29), R10
740	MOVV	88(R29), R11
741	MOVV	96(R29), R12
742	MOVV	104(R29), R13
743	MOVV	112(R29), R14
744	MOVV	120(R29), R15
745	MOVV	128(R29), R16
746	MOVV	136(R29), R17
747	MOVV	144(R29), R18
748	MOVV	152(R29), R19
749	MOVV	160(R29), R22
750	MOVV	168(R29), R24
751	MOVV	176(R29), R25
752	JMP	ret
753
754// Note: these functions use a special calling convention to save generated code space.
755// Arguments are passed in registers, but the space for those arguments are allocated
756// in the caller's stack frame. These stubs write the args into that stack space and
757// then tail call to the corresponding runtime handler.
758// The tail call makes these stubs disappear in backtraces.
759TEXT runtime·panicIndex(SB),NOSPLIT,$0-16
760	MOVV	R1, x+0(FP)
761	MOVV	R2, y+8(FP)
762	JMP	runtime·goPanicIndex(SB)
763TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16
764	MOVV	R1, x+0(FP)
765	MOVV	R2, y+8(FP)
766	JMP	runtime·goPanicIndexU(SB)
767TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16
768	MOVV	R2, x+0(FP)
769	MOVV	R3, y+8(FP)
770	JMP	runtime·goPanicSliceAlen(SB)
771TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16
772	MOVV	R2, x+0(FP)
773	MOVV	R3, y+8(FP)
774	JMP	runtime·goPanicSliceAlenU(SB)
775TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16
776	MOVV	R2, x+0(FP)
777	MOVV	R3, y+8(FP)
778	JMP	runtime·goPanicSliceAcap(SB)
779TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16
780	MOVV	R2, x+0(FP)
781	MOVV	R3, y+8(FP)
782	JMP	runtime·goPanicSliceAcapU(SB)
783TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16
784	MOVV	R1, x+0(FP)
785	MOVV	R2, y+8(FP)
786	JMP	runtime·goPanicSliceB(SB)
787TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16
788	MOVV	R1, x+0(FP)
789	MOVV	R2, y+8(FP)
790	JMP	runtime·goPanicSliceBU(SB)
791TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16
792	MOVV	R3, x+0(FP)
793	MOVV	R4, y+8(FP)
794	JMP	runtime·goPanicSlice3Alen(SB)
795TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16
796	MOVV	R3, x+0(FP)
797	MOVV	R4, y+8(FP)
798	JMP	runtime·goPanicSlice3AlenU(SB)
799TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16
800	MOVV	R3, x+0(FP)
801	MOVV	R4, y+8(FP)
802	JMP	runtime·goPanicSlice3Acap(SB)
803TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16
804	MOVV	R3, x+0(FP)
805	MOVV	R4, y+8(FP)
806	JMP	runtime·goPanicSlice3AcapU(SB)
807TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16
808	MOVV	R2, x+0(FP)
809	MOVV	R3, y+8(FP)
810	JMP	runtime·goPanicSlice3B(SB)
811TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16
812	MOVV	R2, x+0(FP)
813	MOVV	R3, y+8(FP)
814	JMP	runtime·goPanicSlice3BU(SB)
815TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16
816	MOVV	R1, x+0(FP)
817	MOVV	R2, y+8(FP)
818	JMP	runtime·goPanicSlice3C(SB)
819TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16
820	MOVV	R1, x+0(FP)
821	MOVV	R2, y+8(FP)
822	JMP	runtime·goPanicSlice3CU(SB)
823