18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2003 PathScale, Inc. 38c2ecf20Sopenharmony_ci * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 48c2ecf20Sopenharmony_ci * Licensed under the GPL 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/personality.h> 98c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <asm/unistd.h> 128c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 138c2ecf20Sopenharmony_ci#include <asm/ucontext.h> 148c2ecf20Sopenharmony_ci#include <frame_kern.h> 158c2ecf20Sopenharmony_ci#include <skas.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * FPU tag word conversions. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic inline unsigned short twd_i387_to_fxsr(unsigned short twd) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci unsigned int tmp; /* to avoid 16 bit prefixes in the code */ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* Transform each pair of bits into 01 (valid) or 00 (empty) */ 288c2ecf20Sopenharmony_ci tmp = ~twd; 298c2ecf20Sopenharmony_ci tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ 308c2ecf20Sopenharmony_ci /* and move the valid bits to the lower byte. */ 318c2ecf20Sopenharmony_ci tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 328c2ecf20Sopenharmony_ci tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 338c2ecf20Sopenharmony_ci tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 348c2ecf20Sopenharmony_ci return tmp; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct _fpxreg *st = NULL; 408c2ecf20Sopenharmony_ci unsigned long twd = (unsigned long) fxsave->twd; 418c2ecf20Sopenharmony_ci unsigned long tag; 428c2ecf20Sopenharmony_ci unsigned long ret = 0xffff0000; 438c2ecf20Sopenharmony_ci int i; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 488c2ecf20Sopenharmony_ci if (twd & 0x1) { 498c2ecf20Sopenharmony_ci st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci switch (st->exponent & 0x7fff) { 528c2ecf20Sopenharmony_ci case 0x7fff: 538c2ecf20Sopenharmony_ci tag = 2; /* Special */ 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci case 0x0000: 568c2ecf20Sopenharmony_ci if ( !st->significand[0] && 578c2ecf20Sopenharmony_ci !st->significand[1] && 588c2ecf20Sopenharmony_ci !st->significand[2] && 598c2ecf20Sopenharmony_ci !st->significand[3] ) { 608c2ecf20Sopenharmony_ci tag = 1; /* Zero */ 618c2ecf20Sopenharmony_ci } else { 628c2ecf20Sopenharmony_ci tag = 2; /* Special */ 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci default: 668c2ecf20Sopenharmony_ci if (st->significand[3] & 0x8000) { 678c2ecf20Sopenharmony_ci tag = 0; /* Valid */ 688c2ecf20Sopenharmony_ci } else { 698c2ecf20Sopenharmony_ci tag = 2; /* Special */ 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci tag = 3; /* Empty */ 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci ret |= (tag << (2 * i)); 778c2ecf20Sopenharmony_ci twd = twd >> 1; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int convert_fxsr_to_user(struct _fpstate __user *buf, 838c2ecf20Sopenharmony_ci struct user_fxsr_struct *fxsave) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci unsigned long env[7]; 868c2ecf20Sopenharmony_ci struct _fpreg __user *to; 878c2ecf20Sopenharmony_ci struct _fpxreg *from; 888c2ecf20Sopenharmony_ci int i; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; 918c2ecf20Sopenharmony_ci env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; 928c2ecf20Sopenharmony_ci env[2] = twd_fxsr_to_i387(fxsave); 938c2ecf20Sopenharmony_ci env[3] = fxsave->fip; 948c2ecf20Sopenharmony_ci env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); 958c2ecf20Sopenharmony_ci env[5] = fxsave->foo; 968c2ecf20Sopenharmony_ci env[6] = fxsave->fos; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (__copy_to_user(buf, env, 7 * sizeof(unsigned long))) 998c2ecf20Sopenharmony_ci return 1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci to = &buf->_st[0]; 1028c2ecf20Sopenharmony_ci from = (struct _fpxreg *) &fxsave->st_space[0]; 1038c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, to++, from++) { 1048c2ecf20Sopenharmony_ci unsigned long __user *t = (unsigned long __user *)to; 1058c2ecf20Sopenharmony_ci unsigned long *f = (unsigned long *)from; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (__put_user(*f, t) || 1088c2ecf20Sopenharmony_ci __put_user(*(f + 1), t + 1) || 1098c2ecf20Sopenharmony_ci __put_user(from->exponent, &to->exponent)) 1108c2ecf20Sopenharmony_ci return 1; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, 1168c2ecf20Sopenharmony_ci struct _fpstate __user *buf) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci unsigned long env[7]; 1198c2ecf20Sopenharmony_ci struct _fpxreg *to; 1208c2ecf20Sopenharmony_ci struct _fpreg __user *from; 1218c2ecf20Sopenharmony_ci int i; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (copy_from_user( env, buf, 7 * sizeof(long))) 1248c2ecf20Sopenharmony_ci return 1; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci fxsave->cwd = (unsigned short)(env[0] & 0xffff); 1278c2ecf20Sopenharmony_ci fxsave->swd = (unsigned short)(env[1] & 0xffff); 1288c2ecf20Sopenharmony_ci fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); 1298c2ecf20Sopenharmony_ci fxsave->fip = env[3]; 1308c2ecf20Sopenharmony_ci fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); 1318c2ecf20Sopenharmony_ci fxsave->fcs = (env[4] & 0xffff); 1328c2ecf20Sopenharmony_ci fxsave->foo = env[5]; 1338c2ecf20Sopenharmony_ci fxsave->fos = env[6]; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci to = (struct _fpxreg *) &fxsave->st_space[0]; 1368c2ecf20Sopenharmony_ci from = &buf->_st[0]; 1378c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, to++, from++) { 1388c2ecf20Sopenharmony_ci unsigned long *t = (unsigned long *)to; 1398c2ecf20Sopenharmony_ci unsigned long __user *f = (unsigned long __user *)from; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (__get_user(*t, f) || 1428c2ecf20Sopenharmony_ci __get_user(*(t + 1), f + 1) || 1438c2ecf20Sopenharmony_ci __get_user(to->exponent, &from->exponent)) 1448c2ecf20Sopenharmony_ci return 1; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciextern int have_fpx_regs; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#endif 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int copy_sc_from_user(struct pt_regs *regs, 1548c2ecf20Sopenharmony_ci struct sigcontext __user *from) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct sigcontext sc; 1578c2ecf20Sopenharmony_ci int err, pid; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Always make any pending restarted system calls return -EINTR */ 1608c2ecf20Sopenharmony_ci current->restart_block.fn = do_no_restart_syscall; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci err = copy_from_user(&sc, from, sizeof(sc)); 1638c2ecf20Sopenharmony_ci if (err) 1648c2ecf20Sopenharmony_ci return err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 1698c2ecf20Sopenharmony_ci GETREG(GS, gs); 1708c2ecf20Sopenharmony_ci GETREG(FS, fs); 1718c2ecf20Sopenharmony_ci GETREG(ES, es); 1728c2ecf20Sopenharmony_ci GETREG(DS, ds); 1738c2ecf20Sopenharmony_ci#endif 1748c2ecf20Sopenharmony_ci GETREG(DI, di); 1758c2ecf20Sopenharmony_ci GETREG(SI, si); 1768c2ecf20Sopenharmony_ci GETREG(BP, bp); 1778c2ecf20Sopenharmony_ci GETREG(SP, sp); 1788c2ecf20Sopenharmony_ci GETREG(BX, bx); 1798c2ecf20Sopenharmony_ci GETREG(DX, dx); 1808c2ecf20Sopenharmony_ci GETREG(CX, cx); 1818c2ecf20Sopenharmony_ci GETREG(AX, ax); 1828c2ecf20Sopenharmony_ci GETREG(IP, ip); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 1858c2ecf20Sopenharmony_ci GETREG(R8, r8); 1868c2ecf20Sopenharmony_ci GETREG(R9, r9); 1878c2ecf20Sopenharmony_ci GETREG(R10, r10); 1888c2ecf20Sopenharmony_ci GETREG(R11, r11); 1898c2ecf20Sopenharmony_ci GETREG(R12, r12); 1908c2ecf20Sopenharmony_ci GETREG(R13, r13); 1918c2ecf20Sopenharmony_ci GETREG(R14, r14); 1928c2ecf20Sopenharmony_ci GETREG(R15, r15); 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci GETREG(CS, cs); 1968c2ecf20Sopenharmony_ci GETREG(EFLAGS, flags); 1978c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 1988c2ecf20Sopenharmony_ci GETREG(SS, ss); 1998c2ecf20Sopenharmony_ci#endif 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#undef GETREG 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci pid = userspace_pid[current_thread_info()->cpu]; 2048c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 2058c2ecf20Sopenharmony_ci if (have_fpx_regs) { 2068c2ecf20Sopenharmony_ci struct user_fxsr_struct fpx; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci err = copy_from_user(&fpx, 2098c2ecf20Sopenharmony_ci &((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0], 2108c2ecf20Sopenharmony_ci sizeof(struct user_fxsr_struct)); 2118c2ecf20Sopenharmony_ci if (err) 2128c2ecf20Sopenharmony_ci return 1; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci err = convert_fxsr_from_user(&fpx, (void *)sc.fpstate); 2158c2ecf20Sopenharmony_ci if (err) 2168c2ecf20Sopenharmony_ci return 1; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci err = restore_fpx_registers(pid, (unsigned long *) &fpx); 2198c2ecf20Sopenharmony_ci if (err < 0) { 2208c2ecf20Sopenharmony_ci printk(KERN_ERR "copy_sc_from_user - " 2218c2ecf20Sopenharmony_ci "restore_fpx_registers failed, errno = %d\n", 2228c2ecf20Sopenharmony_ci -err); 2238c2ecf20Sopenharmony_ci return 1; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } else 2268c2ecf20Sopenharmony_ci#endif 2278c2ecf20Sopenharmony_ci { 2288c2ecf20Sopenharmony_ci err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, 2298c2ecf20Sopenharmony_ci sizeof(struct _xstate)); 2308c2ecf20Sopenharmony_ci if (err) 2318c2ecf20Sopenharmony_ci return 1; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int copy_sc_to_user(struct sigcontext __user *to, 2378c2ecf20Sopenharmony_ci struct _xstate __user *to_fp, struct pt_regs *regs, 2388c2ecf20Sopenharmony_ci unsigned long mask) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct sigcontext sc; 2418c2ecf20Sopenharmony_ci struct faultinfo * fi = ¤t->thread.arch.faultinfo; 2428c2ecf20Sopenharmony_ci int err, pid; 2438c2ecf20Sopenharmony_ci memset(&sc, 0, sizeof(struct sigcontext)); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno] 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 2488c2ecf20Sopenharmony_ci PUTREG(GS, gs); 2498c2ecf20Sopenharmony_ci PUTREG(FS, fs); 2508c2ecf20Sopenharmony_ci PUTREG(ES, es); 2518c2ecf20Sopenharmony_ci PUTREG(DS, ds); 2528c2ecf20Sopenharmony_ci#endif 2538c2ecf20Sopenharmony_ci PUTREG(DI, di); 2548c2ecf20Sopenharmony_ci PUTREG(SI, si); 2558c2ecf20Sopenharmony_ci PUTREG(BP, bp); 2568c2ecf20Sopenharmony_ci PUTREG(SP, sp); 2578c2ecf20Sopenharmony_ci PUTREG(BX, bx); 2588c2ecf20Sopenharmony_ci PUTREG(DX, dx); 2598c2ecf20Sopenharmony_ci PUTREG(CX, cx); 2608c2ecf20Sopenharmony_ci PUTREG(AX, ax); 2618c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 2628c2ecf20Sopenharmony_ci PUTREG(R8, r8); 2638c2ecf20Sopenharmony_ci PUTREG(R9, r9); 2648c2ecf20Sopenharmony_ci PUTREG(R10, r10); 2658c2ecf20Sopenharmony_ci PUTREG(R11, r11); 2668c2ecf20Sopenharmony_ci PUTREG(R12, r12); 2678c2ecf20Sopenharmony_ci PUTREG(R13, r13); 2688c2ecf20Sopenharmony_ci PUTREG(R14, r14); 2698c2ecf20Sopenharmony_ci PUTREG(R15, r15); 2708c2ecf20Sopenharmony_ci#endif 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci sc.cr2 = fi->cr2; 2738c2ecf20Sopenharmony_ci sc.err = fi->error_code; 2748c2ecf20Sopenharmony_ci sc.trapno = fi->trap_no; 2758c2ecf20Sopenharmony_ci PUTREG(IP, ip); 2768c2ecf20Sopenharmony_ci PUTREG(CS, cs); 2778c2ecf20Sopenharmony_ci PUTREG(EFLAGS, flags); 2788c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 2798c2ecf20Sopenharmony_ci PUTREG(SP, sp_at_signal); 2808c2ecf20Sopenharmony_ci PUTREG(SS, ss); 2818c2ecf20Sopenharmony_ci#endif 2828c2ecf20Sopenharmony_ci#undef PUTREG 2838c2ecf20Sopenharmony_ci sc.oldmask = mask; 2848c2ecf20Sopenharmony_ci sc.fpstate = (unsigned long)to_fp; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = copy_to_user(to, &sc, sizeof(struct sigcontext)); 2878c2ecf20Sopenharmony_ci if (err) 2888c2ecf20Sopenharmony_ci return 1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci pid = userspace_pid[current_thread_info()->cpu]; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 2938c2ecf20Sopenharmony_ci if (have_fpx_regs) { 2948c2ecf20Sopenharmony_ci struct user_fxsr_struct fpx; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci err = save_fpx_registers(pid, (unsigned long *) &fpx); 2978c2ecf20Sopenharmony_ci if (err < 0){ 2988c2ecf20Sopenharmony_ci printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " 2998c2ecf20Sopenharmony_ci "failed, errno = %d\n", err); 3008c2ecf20Sopenharmony_ci return 1; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err = convert_fxsr_to_user(&to_fp->fpstate, &fpx); 3048c2ecf20Sopenharmony_ci if (err) 3058c2ecf20Sopenharmony_ci return 1; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci err |= __put_user(fpx.swd, &to_fp->fpstate.status); 3088c2ecf20Sopenharmony_ci err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); 3098c2ecf20Sopenharmony_ci if (err) 3108c2ecf20Sopenharmony_ci return 1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (copy_to_user(&to_fp->fpstate._fxsr_env[0], &fpx, 3138c2ecf20Sopenharmony_ci sizeof(struct user_fxsr_struct))) 3148c2ecf20Sopenharmony_ci return 1; 3158c2ecf20Sopenharmony_ci } else 3168c2ecf20Sopenharmony_ci#endif 3178c2ecf20Sopenharmony_ci { 3188c2ecf20Sopenharmony_ci if (copy_to_user(to_fp, regs->regs.fp, sizeof(struct _xstate))) 3198c2ecf20Sopenharmony_ci return 1; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 3268c2ecf20Sopenharmony_cistatic int copy_ucontext_to_user(struct ucontext __user *uc, 3278c2ecf20Sopenharmony_ci struct _xstate __user *fp, sigset_t *set, 3288c2ecf20Sopenharmony_ci unsigned long sp) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int err = 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci err |= __save_altstack(&uc->uc_stack, sp); 3338c2ecf20Sopenharmony_ci err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, 0); 3348c2ecf20Sopenharmony_ci err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); 3358c2ecf20Sopenharmony_ci return err; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistruct sigframe 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci char __user *pretcode; 3418c2ecf20Sopenharmony_ci int sig; 3428c2ecf20Sopenharmony_ci struct sigcontext sc; 3438c2ecf20Sopenharmony_ci struct _xstate fpstate; 3448c2ecf20Sopenharmony_ci unsigned long extramask[_NSIG_WORDS-1]; 3458c2ecf20Sopenharmony_ci char retcode[8]; 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistruct rt_sigframe 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci char __user *pretcode; 3518c2ecf20Sopenharmony_ci int sig; 3528c2ecf20Sopenharmony_ci struct siginfo __user *pinfo; 3538c2ecf20Sopenharmony_ci void __user *puc; 3548c2ecf20Sopenharmony_ci struct siginfo info; 3558c2ecf20Sopenharmony_ci struct ucontext uc; 3568c2ecf20Sopenharmony_ci struct _xstate fpstate; 3578c2ecf20Sopenharmony_ci char retcode[8]; 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciint setup_signal_stack_sc(unsigned long stack_top, struct ksignal *ksig, 3618c2ecf20Sopenharmony_ci struct pt_regs *regs, sigset_t *mask) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct sigframe __user *frame; 3648c2ecf20Sopenharmony_ci void __user *restorer; 3658c2ecf20Sopenharmony_ci int err = 0, sig = ksig->sig; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */ 3688c2ecf20Sopenharmony_ci stack_top = ((stack_top + 4) & -16UL) - 4; 3698c2ecf20Sopenharmony_ci frame = (struct sigframe __user *) stack_top - 1; 3708c2ecf20Sopenharmony_ci if (!access_ok(frame, sizeof(*frame))) 3718c2ecf20Sopenharmony_ci return 1; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci restorer = frame->retcode; 3748c2ecf20Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_RESTORER) 3758c2ecf20Sopenharmony_ci restorer = ksig->ka.sa.sa_restorer; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci err |= __put_user(restorer, &frame->pretcode); 3788c2ecf20Sopenharmony_ci err |= __put_user(sig, &frame->sig); 3798c2ecf20Sopenharmony_ci err |= copy_sc_to_user(&frame->sc, &frame->fpstate, regs, mask->sig[0]); 3808c2ecf20Sopenharmony_ci if (_NSIG_WORDS > 1) 3818c2ecf20Sopenharmony_ci err |= __copy_to_user(&frame->extramask, &mask->sig[1], 3828c2ecf20Sopenharmony_ci sizeof(frame->extramask)); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* 3858c2ecf20Sopenharmony_ci * This is popl %eax ; movl $,%eax ; int $0x80 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * WE DO NOT USE IT ANY MORE! It's only left here for historical 3888c2ecf20Sopenharmony_ci * reasons and because gdb uses it as a signature to notice 3898c2ecf20Sopenharmony_ci * signal handler stack frames. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); 3928c2ecf20Sopenharmony_ci err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); 3938c2ecf20Sopenharmony_ci err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (err) 3968c2ecf20Sopenharmony_ci return err; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci PT_REGS_SP(regs) = (unsigned long) frame; 3998c2ecf20Sopenharmony_ci PT_REGS_IP(regs) = (unsigned long) ksig->ka.sa.sa_handler; 4008c2ecf20Sopenharmony_ci PT_REGS_AX(regs) = (unsigned long) sig; 4018c2ecf20Sopenharmony_ci PT_REGS_DX(regs) = (unsigned long) 0; 4028c2ecf20Sopenharmony_ci PT_REGS_CX(regs) = (unsigned long) 0; 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciint setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, 4078c2ecf20Sopenharmony_ci struct pt_regs *regs, sigset_t *mask) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct rt_sigframe __user *frame; 4108c2ecf20Sopenharmony_ci void __user *restorer; 4118c2ecf20Sopenharmony_ci int err = 0, sig = ksig->sig; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci stack_top &= -8UL; 4148c2ecf20Sopenharmony_ci frame = (struct rt_sigframe __user *) stack_top - 1; 4158c2ecf20Sopenharmony_ci if (!access_ok(frame, sizeof(*frame))) 4168c2ecf20Sopenharmony_ci return 1; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci restorer = frame->retcode; 4198c2ecf20Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_RESTORER) 4208c2ecf20Sopenharmony_ci restorer = ksig->ka.sa.sa_restorer; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci err |= __put_user(restorer, &frame->pretcode); 4238c2ecf20Sopenharmony_ci err |= __put_user(sig, &frame->sig); 4248c2ecf20Sopenharmony_ci err |= __put_user(&frame->info, &frame->pinfo); 4258c2ecf20Sopenharmony_ci err |= __put_user(&frame->uc, &frame->puc); 4268c2ecf20Sopenharmony_ci err |= copy_siginfo_to_user(&frame->info, &ksig->info); 4278c2ecf20Sopenharmony_ci err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, 4288c2ecf20Sopenharmony_ci PT_REGS_SP(regs)); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* 4318c2ecf20Sopenharmony_ci * This is movl $,%eax ; int $0x80 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * WE DO NOT USE IT ANY MORE! It's only left here for historical 4348c2ecf20Sopenharmony_ci * reasons and because gdb uses it as a signature to notice 4358c2ecf20Sopenharmony_ci * signal handler stack frames. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); 4388c2ecf20Sopenharmony_ci err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); 4398c2ecf20Sopenharmony_ci err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (err) 4428c2ecf20Sopenharmony_ci return err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci PT_REGS_SP(regs) = (unsigned long) frame; 4458c2ecf20Sopenharmony_ci PT_REGS_IP(regs) = (unsigned long) ksig->ka.sa.sa_handler; 4468c2ecf20Sopenharmony_ci PT_REGS_AX(regs) = (unsigned long) sig; 4478c2ecf20Sopenharmony_ci PT_REGS_DX(regs) = (unsigned long) &frame->info; 4488c2ecf20Sopenharmony_ci PT_REGS_CX(regs) = (unsigned long) &frame->uc; 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cilong sys_sigreturn(void) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci unsigned long sp = PT_REGS_SP(¤t->thread.regs); 4558c2ecf20Sopenharmony_ci struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); 4568c2ecf20Sopenharmony_ci sigset_t set; 4578c2ecf20Sopenharmony_ci struct sigcontext __user *sc = &frame->sc; 4588c2ecf20Sopenharmony_ci int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (copy_from_user(&set.sig[0], &sc->oldmask, sizeof(set.sig[0])) || 4618c2ecf20Sopenharmony_ci copy_from_user(&set.sig[1], frame->extramask, sig_size)) 4628c2ecf20Sopenharmony_ci goto segfault; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci set_current_blocked(&set); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (copy_sc_from_user(¤t->thread.regs, sc)) 4678c2ecf20Sopenharmony_ci goto segfault; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Avoid ERESTART handling */ 4708c2ecf20Sopenharmony_ci PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; 4718c2ecf20Sopenharmony_ci return PT_REGS_SYSCALL_RET(¤t->thread.regs); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci segfault: 4748c2ecf20Sopenharmony_ci force_sig(SIGSEGV); 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#else 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistruct rt_sigframe 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci char __user *pretcode; 4838c2ecf20Sopenharmony_ci struct ucontext uc; 4848c2ecf20Sopenharmony_ci struct siginfo info; 4858c2ecf20Sopenharmony_ci struct _xstate fpstate; 4868c2ecf20Sopenharmony_ci}; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, 4898c2ecf20Sopenharmony_ci struct pt_regs *regs, sigset_t *set) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct rt_sigframe __user *frame; 4928c2ecf20Sopenharmony_ci int err = 0, sig = ksig->sig; 4938c2ecf20Sopenharmony_ci unsigned long fp_to; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci frame = (struct rt_sigframe __user *) 4968c2ecf20Sopenharmony_ci round_down(stack_top - sizeof(struct rt_sigframe), 16); 4978c2ecf20Sopenharmony_ci /* Subtract 128 for a red zone and 8 for proper alignment */ 4988c2ecf20Sopenharmony_ci frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!access_ok(frame, sizeof(*frame))) 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_SIGINFO) { 5048c2ecf20Sopenharmony_ci err |= copy_siginfo_to_user(&frame->info, &ksig->info); 5058c2ecf20Sopenharmony_ci if (err) 5068c2ecf20Sopenharmony_ci goto out; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* Create the ucontext. */ 5108c2ecf20Sopenharmony_ci err |= __put_user(0, &frame->uc.uc_flags); 5118c2ecf20Sopenharmony_ci err |= __put_user(0, &frame->uc.uc_link); 5128c2ecf20Sopenharmony_ci err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs)); 5138c2ecf20Sopenharmony_ci err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, 5148c2ecf20Sopenharmony_ci set->sig[0]); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci fp_to = (unsigned long)&frame->fpstate; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate); 5198c2ecf20Sopenharmony_ci if (sizeof(*set) == 16) { 5208c2ecf20Sopenharmony_ci err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); 5218c2ecf20Sopenharmony_ci err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci else 5248c2ecf20Sopenharmony_ci err |= __copy_to_user(&frame->uc.uc_sigmask, set, 5258c2ecf20Sopenharmony_ci sizeof(*set)); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * Set up to return from userspace. If provided, use a stub 5298c2ecf20Sopenharmony_ci * already in userspace. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci /* x86-64 should always use SA_RESTORER. */ 5328c2ecf20Sopenharmony_ci if (ksig->ka.sa.sa_flags & SA_RESTORER) 5338c2ecf20Sopenharmony_ci err |= __put_user((void *)ksig->ka.sa.sa_restorer, 5348c2ecf20Sopenharmony_ci &frame->pretcode); 5358c2ecf20Sopenharmony_ci else 5368c2ecf20Sopenharmony_ci /* could use a vstub here */ 5378c2ecf20Sopenharmony_ci return err; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (err) 5408c2ecf20Sopenharmony_ci return err; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci PT_REGS_SP(regs) = (unsigned long) frame; 5438c2ecf20Sopenharmony_ci PT_REGS_DI(regs) = sig; 5448c2ecf20Sopenharmony_ci /* In case the signal handler was declared without prototypes */ 5458c2ecf20Sopenharmony_ci PT_REGS_AX(regs) = 0; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* 5488c2ecf20Sopenharmony_ci * This also works for non SA_SIGINFO handlers because they expect the 5498c2ecf20Sopenharmony_ci * next argument after the signal number on the stack. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci PT_REGS_SI(regs) = (unsigned long) &frame->info; 5528c2ecf20Sopenharmony_ci PT_REGS_DX(regs) = (unsigned long) &frame->uc; 5538c2ecf20Sopenharmony_ci PT_REGS_IP(regs) = (unsigned long) ksig->ka.sa.sa_handler; 5548c2ecf20Sopenharmony_ci out: 5558c2ecf20Sopenharmony_ci return err; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci#endif 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cilong sys_rt_sigreturn(void) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci unsigned long sp = PT_REGS_SP(¤t->thread.regs); 5628c2ecf20Sopenharmony_ci struct rt_sigframe __user *frame = 5638c2ecf20Sopenharmony_ci (struct rt_sigframe __user *)(sp - sizeof(long)); 5648c2ecf20Sopenharmony_ci struct ucontext __user *uc = &frame->uc; 5658c2ecf20Sopenharmony_ci sigset_t set; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) 5688c2ecf20Sopenharmony_ci goto segfault; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci set_current_blocked(&set); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) 5738c2ecf20Sopenharmony_ci goto segfault; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* Avoid ERESTART handling */ 5768c2ecf20Sopenharmony_ci PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; 5778c2ecf20Sopenharmony_ci return PT_REGS_SYSCALL_RET(¤t->thread.regs); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci segfault: 5808c2ecf20Sopenharmony_ci force_sig(SIGSEGV); 5818c2ecf20Sopenharmony_ci return 0; 5828c2ecf20Sopenharmony_ci} 583