]> Git Repo - linux.git/commitdiff
Merge tag 'x86_asm_for_v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
authorLinus Torvalds <[email protected]>
Tue, 13 Oct 2020 20:36:07 +0000 (13:36 -0700)
committerLinus Torvalds <[email protected]>
Tue, 13 Oct 2020 20:36:07 +0000 (13:36 -0700)
Pull x86 asm updates from Borislav Petkov:
 "Two asm wrapper fixes:

   - Use XORL instead of XORQ to avoid a REX prefix and save some bytes
     in the .fixup section, by Uros Bizjak.

   - Replace __force_order dummy variable with a memory clobber to fix
     LLVM requiring a definition for former and to prevent memory
     accesses from still being cached/reordered, by Arvind Sankar"

* tag 'x86_asm_for_v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/asm: Replace __force_order with a memory clobber
  x86/uaccess: Use XORL %0,%0 in __get_user_asm()

1  2 
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/uaccess.h
arch/x86/kernel/cpu/common.c

index 94624fb06facd8ce2cc42892526ea074677a7515,d6e3bb9363d228dd2ceb0bf2335f9fbbd08a9ca1..cc177b4431ae8255504afc3c97454cfb480f9eb9
  #include <linux/jump_label.h>
  
  /*
-  * Volatile isn't enough to prevent the compiler from reordering the
-  * read/write functions for the control registers and messing everything up.
-  * A memory clobber would solve the problem, but would prevent reordering of
-  * all loads stores around it, which can hurt performance. Solution is to
-  * use a variable and mimic reads and writes to it to enforce serialization
+  * The compiler should not reorder volatile asm statements with respect to each
+  * other: they should execute in program order. However GCC 4.9.x and 5.x have
+  * a bug (which was fixed in 8.1, 7.3 and 6.5) where they might reorder
+  * volatile asm. The write functions are not affected since they have memory
+  * clobbers preventing reordering. To prevent reads from being reordered with
+  * respect to writes, use a dummy memory operand.
   */
- extern unsigned long __force_order;
+ #define __FORCE_ORDER "m"(*(unsigned int *)0x1000UL)
  
  void native_write_cr0(unsigned long val);
  
  static inline unsigned long native_read_cr0(void)
  {
        unsigned long val;
-       asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
+       asm volatile("mov %%cr0,%0\n\t" : "=r" (val) : __FORCE_ORDER);
        return val;
  }
  
  static __always_inline unsigned long native_read_cr2(void)
  {
        unsigned long val;
-       asm volatile("mov %%cr2,%0\n\t" : "=r" (val), "=m" (__force_order));
+       asm volatile("mov %%cr2,%0\n\t" : "=r" (val) : __FORCE_ORDER);
        return val;
  }
  
  static __always_inline void native_write_cr2(unsigned long val)
  {
-       asm volatile("mov %0,%%cr2": : "r" (val), "m" (__force_order));
+       asm volatile("mov %0,%%cr2": : "r" (val) : "memory");
  }
  
  static inline unsigned long __native_read_cr3(void)
  {
        unsigned long val;
-       asm volatile("mov %%cr3,%0\n\t" : "=r" (val), "=m" (__force_order));
+       asm volatile("mov %%cr3,%0\n\t" : "=r" (val) : __FORCE_ORDER);
        return val;
  }
  
  static inline void native_write_cr3(unsigned long val)
  {
-       asm volatile("mov %0,%%cr3": : "r" (val), "m" (__force_order));
+       asm volatile("mov %0,%%cr3": : "r" (val) : "memory");
  }
  
  static inline unsigned long native_read_cr4(void)
        asm volatile("1: mov %%cr4, %0\n"
                     "2:\n"
                     _ASM_EXTABLE(1b, 2b)
-                    : "=r" (val), "=m" (__force_order) : "0" (0));
+                    : "=r" (val) : "0" (0), __FORCE_ORDER);
  #else
        /* CR4 always exists on x86_64. */
-       asm volatile("mov %%cr4,%0\n\t" : "=r" (val), "=m" (__force_order));
+       asm volatile("mov %%cr4,%0\n\t" : "=r" (val) : __FORCE_ORDER);
  #endif
        return val;
  }
@@@ -234,76 -236,6 +236,76 @@@ static inline void clwb(volatile void *
  
  #define nop() asm volatile ("nop")
  
 +static inline void serialize(void)
 +{
 +      /* Instruction opcode for SERIALIZE; supported in binutils >= 2.35. */
 +      asm volatile(".byte 0xf, 0x1, 0xe8" ::: "memory");
 +}
 +
 +/* The dst parameter must be 64-bytes aligned */
 +static inline void movdir64b(void *dst, const void *src)
 +{
 +      const struct { char _[64]; } *__src = src;
 +      struct { char _[64]; } *__dst = dst;
 +
 +      /*
 +       * MOVDIR64B %(rdx), rax.
 +       *
 +       * Both __src and __dst must be memory constraints in order to tell the
 +       * compiler that no other memory accesses should be reordered around
 +       * this one.
 +       *
 +       * Also, both must be supplied as lvalues because this tells
 +       * the compiler what the object is (its size) the instruction accesses.
 +       * I.e., not the pointers but what they point to, thus the deref'ing '*'.
 +       */
 +      asm volatile(".byte 0x66, 0x0f, 0x38, 0xf8, 0x02"
 +                   : "+m" (*__dst)
 +                   :  "m" (*__src), "a" (__dst), "d" (__src));
 +}
 +
 +/**
 + * enqcmds - Enqueue a command in supervisor (CPL0) mode
 + * @dst: destination, in MMIO space (must be 512-bit aligned)
 + * @src: 512 bits memory operand
 + *
 + * The ENQCMDS instruction allows software to write a 512-bit command to
 + * a 512-bit-aligned special MMIO region that supports the instruction.
 + * A return status is loaded into the ZF flag in the RFLAGS register.
 + * ZF = 0 equates to success, and ZF = 1 indicates retry or error.
 + *
 + * This function issues the ENQCMDS instruction to submit data from
 + * kernel space to MMIO space, in a unit of 512 bits. Order of data access
 + * is not guaranteed, nor is a memory barrier performed afterwards. It
 + * returns 0 on success and -EAGAIN on failure.
 + *
 + * Warning: Do not use this helper unless your driver has checked that the
 + * ENQCMDS instruction is supported on the platform and the device accepts
 + * ENQCMDS.
 + */
 +static inline int enqcmds(void __iomem *dst, const void *src)
 +{
 +      const struct { char _[64]; } *__src = src;
 +      struct { char _[64]; } *__dst = dst;
 +      int zf;
 +
 +      /*
 +       * ENQCMDS %(rdx), rax
 +       *
 +       * See movdir64b()'s comment on operand specification.
 +       */
 +      asm volatile(".byte 0xf3, 0x0f, 0x38, 0xf8, 0x02, 0x66, 0x90"
 +                   CC_SET(z)
 +                   : CC_OUT(z) (zf), "+m" (*__dst)
 +                   : "m" (*__src), "a" (__dst), "d" (__src));
 +
 +      /* Submission failure is indicated via EFLAGS.ZF=1 */
 +      if (zf)
 +              return -EAGAIN;
 +
 +      return 0;
 +}
 +
  #endif /* __KERNEL__ */
  
  #endif /* _ASM_X86_SPECIAL_INSNS_H */
index aa60c239931b7459a3431f45761370623daccaf1,2bffba2a1b2323903154ff227038a72228858e93..477c503f2753d5f976f59d798304df900a28f4e7
@@@ -96,14 -96,25 +96,14 @@@ static inline bool pagefault_disabled(v
        likely(!__range_not_ok(addr, size, user_addr_max()));           \
  })
  
 -/*
 - * These are the main single-value transfer routines.  They automatically
 - * use the right size if we just have the right pointer type.
 - *
 - * This gets kind of ugly. We want to return _two_ values in "get_user()"
 - * and yet we don't want to do any pointers, because that is too much
 - * of a performance impact. Thus we have a few rather ugly macros here,
 - * and hide all the ugliness from the user.
 - *
 - * The "__xxx" versions of the user access functions are versions that
 - * do not verify the address space, that must have been done previously
 - * with a separate "access_ok()" call (this is used when we do multiple
 - * accesses to the same area of user memory).
 - */
 -
  extern int __get_user_1(void);
  extern int __get_user_2(void);
  extern int __get_user_4(void);
  extern int __get_user_8(void);
 +extern int __get_user_nocheck_1(void);
 +extern int __get_user_nocheck_2(void);
 +extern int __get_user_nocheck_4(void);
 +extern int __get_user_nocheck_8(void);
  extern int __get_user_bad(void);
  
  #define __uaccess_begin() stac()
  #define __typefits(x,type,not) \
        __builtin_choose_expr(sizeof(x)<=sizeof(type),(unsigned type)0,not)
  
 -/**
 - * get_user - Get a simple variable from user space.
 - * @x:   Variable to store result.
 - * @ptr: Source address, in user space.
 - *
 - * Context: User context only. This function may sleep if pagefaults are
 - *          enabled.
 - *
 - * This macro copies a single simple variable from user space to kernel
 - * space.  It supports simple types like char and int, but not larger
 - * data types like structures or arrays.
 - *
 - * @ptr must have pointer-to-simple-variable type, and the result of
 - * dereferencing @ptr must be assignable to @x without a cast.
 - *
 - * Return: zero on success, or -EFAULT on error.
 - * On error, the variable @x is set to zero.
 - */
  /*
 + * This is used for both get_user() and __get_user() to expand to
 + * the proper special function call that has odd calling conventions
 + * due to returning both a value and an error, and that depends on
 + * the size of the pointer passed in.
 + *
   * Careful: we have to cast the result to the type of the pointer
   * for sign reasons.
   *
   * Clang/LLVM cares about the size of the register, but still wants
   * the base register for something that ends up being a pair.
   */
 -#define get_user(x, ptr)                                              \
 +#define do_get_user_call(fn,x,ptr)                                    \
  ({                                                                    \
        int __ret_gu;                                                   \
        register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);            \
        __chk_user_ptr(ptr);                                            \
 -      might_fault();                                                  \
 -      asm volatile("call __get_user_%P4"                              \
 +      asm volatile("call __" #fn "_%P4"                               \
                     : "=a" (__ret_gu), "=r" (__val_gu),                \
                        ASM_CALL_CONSTRAINT                             \
                     : "0" (ptr), "i" (sizeof(*(ptr))));                \
        __builtin_expect(__ret_gu, 0);                                  \
  })
  
 -#define __put_user_x(size, x, ptr, __ret_pu)                  \
 -      asm volatile("call __put_user_" #size : "=a" (__ret_pu) \
 -                   : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
 +/**
 + * get_user - Get a simple variable from user space.
 + * @x:   Variable to store result.
 + * @ptr: Source address, in user space.
 + *
 + * Context: User context only. This function may sleep if pagefaults are
 + *          enabled.
 + *
 + * This macro copies a single simple variable from user space to kernel
 + * space.  It supports simple types like char and int, but not larger
 + * data types like structures or arrays.
 + *
 + * @ptr must have pointer-to-simple-variable type, and the result of
 + * dereferencing @ptr must be assignable to @x without a cast.
 + *
 + * Return: zero on success, or -EFAULT on error.
 + * On error, the variable @x is set to zero.
 + */
 +#define get_user(x,ptr) ({ might_fault(); do_get_user_call(get_user,x,ptr); })
  
 +/**
 + * __get_user - Get a simple variable from user space, with less checking.
 + * @x:   Variable to store result.
 + * @ptr: Source address, in user space.
 + *
 + * Context: User context only. This function may sleep if pagefaults are
 + *          enabled.
 + *
 + * This macro copies a single simple variable from user space to kernel
 + * space.  It supports simple types like char and int, but not larger
 + * data types like structures or arrays.
 + *
 + * @ptr must have pointer-to-simple-variable type, and the result of
 + * dereferencing @ptr must be assignable to @x without a cast.
 + *
 + * Caller must check the pointer with access_ok() before calling this
 + * function.
 + *
 + * Return: zero on success, or -EFAULT on error.
 + * On error, the variable @x is set to zero.
 + */
 +#define __get_user(x,ptr) do_get_user_call(get_user_nocheck,x,ptr)
  
  
  #ifdef CONFIG_X86_32
                     : : "A" (x), "r" (addr)                    \
                     : : label)
  
 -#define __put_user_x8(x, ptr, __ret_pu)                               \
 -      asm volatile("call __put_user_8" : "=a" (__ret_pu)      \
 -                   : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
  #else
  #define __put_user_goto_u64(x, ptr, label) \
        __put_user_goto(x, ptr, "q", "er", label)
 -#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
  #endif
  
  extern void __put_user_bad(void);
  
  /*
   * Strange magic calling convention: pointer in %ecx,
 - * value in %eax(:%edx), return value in %eax. clobbers %rbx
 + * value in %eax(:%edx), return value in %ecx. clobbers %rbx
   */
  extern void __put_user_1(void);
  extern void __put_user_2(void);
  extern void __put_user_4(void);
  extern void __put_user_8(void);
 +extern void __put_user_nocheck_1(void);
 +extern void __put_user_nocheck_2(void);
 +extern void __put_user_nocheck_4(void);
 +extern void __put_user_nocheck_8(void);
 +
 +#define do_put_user_call(fn,x,ptr)                                    \
 +({                                                                    \
 +      int __ret_pu;                                                   \
 +      register __typeof__(*(ptr)) __val_pu asm("%"_ASM_AX);           \
 +      __chk_user_ptr(ptr);                                            \
 +      __val_pu = (x);                                                 \
 +      asm volatile("call __" #fn "_%P[size]"                          \
 +                   : "=c" (__ret_pu),                                 \
 +                      ASM_CALL_CONSTRAINT                             \
 +                   : "0" (ptr),                                       \
 +                     "r" (__val_pu),                                  \
 +                     [size] "i" (sizeof(*(ptr)))                      \
 +                   :"ebx");                                           \
 +      __builtin_expect(__ret_pu, 0);                                  \
 +})
  
  /**
   * put_user - Write a simple value into user space.
   *
   * Return: zero on success, or -EFAULT on error.
   */
 -#define put_user(x, ptr)                                      \
 -({                                                            \
 -      int __ret_pu;                                           \
 -      __typeof__(*(ptr)) __pu_val;                            \
 -      __chk_user_ptr(ptr);                                    \
 -      might_fault();                                          \
 -      __pu_val = x;                                           \
 -      switch (sizeof(*(ptr))) {                               \
 -      case 1:                                                 \
 -              __put_user_x(1, __pu_val, ptr, __ret_pu);       \
 -              break;                                          \
 -      case 2:                                                 \
 -              __put_user_x(2, __pu_val, ptr, __ret_pu);       \
 -              break;                                          \
 -      case 4:                                                 \
 -              __put_user_x(4, __pu_val, ptr, __ret_pu);       \
 -              break;                                          \
 -      case 8:                                                 \
 -              __put_user_x8(__pu_val, ptr, __ret_pu);         \
 -              break;                                          \
 -      default:                                                \
 -              __put_user_x(X, __pu_val, ptr, __ret_pu);       \
 -              break;                                          \
 -      }                                                       \
 -      __builtin_expect(__ret_pu, 0);                          \
 -})
 +#define put_user(x, ptr) ({ might_fault(); do_put_user_call(put_user,x,ptr); })
 +
 +/**
 + * __put_user - Write a simple value into user space, with less checking.
 + * @x:   Value to copy to user space.
 + * @ptr: Destination address, in user space.
 + *
 + * Context: User context only. This function may sleep if pagefaults are
 + *          enabled.
 + *
 + * This macro copies a single simple value from kernel space to user
 + * space.  It supports simple types like char and int, but not larger
 + * data types like structures or arrays.
 + *
 + * @ptr must have pointer-to-simple-variable type, and @x must be assignable
 + * to the result of dereferencing @ptr.
 + *
 + * Caller must check the pointer with access_ok() before calling this
 + * function.
 + *
 + * Return: zero on success, or -EFAULT on error.
 + */
 +#define __put_user(x, ptr) do_put_user_call(put_user_nocheck,x,ptr)
  
  #define __put_user_size(x, ptr, size, label)                          \
  do {                                                                  \
        }                                                               \
  } while (0)
  
 +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 +
 +#ifdef CONFIG_X86_32
 +#define __get_user_asm_u64(x, ptr, label) do {                                \
 +      unsigned int __gu_low, __gu_high;                               \
 +      const unsigned int __user *__gu_ptr;                            \
 +      __gu_ptr = (const void __user *)(ptr);                          \
 +      __get_user_asm(__gu_low, ptr, "l", "=r", label);                \
 +      __get_user_asm(__gu_high, ptr+1, "l", "=r", label);             \
 +      (x) = ((unsigned long long)__gu_high << 32) | __gu_low;         \
 +} while (0)
 +#else
 +#define __get_user_asm_u64(x, ptr, label)                             \
 +      __get_user_asm(x, ptr, "q", "=r", label)
 +#endif
 +
 +#define __get_user_size(x, ptr, size, label)                          \
 +do {                                                                  \
 +      __chk_user_ptr(ptr);                                            \
 +      switch (size) {                                                 \
 +      unsigned char x_u8__;                                           \
 +      case 1:                                                         \
 +              __get_user_asm(x_u8__, ptr, "b", "=q", label);          \
 +              (x) = x_u8__;                                           \
 +              break;                                                  \
 +      case 2:                                                         \
 +              __get_user_asm(x, ptr, "w", "=r", label);               \
 +              break;                                                  \
 +      case 4:                                                         \
 +              __get_user_asm(x, ptr, "l", "=r", label);               \
 +              break;                                                  \
 +      case 8:                                                         \
 +              __get_user_asm_u64(x, ptr, label);                      \
 +              break;                                                  \
 +      default:                                                        \
 +              (x) = __get_user_bad();                                 \
 +      }                                                               \
 +} while (0)
 +
 +#define __get_user_asm(x, addr, itype, ltype, label)                  \
 +      asm_volatile_goto("\n"                                          \
 +                   "1:        mov"itype" %[umem],%[output]\n"         \
 +                   _ASM_EXTABLE_UA(1b, %l2)                           \
 +                   : [output] ltype(x)                                \
 +                   : [umem] "m" (__m(addr))                           \
 +                   : : label)
 +
 +#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 +
  #ifdef CONFIG_X86_32
  #define __get_user_asm_u64(x, ptr, retval)                            \
  ({                                                                    \
@@@ -418,7 -343,7 +418,7 @@@ do {                                                                       
                     "2:\n"                                             \
                     ".section .fixup,\"ax\"\n"                         \
                     "3:        mov %[efault],%[errout]\n"              \
-                    "  xor"itype" %[output],%[output]\n"               \
+                    "  xorl %k[output],%k[output]\n"                   \
                     "  jmp 2b\n"                                       \
                     ".previous\n"                                      \
                     _ASM_EXTABLE_UA(1b, 3b)                            \
                     : [umem] "m" (__m(addr)),                          \
                       [efault] "i" (-EFAULT), "0" (err))
  
 -#define __put_user_nocheck(x, ptr, size)                      \
 -({                                                            \
 -      __label__ __pu_label;                                   \
 -      int __pu_err = -EFAULT;                                 \
 -      __typeof__(*(ptr)) __pu_val = (x);                      \
 -      __typeof__(ptr) __pu_ptr = (ptr);                       \
 -      __typeof__(size) __pu_size = (size);                    \
 -      __uaccess_begin();                                      \
 -      __put_user_size(__pu_val, __pu_ptr, __pu_size, __pu_label);     \
 -      __pu_err = 0;                                           \
 -__pu_label:                                                   \
 -      __uaccess_end();                                        \
 -      __builtin_expect(__pu_err, 0);                          \
 -})
 -
 -#define __get_user_nocheck(x, ptr, size)                              \
 -({                                                                    \
 -      int __gu_err;                                                   \
 -      __inttype(*(ptr)) __gu_val;                                     \
 -      __typeof__(ptr) __gu_ptr = (ptr);                               \
 -      __typeof__(size) __gu_size = (size);                            \
 -      __uaccess_begin_nospec();                                       \
 -      __get_user_size(__gu_val, __gu_ptr, __gu_size, __gu_err);       \
 -      __uaccess_end();                                                \
 -      (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
 -      __builtin_expect(__gu_err, 0);                                  \
 -})
 +#endif // CONFIG_CC_ASM_GOTO_OUTPUT
  
  /* FIXME: this hack is definitely wrong -AK */
  struct __large_struct { unsigned long buf[100]; };
                : : ltype(x), "m" (__m(addr))                           \
                : : label)
  
 -/**
 - * __get_user - Get a simple variable from user space, with less checking.
 - * @x:   Variable to store result.
 - * @ptr: Source address, in user space.
 - *
 - * Context: User context only. This function may sleep if pagefaults are
 - *          enabled.
 - *
 - * This macro copies a single simple variable from user space to kernel
 - * space.  It supports simple types like char and int, but not larger
 - * data types like structures or arrays.
 - *
 - * @ptr must have pointer-to-simple-variable type, and the result of
 - * dereferencing @ptr must be assignable to @x without a cast.
 - *
 - * Caller must check the pointer with access_ok() before calling this
 - * function.
 - *
 - * Return: zero on success, or -EFAULT on error.
 - * On error, the variable @x is set to zero.
 - */
 -
 -#define __get_user(x, ptr)                                            \
 -      __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 -
 -/**
 - * __put_user - Write a simple value into user space, with less checking.
 - * @x:   Value to copy to user space.
 - * @ptr: Destination address, in user space.
 - *
 - * Context: User context only. This function may sleep if pagefaults are
 - *          enabled.
 - *
 - * This macro copies a single simple value from kernel space to user
 - * space.  It supports simple types like char and int, but not larger
 - * data types like structures or arrays.
 - *
 - * @ptr must have pointer-to-simple-variable type, and @x must be assignable
 - * to the result of dereferencing @ptr.
 - *
 - * Caller must check the pointer with access_ok() before calling this
 - * function.
 - *
 - * Return: zero on success, or -EFAULT on error.
 - */
 -
 -#define __put_user(x, ptr)                                            \
 -      __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
 -
  extern unsigned long
  copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
  extern __must_check long
@@@ -455,15 -455,6 +455,15 @@@ extern __must_check long strnlen_user(c
  unsigned long __must_check clear_user(void __user *mem, unsigned long len);
  unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
  
 +#ifdef CONFIG_ARCH_HAS_COPY_MC
 +unsigned long __must_check
 +copy_mc_to_kernel(void *to, const void *from, unsigned len);
 +#define copy_mc_to_kernel copy_mc_to_kernel
 +
 +unsigned long __must_check
 +copy_mc_to_user(void *to, const void *from, unsigned len);
 +#endif
 +
  /*
   * movsl can be slow when source and dest are not both 8-byte aligned
   */
@@@ -503,14 -494,6 +503,14 @@@ static __must_check __always_inline boo
  #define unsafe_put_user(x, ptr, label)        \
        __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
  
 +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 +#define unsafe_get_user(x, ptr, err_label)                                    \
 +do {                                                                          \
 +      __inttype(*(ptr)) __gu_val;                                             \
 +      __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), err_label);            \
 +      (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
 +} while (0)
 +#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
  #define unsafe_get_user(x, ptr, err_label)                                    \
  do {                                                                          \
        int __gu_err;                                                           \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
        if (unlikely(__gu_err)) goto err_label;                                 \
  } while (0)
 +#endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT
  
  /*
   * We want the unsafe accessors to always be inlined and use
@@@ -546,11 -528,6 +546,11 @@@ do {                                                                     
  
  #define HAVE_GET_KERNEL_NOFAULT
  
 +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 +#define __get_kernel_nofault(dst, src, type, err_label)                       \
 +      __get_user_size(*((type *)(dst)), (__force type __user *)(src), \
 +                      sizeof(type), err_label)
 +#else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
  #define __get_kernel_nofault(dst, src, type, err_label)                       \
  do {                                                                  \
        int __kr_err;                                                   \
        if (unlikely(__kr_err))                                         \
                goto err_label;                                         \
  } while (0)
 +#endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT
  
  #define __put_kernel_nofault(dst, src, type, err_label)                       \
        __put_user_size(*((type *)(src)), (__force type __user *)(dst), \
index 7824fc62c7cd646a663cfeb0e530726f84f3e77a,178499f9036612f7365e61ec49aeec066c102251..c51158914ea26f4e4f50b3c044a55bcf28681f21
@@@ -23,7 -23,6 +23,7 @@@
  #include <linux/syscore_ops.h>
  #include <linux/pgtable.h>
  
 +#include <asm/cmdline.h>
  #include <asm/stackprotector.h>
  #include <asm/perf_event.h>
  #include <asm/mmu_context.h>
@@@ -360,7 -359,7 +360,7 @@@ void native_write_cr0(unsigned long val
        unsigned long bits_missing = 0;
  
  set_register:
-       asm volatile("mov %0,%%cr0": "+r" (val), "+m" (__force_order));
+       asm volatile("mov %0,%%cr0": "+r" (val) : : "memory");
  
        if (static_branch_likely(&cr_pinning)) {
                if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) {
@@@ -379,7 -378,7 +379,7 @@@ void native_write_cr4(unsigned long val
        unsigned long bits_changed = 0;
  
  set_register:
-       asm volatile("mov %0,%%cr4": "+r" (val), "+m" (cr4_pinned_bits));
+       asm volatile("mov %0,%%cr4": "+r" (val) : : "memory");
  
        if (static_branch_likely(&cr_pinning)) {
                if (unlikely((val & cr4_pinned_mask) != cr4_pinned_bits)) {
@@@ -1221,59 -1220,6 +1221,59 @@@ static void detect_nopl(void
  #endif
  }
  
 +/*
 + * We parse cpu parameters early because fpu__init_system() is executed
 + * before parse_early_param().
 + */
 +static void __init cpu_parse_early_param(void)
 +{
 +      char arg[128];
 +      char *argptr = arg;
 +      int arglen, res, bit;
 +
 +#ifdef CONFIG_X86_32
 +      if (cmdline_find_option_bool(boot_command_line, "no387"))
 +#ifdef CONFIG_MATH_EMULATION
 +              setup_clear_cpu_cap(X86_FEATURE_FPU);
 +#else
 +              pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n");
 +#endif
 +
 +      if (cmdline_find_option_bool(boot_command_line, "nofxsr"))
 +              setup_clear_cpu_cap(X86_FEATURE_FXSR);
 +#endif
 +
 +      if (cmdline_find_option_bool(boot_command_line, "noxsave"))
 +              setup_clear_cpu_cap(X86_FEATURE_XSAVE);
 +
 +      if (cmdline_find_option_bool(boot_command_line, "noxsaveopt"))
 +              setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
 +
 +      if (cmdline_find_option_bool(boot_command_line, "noxsaves"))
 +              setup_clear_cpu_cap(X86_FEATURE_XSAVES);
 +
 +      arglen = cmdline_find_option(boot_command_line, "clearcpuid", arg, sizeof(arg));
 +      if (arglen <= 0)
 +              return;
 +
 +      pr_info("Clearing CPUID bits:");
 +      do {
 +              res = get_option(&argptr, &bit);
 +              if (res == 0 || res == 3)
 +                      break;
 +
 +              /* If the argument was too long, the last bit may be cut off */
 +              if (res == 1 && arglen >= sizeof(arg))
 +                      break;
 +
 +              if (bit >= 0 && bit < NCAPINTS * 32) {
 +                      pr_cont(" " X86_CAP_FMT, x86_cap_flag(bit));
 +                      setup_clear_cpu_cap(bit);
 +              }
 +      } while (res == 2);
 +      pr_cont("\n");
 +}
 +
  /*
   * Do minimum CPU detection early.
   * Fields really needed: vendor, cpuid_level, family, model, mask,
@@@ -1309,7 -1255,6 +1309,7 @@@ static void __init early_identify_cpu(s
                get_cpu_cap(c);
                get_cpu_address_sizes(c);
                setup_force_cpu_cap(X86_FEATURE_CPUID);
 +              cpu_parse_early_param();
  
                if (this_cpu->c_early_init)
                        this_cpu->c_early_init(c);
@@@ -1468,7 -1413,15 +1468,7 @@@ static void generic_identify(struct cpu
         * ESPFIX issue, we can change this.
         */
  #ifdef CONFIG_X86_32
 -# ifdef CONFIG_PARAVIRT_XXL
 -      do {
 -              extern void native_iret(void);
 -              if (pv_ops.cpu.iret == native_iret)
 -                      set_cpu_bug(c, X86_BUG_ESPFIX);
 -      } while (0);
 -# else
        set_cpu_bug(c, X86_BUG_ESPFIX);
 -# endif
  #endif
  }
  
This page took 0.087785 seconds and 4 git commands to generate.