sys_s390x.s raw
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-a15 (10 * 8 = 80 bytes)
28 // - Saved args pointer (8 bytes)
29 // - Padding for alignment
30 // Total: 264 bytes (rounded to 8-byte alignment)
31
32 #define STACK_SIZE 264
33 #define STACK_ARGS 160
34 #define ARGP_SAVE 248
35
36 GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
37 DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
38
39 TEXT syscall15X(SB), NOSPLIT, $0
40 // On entry, R2 contains the args pointer
41 // Save callee-saved registers in caller's frame (per ABI)
42 STMG R6, R15, 48(R15)
43
44 // Allocate our stack frame
45 MOVD R15, R1
46 SUB $STACK_SIZE, R15
47 MOVD R1, 0(R15) // back chain
48
49 // Save args pointer
50 MOVD R2, ARGP_SAVE(R15)
51
52 // R9 := args pointer (syscall15Args*)
53 MOVD R2, R9
54
55 // Load float args into F0, F2, F4, F6 (s390x uses even-numbered FPRs)
56 FMOVD syscall15Args_f1(R9), F0
57 FMOVD syscall15Args_f2(R9), F2
58 FMOVD syscall15Args_f3(R9), F4
59 FMOVD syscall15Args_f4(R9), F6
60
61 // Load integer args into R2-R6 (5 registers)
62 MOVD syscall15Args_a1(R9), R2
63 MOVD syscall15Args_a2(R9), R3
64 MOVD syscall15Args_a3(R9), R4
65 MOVD syscall15Args_a4(R9), R5
66 MOVD syscall15Args_a5(R9), R6
67
68 // Spill remaining args (a6-a15) onto the stack at 160(R15)
69 MOVD ARGP_SAVE(R15), R9 // reload args pointer
70 MOVD syscall15Args_a6(R9), R1
71 MOVD R1, (STACK_ARGS+0*8)(R15)
72 MOVD syscall15Args_a7(R9), R1
73 MOVD R1, (STACK_ARGS+1*8)(R15)
74 MOVD syscall15Args_a8(R9), R1
75 MOVD R1, (STACK_ARGS+2*8)(R15)
76 MOVD syscall15Args_a9(R9), R1
77 MOVD R1, (STACK_ARGS+3*8)(R15)
78 MOVD syscall15Args_a10(R9), R1
79 MOVD R1, (STACK_ARGS+4*8)(R15)
80 MOVD syscall15Args_a11(R9), R1
81 MOVD R1, (STACK_ARGS+5*8)(R15)
82 MOVD syscall15Args_a12(R9), R1
83 MOVD R1, (STACK_ARGS+6*8)(R15)
84 MOVD syscall15Args_a13(R9), R1
85 MOVD R1, (STACK_ARGS+7*8)(R15)
86 MOVD syscall15Args_a14(R9), R1
87 MOVD R1, (STACK_ARGS+8*8)(R15)
88 MOVD syscall15Args_a15(R9), R1
89 MOVD R1, (STACK_ARGS+9*8)(R15)
90
91 // Call function
92 MOVD syscall15Args_fn(R9), R1
93 BL (R1)
94
95 // Restore args pointer for storing results
96 MOVD ARGP_SAVE(R15), R9
97
98 // Store integer results back (R2, R3)
99 MOVD R2, syscall15Args_a1(R9)
100 MOVD R3, syscall15Args_a2(R9)
101
102 // Store float return values (F0, F2, F4, F6)
103 FMOVD F0, syscall15Args_f1(R9)
104 FMOVD F2, syscall15Args_f2(R9)
105 FMOVD F4, syscall15Args_f3(R9)
106 FMOVD F6, syscall15Args_f4(R9)
107
108 // Deallocate stack frame
109 ADD $STACK_SIZE, R15
110
111 // Restore callee-saved registers from caller's save area
112 LMG 48(R15), R6, R15
113
114 RET
115