1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved. 4 * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved. 5 * Author: Liu Bo <liubo2009@cn.fujitsu.com> 6 * Author: Ngie Cooper <yaneurabeya@gmail.com> 7 */ 8 9#ifndef LAPI_RT_SIGACTION_H__ 10#define LAPI_RT_SIGACTION_H__ 11 12#include "ltp_signal.h" 13 14#define INVAL_SA_PTR ((void *)-1) 15 16#if defined(__mips__) 17struct kernel_sigaction { 18 unsigned int sa_flags; 19 void (* k_sa_handler)(int); 20 sigset_t sa_mask; 21}; 22#else 23struct kernel_sigaction { 24 void (* k_sa_handler)(int); 25 unsigned long sa_flags; 26 void (*sa_restorer) (void); 27 sigset_t sa_mask; 28}; 29#endif 30 31/* This macro marks if (struct sigaction) has .sa_restorer member */ 32#if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__) 33# define HAVE_SA_RESTORER 34#endif 35 36#ifdef __x86_64__ 37 38/* 39 * From asm/signal.h -- this value isn't exported anywhere outside of glibc and 40 * asm/signal.h and is only required for the rt_sig* function family because 41 * sigaction(2), et all, appends this if necessary to 42 * (struct sigaction).sa_flags. HEH. 43 * 44 * I do #undef though, just in case... 45 * 46 * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or 47 * other): 48 * 49 * x86-64 should always use SA_RESTORER. 50 * 51 * -- thus SA_RESTORER must always be defined along with 52 * (struct sigaction).sa_restorer for this architecture. 53 */ 54#undef SA_RESTORER 55#define SA_RESTORER 0x04000000 56 57void (*restore_rt)(void); 58 59static void handler_h(int signal) 60{ 61 return; 62} 63 64/* Setup an initial signal handler for signal number = sig for x86_64. */ 65static inline int sig_initial(int sig) 66{ 67 int ret_code = -1; 68 struct sigaction act, oact; 69 70 act.sa_handler = handler_h; 71 act.sa_flags = 0; 72 /* Clear out the signal set. */ 73 if (sigemptyset(&act.sa_mask) < 0) { 74 /* Add the signal to the mask set. */ 75 } else if (sigaddset(&act.sa_mask, sig) < 0) { 76 /* Set act.sa_restorer via syscall(2) */ 77 } else if (sigaction(sig, &act, &oact) < 0) { 78 /* Copy oact.sa_restorer via syscall(2) */ 79 } else if (sigaction(sig, &act, &oact) < 0) { 80 /* And voila -- we just tricked the kernel into giving us our 81 * restorer function! */ 82 } else { 83 restore_rt = oact.sa_restorer; 84 ret_code = 0; 85 } 86 87 return ret_code; 88} 89 90#endif /* __x86_64__ */ 91 92#ifdef __sparc__ 93# if defined __arch64__ || defined __sparcv9 94 95/* 96 * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c 97 */ 98 99extern char *__rt_sig_stub; 100 101static void __attribute__((used)) __rt_sigreturn_stub(void) 102{ 103 __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" 104 "ta 0x6d\n\t" 105 : /* no outputs */ 106 : "i" (__NR_rt_sigreturn)); 107} 108 109# else /* sparc32 */ 110 111/* 112 * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c 113 */ 114 115extern char *__rt_sig_stub, *__sig_stub; 116 117static void __attribute__((used)) __rt_sigreturn_stub(void) 118{ 119 __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" 120 "ta 0x10\n\t" 121 : /* no outputs */ 122 : "i" (__NR_rt_sigreturn)); 123} 124 125static void __attribute__((used)) __sigreturn_stub(void) 126{ 127 __asm__ ("__sig_stub: mov %0, %%g1\n\t" 128 "ta 0x10\n\t" 129 : /* no outputs */ 130 : "i" (__NR_sigreturn)); 131} 132 133# endif 134#endif /* __sparc__ */ 135 136#ifdef __arc__ 137 138#undef SA_RESTORER 139#define SA_RESTORER 0x04000000 140 141/* 142 * based on uClibc/libc/sysdeps/linux/arc/sigaction.c 143 */ 144static void 145__attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void) 146{ 147 __asm__ ( 148 "mov r8, %0 \n\t" 149#ifdef __ARCHS__ 150 "trap_s 0 \n\t" 151#else 152 "trap0 \n\t" 153#endif 154 : /* no outputs */ 155 : "i" (__NR_rt_sigreturn) 156 : "r8"); 157} 158#endif 159 160/* This is a wrapper for __NR_rt_sigaction syscall. 161 * act/oact values of INVAL_SA_PTR is used to pass 162 * an invalid pointer to syscall(__NR_rt_sigaction) 163 * 164 * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c 165 */ 166 167static int ltp_rt_sigaction(int signum, const struct sigaction *act, 168 struct sigaction *oact, size_t sigsetsize) 169{ 170 int ret; 171 struct kernel_sigaction kact, koact; 172 struct kernel_sigaction *kact_p = NULL; 173 struct kernel_sigaction *koact_p = NULL; 174 175 if (act == INVAL_SA_PTR) { 176 kact_p = INVAL_SA_PTR; 177 } else if (act) { 178 kact.k_sa_handler = act->sa_handler; 179 memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t)); 180 kact.sa_flags = act->sa_flags; 181#ifndef __mips__ 182 kact.sa_restorer = NULL; 183#endif 184 kact_p = &kact; 185 } 186 187 if (oact == INVAL_SA_PTR) 188 koact_p = INVAL_SA_PTR; 189 else if (oact) 190 koact_p = &koact; 191 192#ifdef __x86_64__ 193 sig_initial(signum); 194#endif 195 196#if defined __x86_64__ || defined __arc__ 197 kact.sa_flags |= SA_RESTORER; 198 kact.sa_restorer = restore_rt; 199#endif 200 201#ifdef __sparc__ 202 unsigned long stub = 0; 203# if defined __arch64__ || defined __sparcv9 204 stub = ((unsigned long) &__rt_sig_stub) - 8; 205# else /* sparc32 */ 206 if ((kact.sa_flags & SA_SIGINFO) != 0) 207 stub = ((unsigned long) &__rt_sig_stub) - 8; 208 else 209 stub = ((unsigned long) &__sig_stub) - 8; 210# endif 211#endif 212 213 214#ifdef __sparc__ 215 ret = tst_syscall(__NR_rt_sigaction, signum, 216 kact_p, koact_p, 217 stub, sigsetsize); 218#else 219 ret = tst_syscall(__NR_rt_sigaction, signum, 220 kact_p, koact_p, 221 sigsetsize); 222#endif 223 224 if (ret >= 0) { 225 if (oact && (oact != INVAL_SA_PTR)) { 226 oact->sa_handler = koact.k_sa_handler; 227 memcpy(&oact->sa_mask, &koact.sa_mask, 228 sizeof(sigset_t)); 229 oact->sa_flags = koact.sa_flags; 230#ifdef HAVE_SA_RESTORER 231 oact->sa_restorer = koact.sa_restorer; 232#endif 233 } 234 } 235 236 return ret; 237} 238 239#endif /* LAPI_RT_SIGACTION_H__ */ 240