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
14TEXT 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
42nocgo:
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
79DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
80GLOBL	runtime·mainPC(SB),RODATA,$4
81
82TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
83	BREAK
84	RET
85
86TEXT 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
95TEXT runtime·gosave(SB),NOSPLIT|NOFRAME,$0-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
110TEXT 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.
131TEXT runtime·mcall(SB),NOSPLIT|NOFRAME,$0-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()).
159TEXT 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())
165TEXT 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	JAL	runtime·abort(SB)
184
185switch:
186	// save our state in g->sched.  Pretend to
187	// be systemstack_switch if the G stack is scanned.
188	MOVW	$runtime·systemstack_switch(SB), R4
189	ADDU	$8, R4	// get past prologue
190	MOVW	R4, (g_sched+gobuf_pc)(g)
191	MOVW	R29, (g_sched+gobuf_sp)(g)
192	MOVW	R0, (g_sched+gobuf_lr)(g)
193	MOVW	g, (g_sched+gobuf_g)(g)
194
195	// switch to g0
196	MOVW	R3, g
197	JAL	runtime·save_g(SB)
198	MOVW	(g_sched+gobuf_sp)(g), R1
199	// make it look like mstart called systemstack on g0, to stop traceback
200	ADDU	$-4, R1
201	MOVW	$runtime·mstart(SB), R2
202	MOVW	R2, 0(R1)
203	MOVW	R1, R29
204
205	// call target function
206	MOVW	0(REGCTXT), R4	// code pointer
207	JAL	(R4)
208
209	// switch back to g
210	MOVW	g_m(g), R1
211	MOVW	m_curg(R1), g
212	JAL	runtime·save_g(SB)
213	MOVW	(g_sched+gobuf_sp)(g), R29
214	MOVW	R0, (g_sched+gobuf_sp)(g)
215	RET
216
217noswitch:
218	// already on m stack, just call directly
219	// Using a tail call here cleans up tracebacks since we won't stop
220	// at an intermediate systemstack.
221	MOVW	0(REGCTXT), R4	// code pointer
222	MOVW	0(R29), R31	// restore LR
223	ADD	$4, R29
224	JMP	(R4)
225
226/*
227 * support for morestack
228 */
229
230// Called during function prolog when more stack is needed.
231// Caller has already loaded:
232// R1: framesize, R2: argsize, R3: LR
233//
234// The traceback routines see morestack on a g0 as being
235// the top of a stack (for example, morestack calling newstack
236// calling the scheduler calling newm calling gc), so we must
237// record an argument size. For that purpose, it has no arguments.
238TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
239	// Cannot grow scheduler stack (m->g0).
240	MOVW	g_m(g), R7
241	MOVW	m_g0(R7), R8
242	BNE	g, R8, 3(PC)
243	JAL	runtime·badmorestackg0(SB)
244	JAL	runtime·abort(SB)
245
246	// Cannot grow signal stack (m->gsignal).
247	MOVW	m_gsignal(R7), R8
248	BNE	g, R8, 3(PC)
249	JAL	runtime·badmorestackgsignal(SB)
250	JAL	runtime·abort(SB)
251
252	// Called from f.
253	// Set g->sched to context in f.
254	MOVW	R29, (g_sched+gobuf_sp)(g)
255	MOVW	R31, (g_sched+gobuf_pc)(g)
256	MOVW	R3, (g_sched+gobuf_lr)(g)
257	MOVW	REGCTXT, (g_sched+gobuf_ctxt)(g)
258
259	// Called from f.
260	// Set m->morebuf to f's caller.
261	MOVW	R3, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
262	MOVW	R29, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
263	MOVW	g, (m_morebuf+gobuf_g)(R7)
264
265	// Call newstack on m->g0's stack.
266	MOVW	m_g0(R7), g
267	JAL	runtime·save_g(SB)
268	MOVW	(g_sched+gobuf_sp)(g), R29
269	// Create a stack frame on g0 to call newstack.
270	MOVW	R0, -4(R29)	// Zero saved LR in frame
271	ADDU	$-4, R29
272	JAL	runtime·newstack(SB)
273
274	// Not reached, but make sure the return PC from the call to newstack
275	// is still in this function, and not the beginning of the next.
276	UNDEF
277
278TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
279	MOVW	R0, REGCTXT
280	JMP	runtime·morestack(SB)
281
282// reflectcall: call a function with the given argument list
283// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
284// we don't have variable-sized frames, so we use a small number
285// of constant-sized-frame functions to encode a few bits of size in the pc.
286
287#define DISPATCH(NAME,MAXSIZE)	\
288	MOVW	$MAXSIZE, R23;	\
289	SGTU	R1, R23, R23;	\
290	BNE	R23, 3(PC);	\
291	MOVW	$NAME(SB), R4;	\
292	JMP	(R4)
293
294TEXT ·reflectcall(SB),NOSPLIT|NOFRAME,$0-20
295	MOVW	argsize+12(FP), R1
296
297	DISPATCH(runtime·call16, 16)
298	DISPATCH(runtime·call32, 32)
299	DISPATCH(runtime·call64, 64)
300	DISPATCH(runtime·call128, 128)
301	DISPATCH(runtime·call256, 256)
302	DISPATCH(runtime·call512, 512)
303	DISPATCH(runtime·call1024, 1024)
304	DISPATCH(runtime·call2048, 2048)
305	DISPATCH(runtime·call4096, 4096)
306	DISPATCH(runtime·call8192, 8192)
307	DISPATCH(runtime·call16384, 16384)
308	DISPATCH(runtime·call32768, 32768)
309	DISPATCH(runtime·call65536, 65536)
310	DISPATCH(runtime·call131072, 131072)
311	DISPATCH(runtime·call262144, 262144)
312	DISPATCH(runtime·call524288, 524288)
313	DISPATCH(runtime·call1048576, 1048576)
314	DISPATCH(runtime·call2097152, 2097152)
315	DISPATCH(runtime·call4194304, 4194304)
316	DISPATCH(runtime·call8388608, 8388608)
317	DISPATCH(runtime·call16777216, 16777216)
318	DISPATCH(runtime·call33554432, 33554432)
319	DISPATCH(runtime·call67108864, 67108864)
320	DISPATCH(runtime·call134217728, 134217728)
321	DISPATCH(runtime·call268435456, 268435456)
322	DISPATCH(runtime·call536870912, 536870912)
323	DISPATCH(runtime·call1073741824, 1073741824)
324	MOVW	$runtime·badreflectcall(SB), R4
325	JMP	(R4)
326
327#define CALLFN(NAME,MAXSIZE)	\
328TEXT NAME(SB),WRAPPER,$MAXSIZE-20;	\
329	NO_LOCAL_POINTERS;	\
330	/* copy arguments to stack */		\
331	MOVW	arg+8(FP), R1;	\
332	MOVW	argsize+12(FP), R2;	\
333	MOVW	R29, R3;	\
334	ADDU	$4, R3;	\
335	ADDU	R3, R2;	\
336	BEQ	R3, R2, 6(PC);	\
337	MOVBU	(R1), R4;	\
338	ADDU	$1, R1;	\
339	MOVBU	R4, (R3);	\
340	ADDU	$1, R3;	\
341	JMP	-5(PC);	\
342	/* call function */			\
343	MOVW	f+4(FP), REGCTXT;	\
344	MOVW	(REGCTXT), R4;	\
345	PCDATA	$PCDATA_StackMapIndex, $0;	\
346	JAL	(R4);	\
347	/* copy return values back */		\
348	MOVW	argtype+0(FP), R5;	\
349	MOVW	arg+8(FP), R1;	\
350	MOVW	n+12(FP), R2;	\
351	MOVW	retoffset+16(FP), R4;	\
352	ADDU	$4, R29, R3;	\
353	ADDU	R4, R3;	\
354	ADDU	R4, R1;	\
355	SUBU	R4, R2;	\
356	JAL	callRet<>(SB);		\
357	RET
358
359// callRet copies return values back at the end of call*. This is a
360// separate function so it can allocate stack space for the arguments
361// to reflectcallmove. It does not follow the Go ABI; it expects its
362// arguments in registers.
363TEXT callRet<>(SB), NOSPLIT, $16-0
364	MOVW	R5, 4(R29)
365	MOVW	R1, 8(R29)
366	MOVW	R3, 12(R29)
367	MOVW	R2, 16(R29)
368	JAL	runtime·reflectcallmove(SB)
369	RET
370
371CALLFNcall16, 16)
372CALLFNcall32, 32)
373CALLFNcall64, 64)
374CALLFNcall128, 128)
375CALLFNcall256, 256)
376CALLFNcall512, 512)
377CALLFNcall1024, 1024)
378CALLFNcall2048, 2048)
379CALLFNcall4096, 4096)
380CALLFNcall8192, 8192)
381CALLFNcall16384, 16384)
382CALLFNcall32768, 32768)
383CALLFNcall65536, 65536)
384CALLFNcall131072, 131072)
385CALLFNcall262144, 262144)
386CALLFNcall524288, 524288)
387CALLFNcall1048576, 1048576)
388CALLFNcall2097152, 2097152)
389CALLFNcall4194304, 4194304)
390CALLFNcall8388608, 8388608)
391CALLFNcall16777216, 16777216)
392CALLFNcall33554432, 33554432)
393CALLFNcall67108864, 67108864)
394CALLFNcall134217728, 134217728)
395CALLFNcall268435456, 268435456)
396CALLFNcall536870912, 536870912)
397CALLFNcall1073741824, 1073741824)
398
399TEXT runtime·procyield(SB),NOSPLIT,$0-4
400	RET
401
402// void jmpdefer(fv, sp);
403// called from deferreturn.
404// 1. grab stored LR for caller
405// 2. sub 8 bytes to get back to JAL deferreturn
406// 3. JMP to fn
407TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
408	MOVW	0(R29), R31
409	ADDU	$-8, R31
410
411	MOVW	fv+0(FP), REGCTXT
412	MOVW	argp+4(FP), R29
413	ADDU	$-4, R29
414	NOR	R0, R0	// prevent scheduling
415	MOVW	0(REGCTXT), R4
416	JMP	(R4)
417
418// Save state of caller into g->sched. Smashes R1.
419TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
420	MOVW	R31, (g_sched+gobuf_pc)(g)
421	MOVW	R29, (g_sched+gobuf_sp)(g)
422	MOVW	R0, (g_sched+gobuf_lr)(g)
423	MOVW	R0, (g_sched+gobuf_ret)(g)
424	// Assert ctxt is zero. See func save.
425	MOVW	(g_sched+gobuf_ctxt)(g), R1
426	BEQ	R1, 2(PC)
427	JAL	runtime·badctxt(SB)
428	RET
429
430// func asmcgocall(fn, arg unsafe.Pointer) int32
431// Call fn(arg) on the scheduler stack,
432// aligned appropriately for the gcc ABI.
433// See cgocall.go for more details.
434TEXT ·asmcgocall(SB),NOSPLIT,$0-12
435	MOVW	fn+0(FP), R25
436	MOVW	arg+4(FP), R4
437
438	MOVW	R29, R3	// save original stack pointer
439	MOVW	g, R2
440
441	// Figure out if we need to switch to m->g0 stack.
442	// We get called to create new OS threads too, and those
443	// come in on the m->g0 stack already.
444	MOVW	g_m(g), R5
445	MOVW	m_g0(R5), R6
446	BEQ	R6, g, g0
447
448	JAL	gosave<>(SB)
449	MOVW	R6, g
450	JAL	runtime·save_g(SB)
451	MOVW	(g_sched+gobuf_sp)(g), R29
452
453	// Now on a scheduling stack (a pthread-created stack).
454g0:
455	// Save room for two of our pointers and O32 frame.
456	ADDU	$-24, R29
457	AND	$~7, R29	// O32 ABI expects 8-byte aligned stack on function entry
458	MOVW	R2, 16(R29)	// save old g on stack
459	MOVW	(g_stack+stack_hi)(R2), R2
460	SUBU	R3, R2
461	MOVW	R2, 20(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	MOVW	16(R29), g
466	JAL	runtime·save_g(SB)
467	MOVW	(g_stack+stack_hi)(g), R5
468	MOVW	20(R29), R6
469	SUBU	R6, R5
470	MOVW	R5, R29
471
472	MOVW	R2, ret+8(FP)
473	RET
474
475// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
476// Turn the fn into a Go func (by taking its address) and call
477// cgocallback_gofunc.
478TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
479	MOVW	$fn+0(FP), R1
480	MOVW	R1, 4(R29)
481	MOVW	frame+4(FP), R1
482	MOVW	R1, 8(R29)
483	MOVW	framesize+8(FP), R1
484	MOVW	R1, 12(R29)
485	MOVW	ctxt+12(FP), R1
486	MOVW	R1, 16(R29)
487	MOVW	$runtime·cgocallback_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.
493TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-16
494	NO_LOCAL_POINTERS
495
496	// Load m and g from thread-local storage.
497	MOVB	runtime·iscgo(SB), R1
498	BEQ	R1, nocgo
499	JAL	runtime·load_g(SB)
500nocgo:
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	MOVW	g_m(g), R3
510	MOVW	R3, savedm-4(SP)
511	JMP	havem
512
513needm:
514	MOVW	g, savedm-4(SP) // g is zero, so is m.
515	MOVW	$runtime·needm(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	MOVW	g_m(g), R3
530	MOVW	m_g0(R3), R1
531	MOVW	R29, (g_sched+gobuf_sp)(R1)
532
533havem:
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 4(R29) aka savedsp-8(SP).
539	MOVW	m_g0(R3), R1
540	MOVW	(g_sched+gobuf_sp)(R1), R2
541	MOVW	R2, savedsp-8(SP)
542	MOVW	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, -4(SP) is unused (where SP refers to
559	// m->curg's SP while we're setting it up, before we've adjusted it).
560	MOVW	m_curg(R3), g
561	JAL	runtime·save_g(SB)
562	MOVW	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
563	MOVW	(g_sched+gobuf_pc)(g), R4
564	MOVW	R4, -12(R2)
565	MOVW    ctxt+12(FP), R1
566	MOVW    R1, -8(R2)
567	MOVW	$-12(R2), R29
568	JAL	runtime·cgocallbackg(SB)
569
570	// Restore g->sched (== m->curg->sched) from saved values.
571	MOVW	0(R29), R4
572	MOVW	R4, (g_sched+gobuf_pc)(g)
573	MOVW	$12(R29), R2
574	MOVW	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	MOVW	g_m(g), R3
580	MOVW	m_g0(R3), g
581	JAL	runtime·save_g(SB)
582	MOVW	(g_sched+gobuf_sp)(g), R29
583	MOVW	savedsp-8(SP), R2
584	MOVW	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	MOVW	savedm-4(SP), R3
589	BNE	R3, droppedm
590	MOVW	$runtime·dropm(SB), R4
591	JAL	(R4)
592droppedm:
593
594	// Done!
595	RET
596
597// void setg(G*); set g. for use by needm.
598// This only happens if iscgo, so jump straight to save_g
599TEXT runtime·setg(SB),NOSPLIT,$0-4
600	MOVW	gg+0(FP), g
601	JAL	runtime·save_g(SB)
602	RET
603
604// void setg_gcc(G*); set g in C TLS.
605// Must obey the gcc calling convention.
606TEXT setg_gcc<>(SB),NOSPLIT,$0
607	MOVW	R4, g
608	JAL	runtime·save_g(SB)
609	RET
610
611TEXT runtime·abort(SB),NOSPLIT,$0-0
612	UNDEF
613
614// AES hashing not implemented for mips
615TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-16
616	JMP	runtime·memhashFallback(SB)
617TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-12
618	JMP	runtime·strhashFallback(SB)
619TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-12
620	JMP	runtime·memhash32Fallback(SB)
621TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-12
622	JMP	runtime·memhash64Fallback(SB)
623
624TEXT runtime·return0(SB),NOSPLIT,$0
625	MOVW	$0, R1
626	RET
627
628// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
629// Must obey the gcc calling convention.
630TEXT _cgo_topofstack(SB),NOSPLIT|NOFRAME,$0
631	// g (R30), R3 and REGTMP (R23) might be clobbered by load_g. R30 and R23
632	// are callee-save in the gcc calling convention, so save them.
633	MOVW	R23, R8
634	MOVW	g, R9
635	MOVW	R31, R10 // this call frame does not save LR
636
637	JAL	runtime·load_g(SB)
638	MOVW	g_m(g), R1
639	MOVW	m_curg(R1), R1
640	MOVW	(g_stack+stack_hi)(R1), R2 // return value in R2
641
642	MOVW	R8, R23
643	MOVW	R9, g
644	MOVW	R10, R31
645
646	RET
647
648// The top-most function running on a goroutine
649// returns to goexit+PCQuantum.
650TEXT runtime·goexit(SB),NOSPLIT|NOFRAME|TOPFRAME,$0-0
651	NOR	R0, R0	// NOP
652	JAL	runtime·goexit1(SB)	// does not return
653	// traceback from goexit1 must hit code range of goexit
654	NOR	R0, R0	// NOP
655
656TEXT ·checkASM(SB),NOSPLIT,$0-1
657	MOVW	$1, R1
658	MOVB	R1, ret+0(FP)
659	RET
660
661// gcWriteBarrier performs a heap pointer write and informs the GC.
662//
663// gcWriteBarrier does NOT follow the Go ABI. It takes two arguments:
664// - R20 is the destination of the write
665// - R21 is the value being written at R20.
666// It clobbers R23 (the linker temp register).
667// The act of CALLing gcWriteBarrier will clobber R31 (LR).
668// It does not clobber any other general-purpose registers,
669// but may clobber others (e.g., floating point registers).
670TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$104
671	// Save the registers clobbered by the fast path.
672	MOVW	R1, 100(R29)
673	MOVW	R2, 104(R29)
674	MOVW	g_m(g), R1
675	MOVW	m_p(R1), R1
676	MOVW	(p_wbBuf+wbBuf_next)(R1), R2
677	// Increment wbBuf.next position.
678	ADD	$8, R2
679	MOVW	R2, (p_wbBuf+wbBuf_next)(R1)
680	MOVW	(p_wbBuf+wbBuf_end)(R1), R1
681	MOVW	R1, R23		// R23 is linker temp register
682	// Record the write.
683	MOVW	R21, -8(R2)	// Record value
684	MOVW	(R20), R1	// TODO: This turns bad writes into bad reads.
685	MOVW	R1, -4(R2)	// Record *slot
686	// Is the buffer full?
687	BEQ	R2, R23, flush
688ret:
689	MOVW	100(R29), R1
690	MOVW	104(R29), R2
691	// Do the write.
692	MOVW	R21, (R20)
693	RET
694
695flush:
696	// Save all general purpose registers since these could be
697	// clobbered by wbBufFlush and were not saved by the caller.
698	MOVW	R20, 4(R29)	// Also first argument to wbBufFlush
699	MOVW	R21, 8(R29)	// Also second argument to wbBufFlush
700	// R1 already saved
701	// R2 already saved
702	MOVW	R3, 12(R29)
703	MOVW	R4, 16(R29)
704	MOVW	R5, 20(R29)
705	MOVW	R6, 24(R29)
706	MOVW	R7, 28(R29)
707	MOVW	R8, 32(R29)
708	MOVW	R9, 36(R29)
709	MOVW	R10, 40(R29)
710	MOVW	R11, 44(R29)
711	MOVW	R12, 48(R29)
712	MOVW	R13, 52(R29)
713	MOVW	R14, 56(R29)
714	MOVW	R15, 60(R29)
715	MOVW	R16, 64(R29)
716	MOVW	R17, 68(R29)
717	MOVW	R18, 72(R29)
718	MOVW	R19, 76(R29)
719	MOVW	R20, 80(R29)
720	// R21 already saved
721	// R22 already saved.
722	MOVW	R22, 84(R29)
723	// R23 is tmp register.
724	MOVW	R24, 88(R29)
725	MOVW	R25, 92(R29)
726	// R26 is reserved by kernel.
727	// R27 is reserved by kernel.
728	MOVW	R28, 96(R29)
729	// R29 is SP.
730	// R30 is g.
731	// R31 is LR, which was saved by the prologue.
732
733	// This takes arguments R20 and R21.
734	CALL	runtime·wbBufFlush(SB)
735
736	MOVW	4(R29), R20
737	MOVW	8(R29), R21
738	MOVW	12(R29), R3
739	MOVW	16(R29), R4
740	MOVW	20(R29), R5
741	MOVW	24(R29), R6
742	MOVW	28(R29), R7
743	MOVW	32(R29), R8
744	MOVW	36(R29), R9
745	MOVW	40(R29), R10
746	MOVW	44(R29), R11
747	MOVW	48(R29), R12
748	MOVW	52(R29), R13
749	MOVW	56(R29), R14
750	MOVW	60(R29), R15
751	MOVW	64(R29), R16
752	MOVW	68(R29), R17
753	MOVW	72(R29), R18
754	MOVW	76(R29), R19
755	MOVW	80(R29), R20
756	MOVW	84(R29), R22
757	MOVW	88(R29), R24
758	MOVW	92(R29), R25
759	MOVW	96(R29), R28
760	JMP	ret
761
762// Note: these functions use a special calling convention to save generated code space.
763// Arguments are passed in registers, but the space for those arguments are allocated
764// in the caller's stack frame. These stubs write the args into that stack space and
765// then tail call to the corresponding runtime handler.
766// The tail call makes these stubs disappear in backtraces.
767TEXT runtime·panicIndex(SB),NOSPLIT,$0-8
768	MOVW	R1, x+0(FP)
769	MOVW	R2, y+4(FP)
770	JMP	runtime·goPanicIndex(SB)
771TEXT runtime·panicIndexU(SB),NOSPLIT,$0-8
772	MOVW	R1, x+0(FP)
773	MOVW	R2, y+4(FP)
774	JMP	runtime·goPanicIndexU(SB)
775TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-8
776	MOVW	R2, x+0(FP)
777	MOVW	R3, y+4(FP)
778	JMP	runtime·goPanicSliceAlen(SB)
779TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-8
780	MOVW	R2, x+0(FP)
781	MOVW	R3, y+4(FP)
782	JMP	runtime·goPanicSliceAlenU(SB)
783TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-8
784	MOVW	R2, x+0(FP)
785	MOVW	R3, y+4(FP)
786	JMP	runtime·goPanicSliceAcap(SB)
787TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-8
788	MOVW	R2, x+0(FP)
789	MOVW	R3, y+4(FP)
790	JMP	runtime·goPanicSliceAcapU(SB)
791TEXT runtime·panicSliceB(SB),NOSPLIT,$0-8
792	MOVW	R1, x+0(FP)
793	MOVW	R2, y+4(FP)
794	JMP	runtime·goPanicSliceB(SB)
795TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-8
796	MOVW	R1, x+0(FP)
797	MOVW	R2, y+4(FP)
798	JMP	runtime·goPanicSliceBU(SB)
799TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-8
800	MOVW	R3, x+0(FP)
801	MOVW	R4, y+4(FP)
802	JMP	runtime·goPanicSlice3Alen(SB)
803TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-8
804	MOVW	R3, x+0(FP)
805	MOVW	R4, y+4(FP)
806	JMP	runtime·goPanicSlice3AlenU(SB)
807TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-8
808	MOVW	R3, x+0(FP)
809	MOVW	R4, y+4(FP)
810	JMP	runtime·goPanicSlice3Acap(SB)
811TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-8
812	MOVW	R3, x+0(FP)
813	MOVW	R4, y+4(FP)
814	JMP	runtime·goPanicSlice3AcapU(SB)
815TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-8
816	MOVW	R2, x+0(FP)
817	MOVW	R3, y+4(FP)
818	JMP	runtime·goPanicSlice3B(SB)
819TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-8
820	MOVW	R2, x+0(FP)
821	MOVW	R3, y+4(FP)
822	JMP	runtime·goPanicSlice3BU(SB)
823TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-8
824	MOVW	R1, x+0(FP)
825	MOVW	R2, y+4(FP)
826	JMP	runtime·goPanicSlice3C(SB)
827TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-8
828	MOVW	R1, x+0(FP)
829	MOVW	R2, y+4(FP)
830	JMP	runtime·goPanicSlice3CU(SB)
831
832// Extended versions for 64-bit indexes.
833TEXT runtime·panicExtendIndex(SB),NOSPLIT,$0-12
834	MOVW	R5, hi+0(FP)
835	MOVW	R1, lo+4(FP)
836	MOVW	R2, y+8(FP)
837	JMP	runtime·goPanicExtendIndex(SB)
838TEXT runtime·panicExtendIndexU(SB),NOSPLIT,$0-12
839	MOVW	R5, hi+0(FP)
840	MOVW	R1, lo+4(FP)
841	MOVW	R2, y+8(FP)
842	JMP	runtime·goPanicExtendIndexU(SB)
843TEXT runtime·panicExtendSliceAlen(SB),NOSPLIT,$0-12
844	MOVW	R5, hi+0(FP)
845	MOVW	R2, lo+4(FP)
846	MOVW	R3, y+8(FP)
847	JMP	runtime·goPanicExtendSliceAlen(SB)
848TEXT runtime·panicExtendSliceAlenU(SB),NOSPLIT,$0-12
849	MOVW	R5, hi+0(FP)
850	MOVW	R2, lo+4(FP)
851	MOVW	R3, y+8(FP)
852	JMP	runtime·goPanicExtendSliceAlenU(SB)
853TEXT runtime·panicExtendSliceAcap(SB),NOSPLIT,$0-12
854	MOVW	R5, hi+0(FP)
855	MOVW	R2, lo+4(FP)
856	MOVW	R3, y+8(FP)
857	JMP	runtime·goPanicExtendSliceAcap(SB)
858TEXT runtime·panicExtendSliceAcapU(SB),NOSPLIT,$0-12
859	MOVW	R5, hi+0(FP)
860	MOVW	R2, lo+4(FP)
861	MOVW	R3, y+8(FP)
862	JMP	runtime·goPanicExtendSliceAcapU(SB)
863TEXT runtime·panicExtendSliceB(SB),NOSPLIT,$0-12
864	MOVW	R5, hi+0(FP)
865	MOVW	R1, lo+4(FP)
866	MOVW	R2, y+8(FP)
867	JMP	runtime·goPanicExtendSliceB(SB)
868TEXT runtime·panicExtendSliceBU(SB),NOSPLIT,$0-12
869	MOVW	R5, hi+0(FP)
870	MOVW	R1, lo+4(FP)
871	MOVW	R2, y+8(FP)
872	JMP	runtime·goPanicExtendSliceBU(SB)
873TEXT runtime·panicExtendSlice3Alen(SB),NOSPLIT,$0-12
874	MOVW	R5, hi+0(FP)
875	MOVW	R3, lo+4(FP)
876	MOVW	R4, y+8(FP)
877	JMP	runtime·goPanicExtendSlice3Alen(SB)
878TEXT runtime·panicExtendSlice3AlenU(SB),NOSPLIT,$0-12
879	MOVW	R5, hi+0(FP)
880	MOVW	R3, lo+4(FP)
881	MOVW	R4, y+8(FP)
882	JMP	runtime·goPanicExtendSlice3AlenU(SB)
883TEXT runtime·panicExtendSlice3Acap(SB),NOSPLIT,$0-12
884	MOVW	R5, hi+0(FP)
885	MOVW	R3, lo+4(FP)
886	MOVW	R4, y+8(FP)
887	JMP	runtime·goPanicExtendSlice3Acap(SB)
888TEXT runtime·panicExtendSlice3AcapU(SB),NOSPLIT,$0-12
889	MOVW	R5, hi+0(FP)
890	MOVW	R3, lo+4(FP)
891	MOVW	R4, y+8(FP)
892	JMP	runtime·goPanicExtendSlice3AcapU(SB)
893TEXT runtime·panicExtendSlice3B(SB),NOSPLIT,$0-12
894	MOVW	R5, hi+0(FP)
895	MOVW	R2, lo+4(FP)
896	MOVW	R3, y+8(FP)
897	JMP	runtime·goPanicExtendSlice3B(SB)
898TEXT runtime·panicExtendSlice3BU(SB),NOSPLIT,$0-12
899	MOVW	R5, hi+0(FP)
900	MOVW	R2, lo+4(FP)
901	MOVW	R3, y+8(FP)
902	JMP	runtime·goPanicExtendSlice3BU(SB)
903TEXT runtime·panicExtendSlice3C(SB),NOSPLIT,$0-12
904	MOVW	R5, hi+0(FP)
905	MOVW	R1, lo+4(FP)
906	MOVW	R2, y+8(FP)
907	JMP	runtime·goPanicExtendSlice3C(SB)
908TEXT runtime·panicExtendSlice3CU(SB),NOSPLIT,$0-12
909	MOVW	R5, hi+0(FP)
910	MOVW	R1, lo+4(FP)
911	MOVW	R2, y+8(FP)
912	JMP	runtime·goPanicExtendSlice3CU(SB)
913