forked from Minki/linux
63bcff2a30
When Supervisor Mode Access Prevention (SMAP) is enabled, access to userspace from the kernel is controlled by the AC flag. To make the performance of manipulating that flag acceptable, there are two new instructions, STAC and CLAC, to set and clear it. This patch adds those instructions, via alternative(), when the SMAP feature is enabled. It also adds X86_EFLAGS_AC unconditionally to the SYSCALL entry mask; there is simply no reason to make that one conditional. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Link: http://lkml.kernel.org/r/1348256595-29119-9-git-send-email-hpa@linux.intel.com
149 lines
3.6 KiB
C
149 lines
3.6 KiB
C
#ifndef _ASM_X86_FUTEX_H
|
|
#define _ASM_X86_FUTEX_H
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <linux/futex.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <asm/asm.h>
|
|
#include <asm/errno.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/smap.h>
|
|
|
|
#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
|
|
asm volatile("\t" ASM_STAC "\n" \
|
|
"1:\t" insn "\n" \
|
|
"2:\t" ASM_CLAC "\n" \
|
|
"\t.section .fixup,\"ax\"\n" \
|
|
"3:\tmov\t%3, %1\n" \
|
|
"\tjmp\t2b\n" \
|
|
"\t.previous\n" \
|
|
_ASM_EXTABLE(1b, 3b) \
|
|
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
|
|
: "i" (-EFAULT), "0" (oparg), "1" (0))
|
|
|
|
#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
|
|
asm volatile("\t" ASM_STAC "\n" \
|
|
"1:\tmovl %2, %0\n" \
|
|
"\tmovl\t%0, %3\n" \
|
|
"\t" insn "\n" \
|
|
"2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" \
|
|
"\tjnz\t1b\n" \
|
|
"3:\t" ASM_CLAC "\n" \
|
|
"\t.section .fixup,\"ax\"\n" \
|
|
"4:\tmov\t%5, %1\n" \
|
|
"\tjmp\t3b\n" \
|
|
"\t.previous\n" \
|
|
_ASM_EXTABLE(1b, 4b) \
|
|
_ASM_EXTABLE(2b, 4b) \
|
|
: "=&a" (oldval), "=&r" (ret), \
|
|
"+m" (*uaddr), "=&r" (tem) \
|
|
: "r" (oparg), "i" (-EFAULT), "1" (0))
|
|
|
|
static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
{
|
|
int op = (encoded_op >> 28) & 7;
|
|
int cmp = (encoded_op >> 24) & 15;
|
|
int oparg = (encoded_op << 8) >> 20;
|
|
int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret, tem;
|
|
|
|
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
oparg = 1 << oparg;
|
|
|
|
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
return -EFAULT;
|
|
|
|
#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
|
|
/* Real i386 machines can only support FUTEX_OP_SET */
|
|
if (op != FUTEX_OP_SET && boot_cpu_data.x86 == 3)
|
|
return -ENOSYS;
|
|
#endif
|
|
|
|
pagefault_disable();
|
|
|
|
switch (op) {
|
|
case FUTEX_OP_SET:
|
|
__futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
|
|
break;
|
|
case FUTEX_OP_ADD:
|
|
__futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
|
|
uaddr, oparg);
|
|
break;
|
|
case FUTEX_OP_OR:
|
|
__futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg);
|
|
break;
|
|
case FUTEX_OP_ANDN:
|
|
__futex_atomic_op2("andl %4, %3", ret, oldval, uaddr, ~oparg);
|
|
break;
|
|
case FUTEX_OP_XOR:
|
|
__futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr, oparg);
|
|
break;
|
|
default:
|
|
ret = -ENOSYS;
|
|
}
|
|
|
|
pagefault_enable();
|
|
|
|
if (!ret) {
|
|
switch (cmp) {
|
|
case FUTEX_OP_CMP_EQ:
|
|
ret = (oldval == cmparg);
|
|
break;
|
|
case FUTEX_OP_CMP_NE:
|
|
ret = (oldval != cmparg);
|
|
break;
|
|
case FUTEX_OP_CMP_LT:
|
|
ret = (oldval < cmparg);
|
|
break;
|
|
case FUTEX_OP_CMP_GE:
|
|
ret = (oldval >= cmparg);
|
|
break;
|
|
case FUTEX_OP_CMP_LE:
|
|
ret = (oldval <= cmparg);
|
|
break;
|
|
case FUTEX_OP_CMP_GT:
|
|
ret = (oldval > cmparg);
|
|
break;
|
|
default:
|
|
ret = -ENOSYS;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
u32 oldval, u32 newval)
|
|
{
|
|
int ret = 0;
|
|
|
|
#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
|
|
/* Real i386 machines have no cmpxchg instruction */
|
|
if (boot_cpu_data.x86 == 3)
|
|
return -ENOSYS;
|
|
#endif
|
|
|
|
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
return -EFAULT;
|
|
|
|
asm volatile("\t" ASM_STAC "\n"
|
|
"1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
|
|
"2:\t" ASM_CLAC "\n"
|
|
"\t.section .fixup, \"ax\"\n"
|
|
"3:\tmov %3, %0\n"
|
|
"\tjmp 2b\n"
|
|
"\t.previous\n"
|
|
_ASM_EXTABLE(1b, 3b)
|
|
: "+r" (ret), "=a" (oldval), "+m" (*uaddr)
|
|
: "i" (-EFAULT), "r" (newval), "1" (oldval)
|
|
: "memory"
|
|
);
|
|
|
|
*uval = oldval;
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
#endif /* _ASM_X86_FUTEX_H */
|