static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax) { unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define COPY(x) err |= __get_user(regs->x, &sc->x) COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx); COPY(rdx); COPY(rcx); COPY(rip); COPY(r8); COPY(r9); COPY(r10); COPY(r11); COPY(r12); COPY(r13); COPY(r14); COPY(r15); /* Kernel saves and restores only the CS segment register on signals, * which is the bare minimum needed to allow mixed 32/64-bit code. * App's signal handler can save/restore other segments if needed. */ { unsigned cs; err |= __get_user(cs, &sc->cs); regs->cs = cs | 3; /* Force into user mode */ } { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_rax = -1; /* disable syscall checks */ } { struct _fpstate __user * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); } else { struct task_struct *me = current; if (used_math()) { clear_fpu(me); clear_used_math(); } } } err |= __get_user(*prax, &sc->rax); return err; badframe: return 1; }
static int restore_fpu_state_from_user_stack( struct sigcontext __user * sc ) { struct _fpstate __user *fpstate; if (__get_user(fpstate, &sc->fpstate)) return -EFAULT; return restore_i387(fpstate); }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned long *prax) { unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define COPY(x) err |= __get_user(regs->x, &sc->x) COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx); COPY(rdx); COPY(rcx); COPY(rip); COPY(r8); COPY(r9); COPY(r10); COPY(r11); COPY(r12); COPY(r13); COPY(r14); COPY(r15); { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); regs->orig_rax = -1; /* disable syscall checks */ } { struct _fpstate __user * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); } else { struct task_struct *me = current; if (used_math()) { clear_fpu(me); clear_used_math(); } } } err |= __get_user(*prax, &sc->rax); return err; badframe: return 1; }
/* * This sets regs->esp even though we don't actually use sigstacks yet.. */ asmlinkage int sys_sigreturn(unsigned long __unused) { #define COPY(x) regs->x = context.x #ifdef CONFIG_OSFMACH3 #define COPY_SEG(x) #define COPY_SEG_STRICT(x) #else /* CONFIG_OSFMACH3 */ #define COPY_SEG(x) \ if ( (context.x & 0xfffc) /* not a NULL selectors */ \ && (context.x & 0x4) != 0x4 /* not a LDT selector */ \ && (context.x & 3) != 3 /* not a RPL3 GDT selector */ \ ) goto badframe; COPY(x); #define COPY_SEG_STRICT(x) \ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); #endif /* CONFIG_OSFMACH3 */ struct sigcontext_struct context; struct pt_regs * regs; regs = (struct pt_regs *) &__unused; if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context))) goto badframe; memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); current->blocked = context.oldmask & _BLOCKABLE; COPY_SEG(ds); COPY_SEG(es); COPY_SEG(fs); COPY_SEG(gs); COPY_SEG_STRICT(ss); COPY_SEG_STRICT(cs); COPY(eip); COPY(ecx); COPY(edx); COPY(ebx); COPY(esp); COPY(ebp); COPY(edi); COPY(esi); regs->eflags &= ~0x40DD5; regs->eflags |= context.eflags & 0x40DD5; regs->orig_eax = -1; /* disable syscall checks */ if (context.fpstate) { struct _fpstate * buf = context.fpstate; if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; restore_i387(buf); } return context.eax; badframe: do_exit(SIGSEGV); }
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax) { unsigned int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; #define COPY(x) err |= __get_user(regs->x, &sc->x) #define COPY_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ regs->x##seg = tmp|3; } #define GET_SEG(seg) \ { unsigned short tmp; \ err |= __get_user(tmp, &sc->seg); \ loadsegment(seg,tmp); } #define FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_RF | \ X86_EFLAGS_OF | X86_EFLAGS_DF | \ X86_EFLAGS_TF | X86_EFLAGS_SF | X86_EFLAGS_ZF | \ X86_EFLAGS_AF | X86_EFLAGS_PF | X86_EFLAGS_CF) GET_SEG(gs); COPY_SEG(fs); COPY_SEG(es); COPY_SEG(ds); COPY(edi); COPY(esi); COPY(ebp); COPY(esp); COPY(ebx); COPY(edx); COPY(ecx); COPY(eip); COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); regs->eflags = (regs->eflags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); regs->orig_eax = -1; /* disable syscall checks */ } { struct _fpstate __user * buf; err |= __get_user(buf, &sc->fpstate); if (buf) { if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) goto badframe; err |= restore_i387(buf); } else { struct task_struct *me = current; if (used_math()) { clear_fpu(me); clear_used_math(); } } } err |= __get_user(*peax, &sc->eax); return err; badframe: return 1; }