|
@@ -70,6 +70,142 @@ static const struct {
|
|
|
0
|
|
|
};
|
|
|
|
|
|
+#define COPY(x) { \
|
|
|
+ err |= __get_user(regs->x, &sc->x); \
|
|
|
+}
|
|
|
+
|
|
|
+#define COPY_SEG(seg) { \
|
|
|
+ unsigned short tmp; \
|
|
|
+ err |= __get_user(tmp, &sc->seg); \
|
|
|
+ regs->seg = tmp; \
|
|
|
+}
|
|
|
+
|
|
|
+#define COPY_SEG_CPL3(seg) { \
|
|
|
+ unsigned short tmp; \
|
|
|
+ err |= __get_user(tmp, &sc->seg); \
|
|
|
+ regs->seg = tmp | 3; \
|
|
|
+}
|
|
|
+
|
|
|
+#define GET_SEG(seg) { \
|
|
|
+ unsigned short tmp; \
|
|
|
+ err |= __get_user(tmp, &sc->seg); \
|
|
|
+ loadsegment(seg, tmp); \
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|
|
+ unsigned long *pax)
|
|
|
+{
|
|
|
+ void __user *buf;
|
|
|
+ unsigned int tmpflags;
|
|
|
+ unsigned int err = 0;
|
|
|
+
|
|
|
+ /* Always make any pending restarted system calls return -EINTR */
|
|
|
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ GET_SEG(gs);
|
|
|
+ COPY_SEG(fs);
|
|
|
+ COPY_SEG(es);
|
|
|
+ COPY_SEG(ds);
|
|
|
+#endif /* CONFIG_X86_32 */
|
|
|
+
|
|
|
+ COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
|
|
+ COPY(dx); COPY(cx); COPY(ip);
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ COPY(r8);
|
|
|
+ COPY(r9);
|
|
|
+ COPY(r10);
|
|
|
+ COPY(r11);
|
|
|
+ COPY(r12);
|
|
|
+ COPY(r13);
|
|
|
+ COPY(r14);
|
|
|
+ COPY(r15);
|
|
|
+#endif /* CONFIG_X86_64 */
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ COPY_SEG_CPL3(cs);
|
|
|
+ COPY_SEG_CPL3(ss);
|
|
|
+#else /* !CONFIG_X86_32 */
|
|
|
+ /* 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. */
|
|
|
+ COPY_SEG_CPL3(cs);
|
|
|
+#endif /* CONFIG_X86_32 */
|
|
|
+
|
|
|
+ err |= __get_user(tmpflags, &sc->flags);
|
|
|
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
|
|
+ regs->orig_ax = -1; /* disable syscall checks */
|
|
|
+
|
|
|
+ err |= __get_user(buf, &sc->fpstate);
|
|
|
+ err |= restore_i387_xstate(buf);
|
|
|
+
|
|
|
+ err |= __get_user(*pax, &sc->ax);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
|
|
+ struct pt_regs *regs, unsigned long mask)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ {
|
|
|
+ unsigned int tmp;
|
|
|
+
|
|
|
+ savesegment(gs, tmp);
|
|
|
+ err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
|
|
|
+ }
|
|
|
+ err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
|
|
|
+ err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
|
|
|
+ err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
|
|
|
+#endif /* CONFIG_X86_32 */
|
|
|
+
|
|
|
+ err |= __put_user(regs->di, &sc->di);
|
|
|
+ err |= __put_user(regs->si, &sc->si);
|
|
|
+ err |= __put_user(regs->bp, &sc->bp);
|
|
|
+ err |= __put_user(regs->sp, &sc->sp);
|
|
|
+ err |= __put_user(regs->bx, &sc->bx);
|
|
|
+ err |= __put_user(regs->dx, &sc->dx);
|
|
|
+ err |= __put_user(regs->cx, &sc->cx);
|
|
|
+ err |= __put_user(regs->ax, &sc->ax);
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ err |= __put_user(regs->r8, &sc->r8);
|
|
|
+ err |= __put_user(regs->r9, &sc->r9);
|
|
|
+ err |= __put_user(regs->r10, &sc->r10);
|
|
|
+ err |= __put_user(regs->r11, &sc->r11);
|
|
|
+ err |= __put_user(regs->r12, &sc->r12);
|
|
|
+ err |= __put_user(regs->r13, &sc->r13);
|
|
|
+ err |= __put_user(regs->r14, &sc->r14);
|
|
|
+ err |= __put_user(regs->r15, &sc->r15);
|
|
|
+#endif /* CONFIG_X86_64 */
|
|
|
+
|
|
|
+ err |= __put_user(current->thread.trap_no, &sc->trapno);
|
|
|
+ err |= __put_user(current->thread.error_code, &sc->err);
|
|
|
+ err |= __put_user(regs->ip, &sc->ip);
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
|
|
|
+ err |= __put_user(regs->flags, &sc->flags);
|
|
|
+ err |= __put_user(regs->sp, &sc->sp_at_signal);
|
|
|
+ err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
|
|
|
+#else /* !CONFIG_X86_32 */
|
|
|
+ err |= __put_user(regs->flags, &sc->flags);
|
|
|
+ err |= __put_user(regs->cs, &sc->cs);
|
|
|
+ err |= __put_user(0, &sc->gs);
|
|
|
+ err |= __put_user(0, &sc->fs);
|
|
|
+#endif /* CONFIG_X86_32 */
|
|
|
+
|
|
|
+ err |= __put_user(fpstate, &sc->fpstate);
|
|
|
+
|
|
|
+ /* non-iBCS2 extensions.. */
|
|
|
+ err |= __put_user(mask, &sc->oldmask);
|
|
|
+ err |= __put_user(current->thread.cr2, &sc->cr2);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Atomically swap in the new signal mask, and wait for a signal.
|
|
|
*/
|
|
@@ -147,84 +283,9 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
|
|
|
}
|
|
|
#endif /* CONFIG_X86_32 */
|
|
|
|
|
|
-#define COPY(x) { \
|
|
|
- err |= __get_user(regs->x, &sc->x); \
|
|
|
-}
|
|
|
-
|
|
|
-#define COPY_SEG(seg) { \
|
|
|
- unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
- regs->seg = tmp; \
|
|
|
-}
|
|
|
-
|
|
|
-#define COPY_SEG_CPL3(seg) { \
|
|
|
- unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
- regs->seg = tmp | 3; \
|
|
|
-}
|
|
|
-
|
|
|
-#define GET_SEG(seg) { \
|
|
|
- unsigned short tmp; \
|
|
|
- err |= __get_user(tmp, &sc->seg); \
|
|
|
- loadsegment(seg, tmp); \
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Do a signal return; undo the signal stack.
|
|
|
*/
|
|
|
-static int
|
|
|
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|
|
- unsigned long *pax)
|
|
|
-{
|
|
|
- void __user *buf;
|
|
|
- unsigned int tmpflags;
|
|
|
- unsigned int err = 0;
|
|
|
-
|
|
|
- /* Always make any pending restarted system calls return -EINTR */
|
|
|
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_32
|
|
|
- GET_SEG(gs);
|
|
|
- COPY_SEG(fs);
|
|
|
- COPY_SEG(es);
|
|
|
- COPY_SEG(ds);
|
|
|
-#endif /* CONFIG_X86_32 */
|
|
|
-
|
|
|
- COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
|
|
|
- COPY(dx); COPY(cx); COPY(ip);
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- COPY(r8);
|
|
|
- COPY(r9);
|
|
|
- COPY(r10);
|
|
|
- COPY(r11);
|
|
|
- COPY(r12);
|
|
|
- COPY(r13);
|
|
|
- COPY(r14);
|
|
|
- COPY(r15);
|
|
|
-#endif /* CONFIG_X86_64 */
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_32
|
|
|
- COPY_SEG_CPL3(cs);
|
|
|
- COPY_SEG_CPL3(ss);
|
|
|
-#else /* !CONFIG_X86_32 */
|
|
|
- /* 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. */
|
|
|
- COPY_SEG_CPL3(cs);
|
|
|
-#endif /* CONFIG_X86_32 */
|
|
|
-
|
|
|
- err |= __get_user(tmpflags, &sc->flags);
|
|
|
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
|
|
|
- regs->orig_ax = -1; /* disable syscall checks */
|
|
|
-
|
|
|
- err |= __get_user(buf, &sc->fpstate);
|
|
|
- err |= restore_i387_xstate(buf);
|
|
|
-
|
|
|
- err |= __get_user(*pax, &sc->ax);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
|
|
|
{
|
|
|
struct sigframe __user *frame;
|
|
@@ -316,66 +377,6 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
|
|
|
/*
|
|
|
* Set up a signal frame.
|
|
|
*/
|
|
|
-static int
|
|
|
-setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
|
|
|
- struct pt_regs *regs, unsigned long mask)
|
|
|
-{
|
|
|
- int err = 0;
|
|
|
-
|
|
|
-#ifdef CONFIG_X86_32
|
|
|
- {
|
|
|
- unsigned int tmp;
|
|
|
-
|
|
|
- savesegment(gs, tmp);
|
|
|
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
|
|
|
- }
|
|
|
- err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
|
|
|
- err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
|
|
|
- err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
|
|
|
-#endif /* CONFIG_X86_32 */
|
|
|
-
|
|
|
- err |= __put_user(regs->di, &sc->di);
|
|
|
- err |= __put_user(regs->si, &sc->si);
|
|
|
- err |= __put_user(regs->bp, &sc->bp);
|
|
|
- err |= __put_user(regs->sp, &sc->sp);
|
|
|
- err |= __put_user(regs->bx, &sc->bx);
|
|
|
- err |= __put_user(regs->dx, &sc->dx);
|
|
|
- err |= __put_user(regs->cx, &sc->cx);
|
|
|
- err |= __put_user(regs->ax, &sc->ax);
|
|
|
-#ifdef CONFIG_X86_64
|
|
|
- err |= __put_user(regs->r8, &sc->r8);
|
|
|
- err |= __put_user(regs->r9, &sc->r9);
|
|
|
- err |= __put_user(regs->r10, &sc->r10);
|
|
|
- err |= __put_user(regs->r11, &sc->r11);
|
|
|
- err |= __put_user(regs->r12, &sc->r12);
|
|
|
- err |= __put_user(regs->r13, &sc->r13);
|
|
|
- err |= __put_user(regs->r14, &sc->r14);
|
|
|
- err |= __put_user(regs->r15, &sc->r15);
|
|
|
-#endif /* CONFIG_X86_64 */
|
|
|
-
|
|
|
- err |= __put_user(current->thread.trap_no, &sc->trapno);
|
|
|
- err |= __put_user(current->thread.error_code, &sc->err);
|
|
|
- err |= __put_user(regs->ip, &sc->ip);
|
|
|
-#ifdef CONFIG_X86_32
|
|
|
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
|
|
|
- err |= __put_user(regs->flags, &sc->flags);
|
|
|
- err |= __put_user(regs->sp, &sc->sp_at_signal);
|
|
|
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
|
|
|
-#else /* !CONFIG_X86_32 */
|
|
|
- err |= __put_user(regs->flags, &sc->flags);
|
|
|
- err |= __put_user(regs->cs, &sc->cs);
|
|
|
- err |= __put_user(0, &sc->gs);
|
|
|
- err |= __put_user(0, &sc->fs);
|
|
|
-#endif /* CONFIG_X86_32 */
|
|
|
-
|
|
|
- err |= __put_user(fpstate, &sc->fpstate);
|
|
|
-
|
|
|
- /* non-iBCS2 extensions.. */
|
|
|
- err |= __put_user(mask, &sc->oldmask);
|
|
|
- err |= __put_user(current->thread.cr2, &sc->cr2);
|
|
|
-
|
|
|
- return err;
|
|
|
-}
|
|
|
|
|
|
/*
|
|
|
* Determine which stack to use..
|