1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3
4//go:build linux
5
6#include "textflag.h"
7#include "go_asm.h"
8#include "funcdata.h"
9
10// S390X ELF ABI:
11// - Integer args: R2-R6 (5 registers)
12// - Float args: F0, F2, F4, F6 (4 registers, even-numbered)
13// - Return: R2 (integer), F0 (float)
14// - Stack pointer: R15
15// - Link register: R14
16// - Callee-saved: R6-R13, F8-F15 (but R6 is also used for 5th param)
17//
18// Stack frame layout (aligned to 8 bytes):
19// 0(R15) - back chain
20// 8(R15) - reserved
21// 16(R15) - reserved
22// ... - register save area (R6-R15 at 48(R15))
23// 160(R15) - parameter area start (args beyond registers)
24//
25// We need space for:
26// - 160 bytes standard frame (with register save area)
27// - Stack args a6-a32 (27 * 8 = 216 bytes)
28// - Saved args pointer (8 bytes)
29// Total: 384 bytes
30
31#define STACK_SIZE 384
32#define STACK_ARGS 160
33#define ARGP_SAVE 376
34
35GLOBL ·syscallXABI0(SB), NOPTR|RODATA, $8
36DATA ·syscallXABI0(SB)/8, $syscallX(SB)
37
38TEXT syscallX(SB), NOSPLIT, $0
39 // On entry, R2 contains the args pointer
40 // Save callee-saved registers in caller's frame (per ABI)
41 STMG R6, R15, 48(R15)
42
43 // Allocate our stack frame
44 MOVD R15, R1
45 SUB $STACK_SIZE, R15
46 MOVD R1, 0(R15) // back chain
47
48 // Save args pointer
49 MOVD R2, ARGP_SAVE(R15)
50
51 // R9 := args pointer (syscallArgs*)
52 MOVD R2, R9
53
54 // Load float args into F0, F2, F4, F6 (s390x uses even-numbered FPRs)
55 FMOVD syscallArgs_f1(R9), F0
56 FMOVD syscallArgs_f2(R9), F2
57 FMOVD syscallArgs_f3(R9), F4
58 FMOVD syscallArgs_f4(R9), F6
59
60 // Load integer args into R2-R6 (5 registers)
61 MOVD syscallArgs_a1(R9), R2
62 MOVD syscallArgs_a2(R9), R3
63 MOVD syscallArgs_a3(R9), R4
64 MOVD syscallArgs_a4(R9), R5
65 MOVD syscallArgs_a5(R9), R6
66
67 // Spill remaining args (a6-a32) onto the stack at 160(R15)
68 MOVD ARGP_SAVE(R15), R9 // reload args pointer
69 MOVD syscallArgs_a6(R9), R1
70 MOVD R1, (STACK_ARGS+0*8)(R15)
71 MOVD syscallArgs_a7(R9), R1
72 MOVD R1, (STACK_ARGS+1*8)(R15)
73 MOVD syscallArgs_a8(R9), R1
74 MOVD R1, (STACK_ARGS+2*8)(R15)
75 MOVD syscallArgs_a9(R9), R1
76 MOVD R1, (STACK_ARGS+3*8)(R15)
77 MOVD syscallArgs_a10(R9), R1
78 MOVD R1, (STACK_ARGS+4*8)(R15)
79 MOVD syscallArgs_a11(R9), R1
80 MOVD R1, (STACK_ARGS+5*8)(R15)
81 MOVD syscallArgs_a12(R9), R1
82 MOVD R1, (STACK_ARGS+6*8)(R15)
83 MOVD syscallArgs_a13(R9), R1
84 MOVD R1, (STACK_ARGS+7*8)(R15)
85 MOVD syscallArgs_a14(R9), R1
86 MOVD R1, (STACK_ARGS+8*8)(R15)
87 MOVD syscallArgs_a15(R9), R1
88 MOVD R1, (STACK_ARGS+9*8)(R15)
89 MOVD syscallArgs_a16(R9), R1
90 MOVD R1, (STACK_ARGS+10*8)(R15)
91 MOVD syscallArgs_a17(R9), R1
92 MOVD R1, (STACK_ARGS+11*8)(R15)
93 MOVD syscallArgs_a18(R9), R1
94 MOVD R1, (STACK_ARGS+12*8)(R15)
95 MOVD syscallArgs_a19(R9), R1
96 MOVD R1, (STACK_ARGS+13*8)(R15)
97 MOVD syscallArgs_a20(R9), R1
98 MOVD R1, (STACK_ARGS+14*8)(R15)
99 MOVD syscallArgs_a21(R9), R1
100 MOVD R1, (STACK_ARGS+15*8)(R15)
101 MOVD syscallArgs_a22(R9), R1
102 MOVD R1, (STACK_ARGS+16*8)(R15)
103 MOVD syscallArgs_a23(R9), R1
104 MOVD R1, (STACK_ARGS+17*8)(R15)
105 MOVD syscallArgs_a24(R9), R1
106 MOVD R1, (STACK_ARGS+18*8)(R15)
107 MOVD syscallArgs_a25(R9), R1
108 MOVD R1, (STACK_ARGS+19*8)(R15)
109 MOVD syscallArgs_a26(R9), R1
110 MOVD R1, (STACK_ARGS+20*8)(R15)
111 MOVD syscallArgs_a27(R9), R1
112 MOVD R1, (STACK_ARGS+21*8)(R15)
113 MOVD syscallArgs_a28(R9), R1
114 MOVD R1, (STACK_ARGS+22*8)(R15)
115 MOVD syscallArgs_a29(R9), R1
116 MOVD R1, (STACK_ARGS+23*8)(R15)
117 MOVD syscallArgs_a30(R9), R1
118 MOVD R1, (STACK_ARGS+24*8)(R15)
119 MOVD syscallArgs_a31(R9), R1
120 MOVD R1, (STACK_ARGS+25*8)(R15)
121 MOVD syscallArgs_a32(R9), R1
122 MOVD R1, (STACK_ARGS+26*8)(R15)
123
124 // Call function
125 MOVD syscallArgs_fn(R9), R1
126 BL (R1)
127
128 // Restore args pointer for storing results
129 MOVD ARGP_SAVE(R15), R9
130
131 // Store integer results back (R2, R3)
132 MOVD R2, syscallArgs_a1(R9)
133 MOVD R3, syscallArgs_a2(R9)
134 MOVD $0, syscallArgs_a3(R9) // no errno here: clear the input argument
135
136 // Store float return values (F0, F2, F4, F6)
137 FMOVD F0, syscallArgs_f1(R9)
138 FMOVD F2, syscallArgs_f2(R9)
139 FMOVD F4, syscallArgs_f3(R9)
140 FMOVD F6, syscallArgs_f4(R9)
141
142 // Deallocate stack frame
143 ADD $STACK_SIZE, R15
144
145 // Restore callee-saved registers from caller's save area
146 LMG 48(R15), R6, R15
147
148 RET