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