1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3
4#include "textflag.h"
5#include "go_asm.h"
6#include "funcdata.h"
7#include "internal/abi/abi_arm64.h"
8
9// syscall9X calls a function in libc on behalf of the syscall package.
10// syscall9X takes a pointer to a struct like:
11// struct {
12// fn uintptr
13// a1 uintptr
14// a2 uintptr
15// a3 uintptr
16// a4 uintptr
17// a5 uintptr
18// a6 uintptr
19// a7 uintptr
20// a8 uintptr
21// a9 uintptr
22// r1 uintptr
23// r2 uintptr
24// err uintptr
25// }
26// syscall9X must be called on the g0 stack with the
27// C calling convention (use libcCall).
28GLOBL ·syscall9XABI0(SB), NOPTR|RODATA, $8
29DATA ·syscall9XABI0(SB)/8, $syscall9X(SB)
30TEXT syscall9X(SB), NOSPLIT, $0
31 SUB $16, RSP // push structure pointer
32 MOVD R0, 8(RSP)
33
34 MOVD syscall9Args_fn(R0), R12 // fn
35 MOVD syscall9Args_a2(R0), R1 // a2
36 MOVD syscall9Args_a3(R0), R2 // a3
37 MOVD syscall9Args_a4(R0), R3 // a4
38 MOVD syscall9Args_a5(R0), R4 // a5
39 MOVD syscall9Args_a6(R0), R5 // a6
40 MOVD syscall9Args_a7(R0), R6 // a7
41 MOVD syscall9Args_a8(R0), R7 // a8
42 MOVD syscall9Args_a9(R0), R8 // a9
43 MOVD syscall9Args_a1(R0), R0 // a1
44
45 // these may be float arguments
46 // so we put them also where C expects floats
47 FMOVD R0, F0 // a1
48 FMOVD R1, F1 // a2
49 FMOVD R2, F2 // a3
50 FMOVD R3, F3 // a4
51 FMOVD R4, F4 // a5
52 FMOVD R5, F5 // a6
53 FMOVD R6, F6 // a7
54 FMOVD R7, F7 // a8
55
56 MOVD R8, (RSP) // push a9 onto stack
57
58 BL (R12)
59
60 MOVD 8(RSP), R2 // pop structure pointer
61 ADD $16, RSP
62 MOVD R0, syscall9Args_r1(R2) // save r1
63 MOVD R1, syscall9Args_r2(R2) // save r2
64 RET
65
66// runtime·cgocallback expects a call to the ABIInternal function
67// However, the tag <ABIInternal> is only available in the runtime :(
68// This is a small wrapper function that copies both whatever is in the register
69// and is on the stack and places both on the stack. It then calls callbackWrapPicker
70// which will choose which parameter should be used depending on the version of Go.
71// It then calls the real version of callbackWrap
72TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
73 MOVD R0, 16(RSP)
74 B ·callbackWrapPicker(SB)
75 RET
76
77TEXT callbackasm1(SB), NOSPLIT, $208-0
78 NO_LOCAL_POINTERS
79
80 // On entry, the trampoline in zcallback_darwin_arm64.s left
81 // the callback index in R12 (which is volatile in the C ABI).
82
83 // Save callback register arguments R0-R7.
84 // We do this at the top of the frame so they're contiguous with stack arguments.
85 // The 7*8 setting up R14 looks like a bug but is not: the eighth word
86 // is the space the assembler reserved for our caller's frame pointer,
87 // but we are not called from Go so that space is ours to use,
88 // and we must to be contiguous with the stack arguments.
89 MOVD $arg0-(7*8)(SP), R14
90 STP (R0, R1), (0*8)(R14)
91 STP (R2, R3), (2*8)(R14)
92 STP (R4, R5), (4*8)(R14)
93 STP (R6, R7), (6*8)(R14)
94
95 // Create a struct callbackArgs on our stack.
96 MOVD $cbargs-(18*8+callbackArgs__size)(SP), R13
97 MOVD R12, callbackArgs_index(R13) // callback index
98 MOVD R14, R0
99 MOVD R0, callbackArgs_args(R13) // address of args vector
100 MOVD $0, R0
101 MOVD R0, callbackArgs_result(R13) // result
102
103 // Move parameters into registers
104 MOVD $callbackWrapInternal<>(SB), R0 // fn unsafe.Pointer
105 MOVD R13, R1 // frame (&callbackArgs{...})
106 MOVD $0, R3 // ctxt uintptr
107
108 // We still need to save all callee save register as before, and then
109 // push 3 args for fn (R0, R1, R3), skipping R2.
110 // Also note that at procedure entry in gc world, 8(RSP) will be the
111 // first arg.
112 SUB $(8*24), RSP
113 STP (R0, R1), (8*1)(RSP)
114 MOVD R3, (8*3)(RSP)
115
116 // Push C callee-save registers R19-R28.
117 // LR, FP already saved.
118 SAVE_R19_TO_R28(8*4)
119 SAVE_F8_TO_F15(8*14)
120 STP (R29, R30), (8*22)(RSP)
121
122 // Initialize Go ABI environment
123 BL runtime·load_g(SB)
124 BL runtime·cgocallback(SB)
125
126 RESTORE_R19_TO_R28(8*4)
127 RESTORE_F8_TO_F15(8*14)
128 LDP (8*22)(RSP), (R29, R30)
129
130 ADD $(8*24), RSP
131
132 // Get callback result.
133 MOVD $cbargs-(18*8+callbackArgs__size)(SP), R13
134 MOVD callbackArgs_result(R13), R0
135
136 RET