1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * Alpha specific definitions for NOLIBC 4 * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> 5 */ 6 7 #ifndef _NOLIBC_ARCH_ALPHA_H 8 #define _NOLIBC_ARCH_ALPHA_H 9 10 #include "compiler.h" 11 #include "crt.h" 12 13 /* 14 * Syscalls for Alpha: 15 * - registers are 64-bit 16 * - syscall number is passed in $0/v0 17 * - the system call is performed by calling callsys 18 * - syscall return comes in $0/v0, error flag in $19/a3 19 * - arguments are passed in $16/a0 to $21/a5 20 * - GCC does not support symbol register names 21 */ 22 23 #define _NOLIBC_SYSCALL_CLOBBERLIST \ 24 "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", \ 25 "$22", "$23", "$24", "$25", "$27", "$28", "memory", "cc" 26 27 #define __nolibc_syscall0(num) \ 28 ({ \ 29 register long _num __asm__ ("$0") = (num); \ 30 register long _err __asm__ ("$19"); \ 31 \ 32 __asm__ volatile ( \ 33 "callsys" \ 34 : "+r"(_num), "=r"(_err) \ 35 : \ 36 : _NOLIBC_SYSCALL_CLOBBERLIST, \ 37 "$16", "$17", "$18", "$20", "$21" \ 38 ); \ 39 _err ? -_num : _num; \ 40 }) 41 42 #define __nolibc_syscall1(num, arg1) \ 43 ({ \ 44 register long _num __asm__ ("$0") = (num); \ 45 register long _err __asm__ ("$19"); \ 46 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 47 \ 48 __asm__ volatile ( \ 49 "callsys" \ 50 : "+r"(_num), "=r"(_err) \ 51 : "r"(_arg1) \ 52 : _NOLIBC_SYSCALL_CLOBBERLIST, "$17", "$18", "$20", "$21" \ 53 ); \ 54 _err ? -_num : _num; \ 55 }) 56 57 #define __nolibc_syscall2(num, arg1, arg2) \ 58 ({ \ 59 register long _num __asm__ ("$0") = (num); \ 60 register long _err __asm__ ("$19"); \ 61 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 62 register long _arg2 __asm__ ("$17") = (long)(arg2); \ 63 \ 64 __asm__ volatile ( \ 65 "callsys" \ 66 : "+r"(_num), "=r"(_err) \ 67 : "r"(_arg1), "r"(_arg2) \ 68 : _NOLIBC_SYSCALL_CLOBBERLIST, "$18", "$20", "$21" \ 69 ); \ 70 _err ? -_num : _num; \ 71 }) 72 73 #define __nolibc_syscall3(num, arg1, arg2, arg3) \ 74 ({ \ 75 register long _num __asm__ ("$0") = (num); \ 76 register long _err __asm__ ("$19"); \ 77 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 78 register long _arg2 __asm__ ("$17") = (long)(arg2); \ 79 register long _arg3 __asm__ ("$18") = (long)(arg3); \ 80 \ 81 __asm__ volatile ( \ 82 "callsys" \ 83 : "+r"(_num), "=r"(_err) \ 84 : "r"(_arg1), "r"(_arg2), "r"(_arg3) \ 85 : _NOLIBC_SYSCALL_CLOBBERLIST, "$20", "$21" \ 86 ); \ 87 _err ? -_num : _num; \ 88 }) 89 90 #define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ 91 ({ \ 92 register long _num __asm__ ("$0") = (num); \ 93 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 94 register long _arg2 __asm__ ("$17") = (long)(arg2); \ 95 register long _arg3 __asm__ ("$18") = (long)(arg3); \ 96 register long _arg4 __asm__ ("$19") = (long)(arg4); \ 97 \ 98 __asm__ volatile ( \ 99 "callsys" \ 100 : "+r"(_num), "+r"(_arg4) \ 101 : "r"(_arg1), "r"(_arg2), "r"(_arg3) \ 102 : _NOLIBC_SYSCALL_CLOBBERLIST, "$20", "$21" \ 103 ); \ 104 _arg4 ? -_num : _num; \ 105 }) 106 107 #define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 108 ({ \ 109 register long _num __asm__ ("$0") = (num); \ 110 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 111 register long _arg2 __asm__ ("$17") = (long)(arg2); \ 112 register long _arg3 __asm__ ("$18") = (long)(arg3); \ 113 register long _arg4 __asm__ ("$19") = (long)(arg4); \ 114 register long _arg5 __asm__ ("$20") = (long)(arg5); \ 115 \ 116 __asm__ volatile ( \ 117 "callsys" \ 118 : "+r"(_num), "+r"(_arg4) \ 119 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg5) \ 120 : _NOLIBC_SYSCALL_CLOBBERLIST, "$21" \ 121 ); \ 122 _arg4 ? -_num : _num; \ 123 }) 124 125 #define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 126 ({ \ 127 register long _num __asm__ ("$0") = (num); \ 128 register long _arg1 __asm__ ("$16") = (long)(arg1); \ 129 register long _arg2 __asm__ ("$17") = (long)(arg2); \ 130 register long _arg3 __asm__ ("$18") = (long)(arg3); \ 131 register long _arg4 __asm__ ("$19") = (long)(arg4); \ 132 register long _arg5 __asm__ ("$20") = (long)(arg5); \ 133 register long _arg6 __asm__ ("$21") = (long)(arg6); \ 134 \ 135 __asm__ volatile ( \ 136 "callsys" \ 137 : "+r"(_num), "+r"(_arg4) \ 138 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg5), \ 139 "r"(_arg6) \ 140 : _NOLIBC_SYSCALL_CLOBBERLIST \ 141 ); \ 142 _arg4 ? -_num : _num; \ 143 }) 144 145 /* startup code */ 146 void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector 147 _start(void) 148 { 149 __asm__ volatile ( 150 "br $gp, 0f\n" /* setup $gp, so that 'lda' works */ 151 "0: ldgp $gp, 0($gp)\n" 152 "lda $27, _start_c\n" /* setup current function address for _start_c */ 153 "mov $sp, $16\n" /* save argc pointer to $16, as arg1 of _start_c */ 154 "br _start_c\n" /* transfer to c runtime */ 155 ); 156 __nolibc_entrypoint_epilogue(); 157 } 158 159 #endif /* _NOLIBC_ARCH_ALPHA_H */ 160