x86, smap: Reduce the SMAP overhead for signal handling
Signal handling contains a bunch of accesses to individual user space items, which causes an excessive number of STAC and CLAC instructions. Instead, let get/put_user_try ... get/put_user_catch() contain the STAC and CLAC instructions. This means that get/put_user_try no longer nests, and furthermore that it is no longer legal to use user space access functions other than __get/put_user_ex() inside those blocks. However, these macros are x86-specific anyway and are only used in the signal-handling paths; a simple reordering of moving the larger subroutine calls out of the try...catch blocks resolves that problem. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Link: http://lkml.kernel.org/r/1348256595-29119-12-git-send-email-hpa@linux.intel.com
This commit is contained in:
@@ -250,11 +250,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
|||||||
|
|
||||||
get_user_ex(tmp, &sc->fpstate);
|
get_user_ex(tmp, &sc->fpstate);
|
||||||
buf = compat_ptr(tmp);
|
buf = compat_ptr(tmp);
|
||||||
err |= restore_i387_xstate_ia32(buf);
|
|
||||||
|
|
||||||
get_user_ex(*pax, &sc->ax);
|
get_user_ex(*pax, &sc->ax);
|
||||||
} get_user_catch(err);
|
} get_user_catch(err);
|
||||||
|
|
||||||
|
err |= restore_i387_xstate_ia32(buf);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,7 +503,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(sig, &frame->sig);
|
put_user_ex(sig, &frame->sig);
|
||||||
put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
|
put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
|
||||||
put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
|
put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
|
||||||
err |= copy_siginfo_to_user32(&frame->info, info);
|
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
if (cpu_has_xsave)
|
if (cpu_has_xsave)
|
||||||
@@ -514,9 +514,6 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(sas_ss_flags(regs->sp),
|
put_user_ex(sas_ss_flags(regs->sp),
|
||||||
&frame->uc.uc_stack.ss_flags);
|
&frame->uc.uc_stack.ss_flags);
|
||||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
|
||||||
regs, set->sig[0]);
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_RESTORER)
|
if (ka->sa.sa_flags & SA_RESTORER)
|
||||||
restorer = ka->sa.sa_restorer;
|
restorer = ka->sa.sa_restorer;
|
||||||
@@ -532,6 +529,11 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
|
err |= copy_siginfo_to_user32(&frame->info, info);
|
||||||
|
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||||
|
regs, set->sig[0]);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
|||||||
@@ -416,9 +416,8 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
|
#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
|
||||||
asm volatile(ASM_STAC "\n" \
|
asm volatile("1: mov"itype" %1,%"rtype"0\n" \
|
||||||
"1: mov"itype" %1,%"rtype"0\n" \
|
"2:\n" \
|
||||||
"2: " ASM_CLAC "\n" \
|
|
||||||
_ASM_EXTABLE_EX(1b, 2b) \
|
_ASM_EXTABLE_EX(1b, 2b) \
|
||||||
: ltype(x) : "m" (__m(addr)))
|
: ltype(x) : "m" (__m(addr)))
|
||||||
|
|
||||||
@@ -460,9 +459,8 @@ struct __large_struct { unsigned long buf[100]; };
|
|||||||
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
|
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
|
||||||
|
|
||||||
#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
|
#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
|
||||||
asm volatile(ASM_STAC "\n" \
|
asm volatile("1: mov"itype" %"rtype"0,%1\n" \
|
||||||
"1: mov"itype" %"rtype"0,%1\n" \
|
"2:\n" \
|
||||||
"2: " ASM_CLAC "\n" \
|
|
||||||
_ASM_EXTABLE_EX(1b, 2b) \
|
_ASM_EXTABLE_EX(1b, 2b) \
|
||||||
: : ltype(x), "m" (__m(addr)))
|
: : ltype(x), "m" (__m(addr)))
|
||||||
|
|
||||||
@@ -470,13 +468,13 @@ struct __large_struct { unsigned long buf[100]; };
|
|||||||
* uaccess_try and catch
|
* uaccess_try and catch
|
||||||
*/
|
*/
|
||||||
#define uaccess_try do { \
|
#define uaccess_try do { \
|
||||||
int prev_err = current_thread_info()->uaccess_err; \
|
|
||||||
current_thread_info()->uaccess_err = 0; \
|
current_thread_info()->uaccess_err = 0; \
|
||||||
|
stac(); \
|
||||||
barrier();
|
barrier();
|
||||||
|
|
||||||
#define uaccess_catch(err) \
|
#define uaccess_catch(err) \
|
||||||
|
clac(); \
|
||||||
(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0); \
|
(err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0); \
|
||||||
current_thread_info()->uaccess_err = prev_err; \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+14
-10
@@ -114,11 +114,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
|||||||
regs->orig_ax = -1; /* disable syscall checks */
|
regs->orig_ax = -1; /* disable syscall checks */
|
||||||
|
|
||||||
get_user_ex(buf, &sc->fpstate);
|
get_user_ex(buf, &sc->fpstate);
|
||||||
err |= restore_i387_xstate(buf);
|
|
||||||
|
|
||||||
get_user_ex(*pax, &sc->ax);
|
get_user_ex(*pax, &sc->ax);
|
||||||
} get_user_catch(err);
|
} get_user_catch(err);
|
||||||
|
|
||||||
|
err |= restore_i387_xstate(buf);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +358,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(sig, &frame->sig);
|
put_user_ex(sig, &frame->sig);
|
||||||
put_user_ex(&frame->info, &frame->pinfo);
|
put_user_ex(&frame->info, &frame->pinfo);
|
||||||
put_user_ex(&frame->uc, &frame->puc);
|
put_user_ex(&frame->uc, &frame->puc);
|
||||||
err |= copy_siginfo_to_user(&frame->info, info);
|
|
||||||
|
|
||||||
/* Create the ucontext. */
|
/* Create the ucontext. */
|
||||||
if (cpu_has_xsave)
|
if (cpu_has_xsave)
|
||||||
@@ -369,9 +369,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(sas_ss_flags(regs->sp),
|
put_user_ex(sas_ss_flags(regs->sp),
|
||||||
&frame->uc.uc_stack.ss_flags);
|
&frame->uc.uc_stack.ss_flags);
|
||||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
|
||||||
regs, set->sig[0]);
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
||||||
|
|
||||||
/* Set up to return from userspace. */
|
/* Set up to return from userspace. */
|
||||||
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
|
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
|
||||||
@@ -389,6 +386,11 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
|
err |= copy_siginfo_to_user(&frame->info, info);
|
||||||
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||||
|
regs, set->sig[0]);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
@@ -436,8 +438,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
put_user_ex(sas_ss_flags(regs->sp),
|
put_user_ex(sas_ss_flags(regs->sp),
|
||||||
&frame->uc.uc_stack.ss_flags);
|
&frame->uc.uc_stack.ss_flags);
|
||||||
put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
||||||
|
|
||||||
/* Set up to return from userspace. If provided, use a stub
|
/* Set up to return from userspace. If provided, use a stub
|
||||||
already in userspace. */
|
already in userspace. */
|
||||||
@@ -450,6 +450,9 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
}
|
}
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
@@ -855,9 +858,6 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
|||||||
&frame->uc.uc_stack.ss_flags);
|
&frame->uc.uc_stack.ss_flags);
|
||||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
put_user_ex(0, &frame->uc.uc__pad0);
|
put_user_ex(0, &frame->uc.uc__pad0);
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
|
||||||
regs, set->sig[0]);
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||||
restorer = ka->sa.sa_restorer;
|
restorer = ka->sa.sa_restorer;
|
||||||
@@ -869,6 +869,10 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
|||||||
put_user_ex(restorer, &frame->pretcode);
|
put_user_ex(restorer, &frame->pretcode);
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||||
|
regs, set->sig[0]);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user