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