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