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// PPC64LE ELFv2 ABI:
11// - Integer args: R3-R10 (8 registers)
12// - Float args: F1-F8 (8 registers)
13// - Return: R3 (integer), F1 (float)
14// - Stack pointer: R1
15// - Link register: LR (special)
16// - TOC pointer: R2 (must preserve)
17
18// Stack layout for ELFv2 ABI (aligned to 16 bytes):
19// From callee's perspective when we call BL (CTR):
20// 0(R1) - back chain (our old R1)
21// 8(R1) - CR save word (optional)
22// 16(R1) - LR save (optional, we save it)
23// 24(R1) - Reserved (compilers)
24// 32(R1) - Parameter save area start (8 * 8 = 64 bytes for R3-R10)
25// 96(R1) - First stack arg (a9) - this is where callee looks
26// 104(R1) - Second stack arg (a10)
27// 112-152 - Stack args a11-a15 (5 * 8 = 40 bytes)
28// 160(R1) - TOC save (we put it here, outside param save area)
29// 168(R1) - saved args pointer
30// 176(R1) - padding for 16-byte alignment
31// Total: 176 bytes
32
33#define STACK_SIZE 176
34#define LR_SAVE 16
35#define TOC_SAVE 160
36#define ARGP_SAVE 168
37
38GLOBL ·syscallXABI0(SB), NOPTR|RODATA, $8
39DATA ·syscallXABI0(SB)/8, $syscallX(SB)
40
41TEXT syscallX(SB), NOSPLIT, $0
42 // Prologue: create stack frame
43 // R3 contains the args pointer on entry
44 MOVD R1, R12 // save old SP
45 SUB $STACK_SIZE, R1 // allocate stack frame
46 MOVD R12, 0(R1) // save back chain
47 MOVD LR, R12
48 MOVD R12, LR_SAVE(R1) // save LR
49 MOVD R2, TOC_SAVE(R1) // save TOC
50
51 // Save args pointer (in R3)
52 MOVD R3, ARGP_SAVE(R1)
53
54 // R11 := args pointer (syscallArgs*)
55 MOVD R3, R11
56
57 // Load float args into F1-F8
58 FMOVD syscallArgs_f1(R11), F1
59 FMOVD syscallArgs_f2(R11), F2
60 FMOVD syscallArgs_f3(R11), F3
61 FMOVD syscallArgs_f4(R11), F4
62 FMOVD syscallArgs_f5(R11), F5
63 FMOVD syscallArgs_f6(R11), F6
64 FMOVD syscallArgs_f7(R11), F7
65 FMOVD syscallArgs_f8(R11), F8
66
67 // Load integer args into R3-R10
68 MOVD syscallArgs_a1(R11), R3
69 MOVD syscallArgs_a2(R11), R4
70 MOVD syscallArgs_a3(R11), R5
71 MOVD syscallArgs_a4(R11), R6
72 MOVD syscallArgs_a5(R11), R7
73 MOVD syscallArgs_a6(R11), R8
74 MOVD syscallArgs_a7(R11), R9
75 MOVD syscallArgs_a8(R11), R10
76
77 // Spill a9-a15 onto the stack (stack parameters start at 96(R1))
78 // Per ELFv2: parameter save area is 32-95, stack args start at 96
79 MOVD ARGP_SAVE(R1), R11 // reload args pointer
80 MOVD syscallArgs_a9(R11), R12
81 MOVD R12, 96(R1) // a9 at 96(R1)
82 MOVD syscallArgs_a10(R11), R12
83 MOVD R12, 104(R1) // a10 at 104(R1)
84 MOVD syscallArgs_a11(R11), R12
85 MOVD R12, 112(R1) // a11 at 112(R1)
86 MOVD syscallArgs_a12(R11), R12
87 MOVD R12, 120(R1) // a12 at 120(R1)
88 MOVD syscallArgs_a13(R11), R12
89 MOVD R12, 128(R1) // a13 at 128(R1)
90 MOVD syscallArgs_a14(R11), R12
91 MOVD R12, 136(R1) // a14 at 136(R1)
92 MOVD syscallArgs_a15(R11), R12
93 MOVD R12, 144(R1) // a15 at 144(R1)
94
95 // Call function: load fn and call
96 MOVD syscallArgs_fn(R11), R12
97 MOVD R12, CTR
98 BL (CTR)
99
100 // Restore TOC after call
101 MOVD TOC_SAVE(R1), R2
102
103 // Restore args pointer for storing results
104 MOVD ARGP_SAVE(R1), R11
105
106 // Store integer results back (R3, R4)
107 MOVD R3, syscallArgs_a1(R11)
108 MOVD R4, syscallArgs_a2(R11)
109 MOVD $0, R3
110 MOVD R3, syscallArgs_a3(R11) // no errno here: clear the input argument
111
112 // Store float return values F1-F8 (an HFA may span up to eight).
113 FMOVD F1, syscallArgs_f1(R11)
114 FMOVD F2, syscallArgs_f2(R11)
115 FMOVD F3, syscallArgs_f3(R11)
116 FMOVD F4, syscallArgs_f4(R11)
117 FMOVD F5, syscallArgs_f5(R11)
118 FMOVD F6, syscallArgs_f6(R11)
119 FMOVD F7, syscallArgs_f7(R11)
120 FMOVD F8, syscallArgs_f8(R11)
121
122 // Epilogue: restore and return
123 MOVD LR_SAVE(R1), R12
124 MOVD R12, LR
125 ADD $STACK_SIZE, R1
126 RET