1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * SPARC (32bit and 64bit) specific definitions for NOLIBC 4 * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 */ 6 7 #ifndef _NOLIBC_ARCH_SPARC_H 8 #define _NOLIBC_ARCH_SPARC_H 9 10 #include <linux/unistd.h> 11 12 #include "compiler.h" 13 #include "crt.h" 14 15 /* 16 * Syscalls for SPARC: 17 * - registers are native word size 18 * - syscall number is passed in g1 19 * - arguments are in o0-o5 20 * - the system call is performed by calling a trap instruction 21 * - syscall return value is in o0 22 * - syscall error flag is in the carry bit of the processor status register 23 */ 24 25 #ifdef __arch64__ 26 27 #define _NOLIBC_SYSCALL "t 0x6d\n" \ 28 "bcs,a %%xcc, 1f\n" \ 29 "sub %%g0, %%o0, %%o0\n" \ 30 "1:\n" 31 32 #else 33 34 #define _NOLIBC_SYSCALL "t 0x10\n" \ 35 "bcs,a 1f\n" \ 36 "sub %%g0, %%o0, %%o0\n" \ 37 "1:\n" 38 39 #endif /* __arch64__ */ 40 41 #define my_syscall0(num) \ 42 ({ \ 43 register long _num __asm__ ("g1") = (num); \ 44 register long _arg1 __asm__ ("o0"); \ 45 \ 46 __asm__ volatile ( \ 47 _NOLIBC_SYSCALL \ 48 : "+r"(_arg1) \ 49 : "r"(_num) \ 50 : "memory", "cc" \ 51 ); \ 52 _arg1; \ 53 }) 54 55 #define my_syscall1(num, arg1) \ 56 ({ \ 57 register long _num __asm__ ("g1") = (num); \ 58 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 59 \ 60 __asm__ volatile ( \ 61 _NOLIBC_SYSCALL \ 62 : "+r"(_arg1) \ 63 : "r"(_num) \ 64 : "memory", "cc" \ 65 ); \ 66 _arg1; \ 67 }) 68 69 #define my_syscall2(num, arg1, arg2) \ 70 ({ \ 71 register long _num __asm__ ("g1") = (num); \ 72 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 73 register long _arg2 __asm__ ("o1") = (long)(arg2); \ 74 \ 75 __asm__ volatile ( \ 76 _NOLIBC_SYSCALL \ 77 : "+r"(_arg1) \ 78 : "r"(_arg2), "r"(_num) \ 79 : "memory", "cc" \ 80 ); \ 81 _arg1; \ 82 }) 83 84 #define my_syscall3(num, arg1, arg2, arg3) \ 85 ({ \ 86 register long _num __asm__ ("g1") = (num); \ 87 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 88 register long _arg2 __asm__ ("o1") = (long)(arg2); \ 89 register long _arg3 __asm__ ("o2") = (long)(arg3); \ 90 \ 91 __asm__ volatile ( \ 92 _NOLIBC_SYSCALL \ 93 : "+r"(_arg1) \ 94 : "r"(_arg2), "r"(_arg3), "r"(_num) \ 95 : "memory", "cc" \ 96 ); \ 97 _arg1; \ 98 }) 99 100 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 101 ({ \ 102 register long _num __asm__ ("g1") = (num); \ 103 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 104 register long _arg2 __asm__ ("o1") = (long)(arg2); \ 105 register long _arg3 __asm__ ("o2") = (long)(arg3); \ 106 register long _arg4 __asm__ ("o3") = (long)(arg4); \ 107 \ 108 __asm__ volatile ( \ 109 _NOLIBC_SYSCALL \ 110 : "+r"(_arg1) \ 111 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num) \ 112 : "memory", "cc" \ 113 ); \ 114 _arg1; \ 115 }) 116 117 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 118 ({ \ 119 register long _num __asm__ ("g1") = (num); \ 120 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 121 register long _arg2 __asm__ ("o1") = (long)(arg2); \ 122 register long _arg3 __asm__ ("o2") = (long)(arg3); \ 123 register long _arg4 __asm__ ("o3") = (long)(arg4); \ 124 register long _arg5 __asm__ ("o4") = (long)(arg5); \ 125 \ 126 __asm__ volatile ( \ 127 _NOLIBC_SYSCALL \ 128 : "+r"(_arg1) \ 129 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num) \ 130 : "memory", "cc" \ 131 ); \ 132 _arg1; \ 133 }) 134 135 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 136 ({ \ 137 register long _num __asm__ ("g1") = (num); \ 138 register long _arg1 __asm__ ("o0") = (long)(arg1); \ 139 register long _arg2 __asm__ ("o1") = (long)(arg2); \ 140 register long _arg3 __asm__ ("o2") = (long)(arg3); \ 141 register long _arg4 __asm__ ("o3") = (long)(arg4); \ 142 register long _arg5 __asm__ ("o4") = (long)(arg5); \ 143 register long _arg6 __asm__ ("o5") = (long)(arg6); \ 144 \ 145 __asm__ volatile ( \ 146 _NOLIBC_SYSCALL \ 147 : "+r"(_arg1) \ 148 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 149 "r"(_num) \ 150 : "memory", "cc" \ 151 ); \ 152 _arg1; \ 153 }) 154 155 /* startup code */ 156 void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 157 { 158 __asm__ volatile ( 159 /* 160 * Save argc pointer to o0, as arg1 of _start_c. 161 * Account for the window save area, which is 16 registers wide. 162 */ 163 #ifdef __arch64__ 164 "add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */ 165 #else 166 "add %sp, 64, %o0\n" 167 #endif 168 "b,a _start_c\n" /* transfer to c runtime */ 169 ); 170 __nolibc_entrypoint_epilogue(); 171 } 172 173 static pid_t getpid(void); 174 175 static __attribute__((unused)) 176 pid_t sys_fork(void) 177 { 178 pid_t parent, ret; 179 180 parent = getpid(); 181 ret = my_syscall0(__NR_fork); 182 183 /* The syscall returns the parent pid in the child instead of 0 */ 184 if (ret == parent) 185 return 0; 186 else 187 return ret; 188 } 189 #define sys_fork sys_fork 190 191 static __attribute__((unused)) 192 pid_t sys_vfork(void) 193 { 194 pid_t parent, ret; 195 196 parent = getpid(); 197 ret = my_syscall0(__NR_vfork); 198 199 /* The syscall returns the parent pid in the child instead of 0 */ 200 if (ret == parent) 201 return 0; 202 else 203 return ret; 204 } 205 #define sys_vfork sys_vfork 206 207 #endif /* _NOLIBC_ARCH_SPARC_H */ 208