Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: um, x86: Cast to (u64 *) inside set_64bit() x86-32, asm: Directly access per-cpu GDT x86-64, asm: Directly access per-cpu IST x86, asm: Merge cmpxchg_486_u64() and cmpxchg8b_emu() x86, asm: Move cmpxchg emulation code to arch/x86/lib x86, asm: Clean up and simplify <asm/cmpxchg.h> x86, asm: Clean up and simplify set_64bit() x86: Add memory modify constraints to xchg() and cmpxchg() x86-64: Simplify loading initial_gs x86: Use symbolic MSR names x86: Remove redundant K6 MSRs
This commit is contained in:
commit
d9a73c0016
|
@ -60,7 +60,7 @@
|
||||||
set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd)))
|
set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd)))
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
#define set_pud(pudptr, pudval) set_64bit((phys_t *) (pudptr), pud_val(pudval))
|
#define set_pud(pudptr, pudval) set_64bit((u64 *) (pudptr), pud_val(pudval))
|
||||||
#else
|
#else
|
||||||
#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
|
#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,7 +73,7 @@ static inline int pgd_newpage(pgd_t pgd)
|
||||||
static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
|
static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
#define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
|
#define set_pmd(pmdptr, pmdval) set_64bit((u64 *) (pmdptr), pmd_val(pmdval))
|
||||||
#else
|
#else
|
||||||
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
|
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,38 +11,42 @@
|
||||||
extern void __xchg_wrong_size(void);
|
extern void __xchg_wrong_size(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
|
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
|
||||||
* Note 2: xchg has side effect, so that attribute volatile is necessary,
|
* Since this is generally used to protect other memory information, we
|
||||||
* but generally the primitive is invalid, *ptr is output argument. --ANK
|
* use "asm volatile" and "memory" clobbers to prevent gcc from moving
|
||||||
|
* information around.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct __xchg_dummy {
|
|
||||||
unsigned long a[100];
|
|
||||||
};
|
|
||||||
#define __xg(x) ((struct __xchg_dummy *)(x))
|
|
||||||
|
|
||||||
#define __xchg(x, ptr, size) \
|
#define __xchg(x, ptr, size) \
|
||||||
({ \
|
({ \
|
||||||
__typeof(*(ptr)) __x = (x); \
|
__typeof(*(ptr)) __x = (x); \
|
||||||
switch (size) { \
|
switch (size) { \
|
||||||
case 1: \
|
case 1: \
|
||||||
asm volatile("xchgb %b0,%1" \
|
{ \
|
||||||
: "=q" (__x) \
|
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
asm volatile("xchgb %0,%1" \
|
||||||
|
: "=q" (__x), "+m" (*__ptr) \
|
||||||
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 2: \
|
case 2: \
|
||||||
asm volatile("xchgw %w0,%1" \
|
{ \
|
||||||
: "=r" (__x) \
|
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
asm volatile("xchgw %0,%1" \
|
||||||
|
: "=r" (__x), "+m" (*__ptr) \
|
||||||
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 4: \
|
case 4: \
|
||||||
|
{ \
|
||||||
|
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||||
asm volatile("xchgl %0,%1" \
|
asm volatile("xchgl %0,%1" \
|
||||||
: "=r" (__x) \
|
: "=r" (__x), "+m" (*__ptr) \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
default: \
|
default: \
|
||||||
__xchg_wrong_size(); \
|
__xchg_wrong_size(); \
|
||||||
} \
|
} \
|
||||||
|
@ -53,60 +57,33 @@ struct __xchg_dummy {
|
||||||
__xchg((v), (ptr), sizeof(*ptr))
|
__xchg((v), (ptr), sizeof(*ptr))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The semantics of XCHGCMP8B are a bit strange, this is why
|
* CMPXCHG8B only writes to the target if we had the previous
|
||||||
* there is a loop and the loading of %%eax and %%edx has to
|
* value in registers, otherwise it acts as a read and gives us the
|
||||||
* be inside. This inlines well in most cases, the cached
|
* "new previous" value. That is why there is a loop. Preloading
|
||||||
* cost is around ~38 cycles. (in the future we might want
|
* EDX:EAX is a performance optimization: in the common case it means
|
||||||
* to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
|
* we need only one locked operation.
|
||||||
* might have an implicit FPU-save as a cost, so it's not
|
|
||||||
* clear which path to go.)
|
|
||||||
*
|
*
|
||||||
* cmpxchg8b must be used with the lock prefix here to allow
|
* A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
|
||||||
* the instruction to be executed atomically, see page 3-102
|
* least an FPU save and/or %cr0.ts manipulation.
|
||||||
* of the instruction set reference 24319102.pdf. We need
|
*
|
||||||
* the reader side to see the coherent 64bit value.
|
* cmpxchg8b must be used with the lock prefix here to allow the
|
||||||
|
* instruction to be executed atomically. We need to have the reader
|
||||||
|
* side to see the coherent 64bit value.
|
||||||
*/
|
*/
|
||||||
static inline void __set_64bit(unsigned long long *ptr,
|
static inline void set_64bit(volatile u64 *ptr, u64 value)
|
||||||
unsigned int low, unsigned int high)
|
|
||||||
{
|
{
|
||||||
|
u32 low = value;
|
||||||
|
u32 high = value >> 32;
|
||||||
|
u64 prev = *ptr;
|
||||||
|
|
||||||
asm volatile("\n1:\t"
|
asm volatile("\n1:\t"
|
||||||
"movl (%0), %%eax\n\t"
|
LOCK_PREFIX "cmpxchg8b %0\n\t"
|
||||||
"movl 4(%0), %%edx\n\t"
|
|
||||||
LOCK_PREFIX "cmpxchg8b (%0)\n\t"
|
|
||||||
"jnz 1b"
|
"jnz 1b"
|
||||||
: /* no outputs */
|
: "=m" (*ptr), "+A" (prev)
|
||||||
: "D"(ptr),
|
: "b" (low), "c" (high)
|
||||||
"b"(low),
|
: "memory");
|
||||||
"c"(high)
|
|
||||||
: "ax", "dx", "memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __set_64bit_constant(unsigned long long *ptr,
|
|
||||||
unsigned long long value)
|
|
||||||
{
|
|
||||||
__set_64bit(ptr, (unsigned int)value, (unsigned int)(value >> 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ll_low(x) *(((unsigned int *)&(x)) + 0)
|
|
||||||
#define ll_high(x) *(((unsigned int *)&(x)) + 1)
|
|
||||||
|
|
||||||
static inline void __set_64bit_var(unsigned long long *ptr,
|
|
||||||
unsigned long long value)
|
|
||||||
{
|
|
||||||
__set_64bit(ptr, ll_low(value), ll_high(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define set_64bit(ptr, value) \
|
|
||||||
(__builtin_constant_p((value)) \
|
|
||||||
? __set_64bit_constant((ptr), (value)) \
|
|
||||||
: __set_64bit_var((ptr), (value)))
|
|
||||||
|
|
||||||
#define _set_64bit(ptr, value) \
|
|
||||||
(__builtin_constant_p(value) \
|
|
||||||
? __set_64bit(ptr, (unsigned int)(value), \
|
|
||||||
(unsigned int)((value) >> 32)) \
|
|
||||||
: __set_64bit(ptr, ll_low((value)), ll_high((value))))
|
|
||||||
|
|
||||||
extern void __cmpxchg_wrong_size(void);
|
extern void __cmpxchg_wrong_size(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -121,23 +98,32 @@ extern void __cmpxchg_wrong_size(void);
|
||||||
__typeof__(*(ptr)) __new = (new); \
|
__typeof__(*(ptr)) __new = (new); \
|
||||||
switch (size) { \
|
switch (size) { \
|
||||||
case 1: \
|
case 1: \
|
||||||
asm volatile(lock "cmpxchgb %b1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||||
: "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgb %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "q" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 2: \
|
case 2: \
|
||||||
asm volatile(lock "cmpxchgw %w1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||||
: "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgw %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "r" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 4: \
|
case 4: \
|
||||||
asm volatile(lock "cmpxchgl %1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||||
: "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgl %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "r" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
default: \
|
default: \
|
||||||
__cmpxchg_wrong_size(); \
|
__cmpxchg_wrong_size(); \
|
||||||
} \
|
} \
|
||||||
|
@ -175,32 +161,28 @@ extern void __cmpxchg_wrong_size(void);
|
||||||
(unsigned long long)(n)))
|
(unsigned long long)(n)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline unsigned long long __cmpxchg64(volatile void *ptr,
|
static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
|
||||||
unsigned long long old,
|
|
||||||
unsigned long long new)
|
|
||||||
{
|
{
|
||||||
unsigned long long prev;
|
u64 prev;
|
||||||
asm volatile(LOCK_PREFIX "cmpxchg8b %3"
|
asm volatile(LOCK_PREFIX "cmpxchg8b %1"
|
||||||
: "=A"(prev)
|
: "=A" (prev),
|
||||||
: "b"((unsigned long)new),
|
"+m" (*ptr)
|
||||||
"c"((unsigned long)(new >> 32)),
|
: "b" ((u32)new),
|
||||||
"m"(*__xg(ptr)),
|
"c" ((u32)(new >> 32)),
|
||||||
"0"(old)
|
"0" (old)
|
||||||
: "memory");
|
: "memory");
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
|
static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
|
||||||
unsigned long long old,
|
|
||||||
unsigned long long new)
|
|
||||||
{
|
{
|
||||||
unsigned long long prev;
|
u64 prev;
|
||||||
asm volatile("cmpxchg8b %3"
|
asm volatile("cmpxchg8b %1"
|
||||||
: "=A"(prev)
|
: "=A" (prev),
|
||||||
: "b"((unsigned long)new),
|
"+m" (*ptr)
|
||||||
"c"((unsigned long)(new >> 32)),
|
: "b" ((u32)new),
|
||||||
"m"(*__xg(ptr)),
|
"c" ((u32)(new >> 32)),
|
||||||
"0"(old)
|
"0" (old)
|
||||||
: "memory");
|
: "memory");
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
@ -264,8 +246,6 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
|
||||||
* to simulate the cmpxchg8b on the 80386 and 80486 CPU.
|
* to simulate the cmpxchg8b on the 80386 and 80486 CPU.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
|
|
||||||
|
|
||||||
#define cmpxchg64(ptr, o, n) \
|
#define cmpxchg64(ptr, o, n) \
|
||||||
({ \
|
({ \
|
||||||
__typeof__(*(ptr)) __ret; \
|
__typeof__(*(ptr)) __ret; \
|
||||||
|
@ -283,20 +263,20 @@ extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
|
||||||
__ret; })
|
__ret; })
|
||||||
|
|
||||||
|
|
||||||
|
#define cmpxchg64_local(ptr, o, n) \
|
||||||
#define cmpxchg64_local(ptr, o, n) \
|
({ \
|
||||||
({ \
|
__typeof__(*(ptr)) __ret; \
|
||||||
__typeof__(*(ptr)) __ret; \
|
__typeof__(*(ptr)) __old = (o); \
|
||||||
if (likely(boot_cpu_data.x86 > 4)) \
|
__typeof__(*(ptr)) __new = (n); \
|
||||||
__ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr), \
|
alternative_io("call cmpxchg8b_emu", \
|
||||||
(unsigned long long)(o), \
|
"cmpxchg8b (%%esi)" , \
|
||||||
(unsigned long long)(n)); \
|
X86_FEATURE_CX8, \
|
||||||
else \
|
"=A" (__ret), \
|
||||||
__ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr), \
|
"S" ((ptr)), "0" (__old), \
|
||||||
(unsigned long long)(o), \
|
"b" ((unsigned int)__new), \
|
||||||
(unsigned long long)(n)); \
|
"c" ((unsigned int)(__new>>32)) \
|
||||||
__ret; \
|
: "memory"); \
|
||||||
})
|
__ret; })
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -3,51 +3,60 @@
|
||||||
|
|
||||||
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
|
#include <asm/alternative.h> /* Provides LOCK_PREFIX */
|
||||||
|
|
||||||
#define __xg(x) ((volatile long *)(x))
|
static inline void set_64bit(volatile u64 *ptr, u64 val)
|
||||||
|
|
||||||
static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
|
|
||||||
{
|
{
|
||||||
*ptr = val;
|
*ptr = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _set_64bit set_64bit
|
|
||||||
|
|
||||||
extern void __xchg_wrong_size(void);
|
extern void __xchg_wrong_size(void);
|
||||||
extern void __cmpxchg_wrong_size(void);
|
extern void __cmpxchg_wrong_size(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
|
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
|
||||||
* Note 2: xchg has side effect, so that attribute volatile is necessary,
|
* Since this is generally used to protect other memory information, we
|
||||||
* but generally the primitive is invalid, *ptr is output argument. --ANK
|
* use "asm volatile" and "memory" clobbers to prevent gcc from moving
|
||||||
|
* information around.
|
||||||
*/
|
*/
|
||||||
#define __xchg(x, ptr, size) \
|
#define __xchg(x, ptr, size) \
|
||||||
({ \
|
({ \
|
||||||
__typeof(*(ptr)) __x = (x); \
|
__typeof(*(ptr)) __x = (x); \
|
||||||
switch (size) { \
|
switch (size) { \
|
||||||
case 1: \
|
case 1: \
|
||||||
asm volatile("xchgb %b0,%1" \
|
{ \
|
||||||
: "=q" (__x) \
|
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
asm volatile("xchgb %0,%1" \
|
||||||
|
: "=q" (__x), "+m" (*__ptr) \
|
||||||
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 2: \
|
case 2: \
|
||||||
asm volatile("xchgw %w0,%1" \
|
{ \
|
||||||
: "=r" (__x) \
|
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
asm volatile("xchgw %0,%1" \
|
||||||
|
: "=r" (__x), "+m" (*__ptr) \
|
||||||
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 4: \
|
case 4: \
|
||||||
asm volatile("xchgl %k0,%1" \
|
{ \
|
||||||
: "=r" (__x) \
|
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
asm volatile("xchgl %0,%1" \
|
||||||
|
: "=r" (__x), "+m" (*__ptr) \
|
||||||
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 8: \
|
case 8: \
|
||||||
|
{ \
|
||||||
|
volatile u64 *__ptr = (volatile u64 *)(ptr); \
|
||||||
asm volatile("xchgq %0,%1" \
|
asm volatile("xchgq %0,%1" \
|
||||||
: "=r" (__x) \
|
: "=r" (__x), "+m" (*__ptr) \
|
||||||
: "m" (*__xg(ptr)), "0" (__x) \
|
: "0" (__x) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
default: \
|
default: \
|
||||||
__xchg_wrong_size(); \
|
__xchg_wrong_size(); \
|
||||||
} \
|
} \
|
||||||
|
@ -71,29 +80,41 @@ extern void __cmpxchg_wrong_size(void);
|
||||||
__typeof__(*(ptr)) __new = (new); \
|
__typeof__(*(ptr)) __new = (new); \
|
||||||
switch (size) { \
|
switch (size) { \
|
||||||
case 1: \
|
case 1: \
|
||||||
asm volatile(lock "cmpxchgb %b1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u8 *__ptr = (volatile u8 *)(ptr); \
|
||||||
: "q"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgb %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "q" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 2: \
|
case 2: \
|
||||||
asm volatile(lock "cmpxchgw %w1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u16 *__ptr = (volatile u16 *)(ptr); \
|
||||||
: "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgw %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "r" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 4: \
|
case 4: \
|
||||||
asm volatile(lock "cmpxchgl %k1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u32 *__ptr = (volatile u32 *)(ptr); \
|
||||||
: "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgl %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "r" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
case 8: \
|
case 8: \
|
||||||
asm volatile(lock "cmpxchgq %1,%2" \
|
{ \
|
||||||
: "=a"(__ret) \
|
volatile u64 *__ptr = (volatile u64 *)(ptr); \
|
||||||
: "r"(__new), "m"(*__xg(ptr)), "0"(__old) \
|
asm volatile(lock "cmpxchgq %2,%1" \
|
||||||
|
: "=a" (__ret), "+m" (*__ptr) \
|
||||||
|
: "r" (__new), "0" (__old) \
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
break; \
|
break; \
|
||||||
|
} \
|
||||||
default: \
|
default: \
|
||||||
__cmpxchg_wrong_size(); \
|
__cmpxchg_wrong_size(); \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -161,8 +161,6 @@
|
||||||
#define MSR_K7_FID_VID_STATUS 0xc0010042
|
#define MSR_K7_FID_VID_STATUS 0xc0010042
|
||||||
|
|
||||||
/* K6 MSRs */
|
/* K6 MSRs */
|
||||||
#define MSR_K6_EFER 0xc0000080
|
|
||||||
#define MSR_K6_STAR 0xc0000081
|
|
||||||
#define MSR_K6_WHCR 0xc0000082
|
#define MSR_K6_WHCR 0xc0000082
|
||||||
#define MSR_K6_UWCCR 0xc0000085
|
#define MSR_K6_UWCCR 0xc0000085
|
||||||
#define MSR_K6_EPMR 0xc0000086
|
#define MSR_K6_EPMR 0xc0000086
|
||||||
|
|
|
@ -104,7 +104,7 @@ _start:
|
||||||
movl %eax, %ecx
|
movl %eax, %ecx
|
||||||
orl %edx, %ecx
|
orl %edx, %ecx
|
||||||
jz 1f
|
jz 1f
|
||||||
movl $0xc0000080, %ecx
|
movl $MSR_EFER, %ecx
|
||||||
wrmsr
|
wrmsr
|
||||||
1:
|
1:
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ obj-y := intel_cacheinfo.o scattered.o topology.o
|
||||||
obj-y += proc.o capflags.o powerflags.o common.o
|
obj-y += proc.o capflags.o powerflags.o common.o
|
||||||
obj-y += vmware.o hypervisor.o sched.o mshyperv.o
|
obj-y += vmware.o hypervisor.o sched.o mshyperv.o
|
||||||
|
|
||||||
obj-$(CONFIG_X86_32) += bugs.o cmpxchg.o
|
obj-$(CONFIG_X86_32) += bugs.o
|
||||||
obj-$(CONFIG_X86_64) += bugs_64.o
|
obj-$(CONFIG_X86_64) += bugs_64.o
|
||||||
|
|
||||||
obj-$(CONFIG_CPU_SUP_INTEL) += intel.o
|
obj-$(CONFIG_CPU_SUP_INTEL) += intel.o
|
||||||
|
|
|
@ -611,14 +611,14 @@ ldt_ss:
|
||||||
* compensating for the offset by changing to the ESPFIX segment with
|
* compensating for the offset by changing to the ESPFIX segment with
|
||||||
* a base address that matches for the difference.
|
* a base address that matches for the difference.
|
||||||
*/
|
*/
|
||||||
|
#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8)
|
||||||
mov %esp, %edx /* load kernel esp */
|
mov %esp, %edx /* load kernel esp */
|
||||||
mov PT_OLDESP(%esp), %eax /* load userspace esp */
|
mov PT_OLDESP(%esp), %eax /* load userspace esp */
|
||||||
mov %dx, %ax /* eax: new kernel esp */
|
mov %dx, %ax /* eax: new kernel esp */
|
||||||
sub %eax, %edx /* offset (low word is 0) */
|
sub %eax, %edx /* offset (low word is 0) */
|
||||||
PER_CPU(gdt_page, %ebx)
|
|
||||||
shr $16, %edx
|
shr $16, %edx
|
||||||
mov %dl, GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx) /* bits 16..23 */
|
mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
|
||||||
mov %dh, GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx) /* bits 24..31 */
|
mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
|
||||||
pushl $__ESPFIX_SS
|
pushl $__ESPFIX_SS
|
||||||
CFI_ADJUST_CFA_OFFSET 4
|
CFI_ADJUST_CFA_OFFSET 4
|
||||||
push %eax /* new kernel esp */
|
push %eax /* new kernel esp */
|
||||||
|
@ -791,9 +791,8 @@ ptregs_clone:
|
||||||
* normal stack and adjusts ESP with the matching offset.
|
* normal stack and adjusts ESP with the matching offset.
|
||||||
*/
|
*/
|
||||||
/* fixup the stack */
|
/* fixup the stack */
|
||||||
PER_CPU(gdt_page, %ebx)
|
mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
|
||||||
mov GDT_ENTRY_ESPFIX_SS * 8 + 4(%ebx), %al /* bits 16..23 */
|
mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
|
||||||
mov GDT_ENTRY_ESPFIX_SS * 8 + 7(%ebx), %ah /* bits 24..31 */
|
|
||||||
shl $16, %eax
|
shl $16, %eax
|
||||||
addl %esp, %eax /* the adjusted stack pointer */
|
addl %esp, %eax /* the adjusted stack pointer */
|
||||||
pushl $__KERNEL_DS
|
pushl $__KERNEL_DS
|
||||||
|
|
|
@ -1065,6 +1065,7 @@ ENTRY(\sym)
|
||||||
END(\sym)
|
END(\sym)
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
|
||||||
.macro paranoidzeroentry_ist sym do_sym ist
|
.macro paranoidzeroentry_ist sym do_sym ist
|
||||||
ENTRY(\sym)
|
ENTRY(\sym)
|
||||||
INTR_FRAME
|
INTR_FRAME
|
||||||
|
@ -1076,10 +1077,9 @@ ENTRY(\sym)
|
||||||
TRACE_IRQS_OFF
|
TRACE_IRQS_OFF
|
||||||
movq %rsp,%rdi /* pt_regs pointer */
|
movq %rsp,%rdi /* pt_regs pointer */
|
||||||
xorl %esi,%esi /* no error code */
|
xorl %esi,%esi /* no error code */
|
||||||
PER_CPU(init_tss, %r12)
|
subq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
|
||||||
subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
|
|
||||||
call \do_sym
|
call \do_sym
|
||||||
addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%r12)
|
addq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
|
||||||
jmp paranoid_exit /* %ebx: no swapgs flag */
|
jmp paranoid_exit /* %ebx: no swapgs flag */
|
||||||
CFI_ENDPROC
|
CFI_ENDPROC
|
||||||
END(\sym)
|
END(\sym)
|
||||||
|
|
|
@ -234,9 +234,8 @@ ENTRY(secondary_startup_64)
|
||||||
* init data section till per cpu areas are set up.
|
* init data section till per cpu areas are set up.
|
||||||
*/
|
*/
|
||||||
movl $MSR_GS_BASE,%ecx
|
movl $MSR_GS_BASE,%ecx
|
||||||
movq initial_gs(%rip),%rax
|
movl initial_gs(%rip),%eax
|
||||||
movq %rax,%rdx
|
movl initial_gs+4(%rip),%edx
|
||||||
shrq $32,%rdx
|
|
||||||
wrmsr
|
wrmsr
|
||||||
|
|
||||||
/* esi is pointer to real mode structure with interesting info.
|
/* esi is pointer to real mode structure with interesting info.
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
|
#include <asm/msr-index.h>
|
||||||
|
|
||||||
verify_cpu:
|
verify_cpu:
|
||||||
pushfl # Save caller passed flags
|
pushfl # Save caller passed flags
|
||||||
|
@ -88,7 +89,7 @@ verify_cpu_sse_test:
|
||||||
je verify_cpu_sse_ok
|
je verify_cpu_sse_ok
|
||||||
test %di,%di
|
test %di,%di
|
||||||
jz verify_cpu_no_longmode # only try to force SSE on AMD
|
jz verify_cpu_no_longmode # only try to force SSE on AMD
|
||||||
movl $0xc0010015,%ecx # HWCR
|
movl $MSR_K7_HWCR,%ecx
|
||||||
rdmsr
|
rdmsr
|
||||||
btr $15,%eax # enable SSE
|
btr $15,%eax # enable SSE
|
||||||
wrmsr
|
wrmsr
|
||||||
|
|
|
@ -131,7 +131,7 @@ static struct svm_direct_access_msrs {
|
||||||
u32 index; /* Index of the MSR */
|
u32 index; /* Index of the MSR */
|
||||||
bool always; /* True if intercept is always on */
|
bool always; /* True if intercept is always on */
|
||||||
} direct_access_msrs[] = {
|
} direct_access_msrs[] = {
|
||||||
{ .index = MSR_K6_STAR, .always = true },
|
{ .index = MSR_STAR, .always = true },
|
||||||
{ .index = MSR_IA32_SYSENTER_CS, .always = true },
|
{ .index = MSR_IA32_SYSENTER_CS, .always = true },
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
{ .index = MSR_GS_BASE, .always = true },
|
{ .index = MSR_GS_BASE, .always = true },
|
||||||
|
@ -2432,7 +2432,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
|
||||||
*data = tsc_offset + native_read_tsc();
|
*data = tsc_offset + native_read_tsc();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_K6_STAR:
|
case MSR_STAR:
|
||||||
*data = svm->vmcb->save.star;
|
*data = svm->vmcb->save.star;
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
@ -2556,7 +2556,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_K6_STAR:
|
case MSR_STAR:
|
||||||
svm->vmcb->save.star = data;
|
svm->vmcb->save.star = data;
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
|
|
@ -240,14 +240,14 @@ static u64 host_efer;
|
||||||
static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
|
static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
|
* Keep MSR_STAR at the end, as setup_msrs() will try to optimize it
|
||||||
* away by decrementing the array size.
|
* away by decrementing the array size.
|
||||||
*/
|
*/
|
||||||
static const u32 vmx_msr_index[] = {
|
static const u32 vmx_msr_index[] = {
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
|
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
|
||||||
#endif
|
#endif
|
||||||
MSR_EFER, MSR_TSC_AUX, MSR_K6_STAR,
|
MSR_EFER, MSR_TSC_AUX, MSR_STAR,
|
||||||
};
|
};
|
||||||
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
|
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
|
||||||
|
|
||||||
|
@ -1117,10 +1117,10 @@ static void setup_msrs(struct vcpu_vmx *vmx)
|
||||||
if (index >= 0 && vmx->rdtscp_enabled)
|
if (index >= 0 && vmx->rdtscp_enabled)
|
||||||
move_msr_up(vmx, index, save_nmsrs++);
|
move_msr_up(vmx, index, save_nmsrs++);
|
||||||
/*
|
/*
|
||||||
* MSR_K6_STAR is only needed on long mode guests, and only
|
* MSR_STAR is only needed on long mode guests, and only
|
||||||
* if efer.sce is enabled.
|
* if efer.sce is enabled.
|
||||||
*/
|
*/
|
||||||
index = __find_msr_index(vmx, MSR_K6_STAR);
|
index = __find_msr_index(vmx, MSR_STAR);
|
||||||
if ((index >= 0) && (vmx->vcpu.arch.efer & EFER_SCE))
|
if ((index >= 0) && (vmx->vcpu.arch.efer & EFER_SCE))
|
||||||
move_msr_up(vmx, index, save_nmsrs++);
|
move_msr_up(vmx, index, save_nmsrs++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -733,7 +733,7 @@ static u32 msrs_to_save[] = {
|
||||||
HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
|
HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
|
||||||
HV_X64_MSR_APIC_ASSIST_PAGE,
|
HV_X64_MSR_APIC_ASSIST_PAGE,
|
||||||
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
|
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
|
||||||
MSR_K6_STAR,
|
MSR_STAR,
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
|
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,7 @@ ifeq ($(CONFIG_X86_32),y)
|
||||||
lib-y += checksum_32.o
|
lib-y += checksum_32.o
|
||||||
lib-y += strstr_32.o
|
lib-y += strstr_32.o
|
||||||
lib-y += semaphore_32.o string_32.o
|
lib-y += semaphore_32.o string_32.o
|
||||||
|
lib-y += cmpxchg.o
|
||||||
ifneq ($(CONFIG_X86_CMPXCHG64),y)
|
ifneq ($(CONFIG_X86_CMPXCHG64),y)
|
||||||
lib-y += cmpxchg8b_emu.o atomic64_386_32.o
|
lib-y += cmpxchg8b_emu.o atomic64_386_32.o
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -52,21 +52,3 @@ unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cmpxchg_386_u32);
|
EXPORT_SYMBOL(cmpxchg_386_u32);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_X86_CMPXCHG64
|
|
||||||
unsigned long long cmpxchg_486_u64(volatile void *ptr, u64 old, u64 new)
|
|
||||||
{
|
|
||||||
u64 prev;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Poor man's cmpxchg8b for 386 and 486. Unsuitable for SMP */
|
|
||||||
local_irq_save(flags);
|
|
||||||
prev = *(u64 *)ptr;
|
|
||||||
if (prev == old)
|
|
||||||
*(u64 *)ptr = new;
|
|
||||||
local_irq_restore(flags);
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(cmpxchg_486_u64);
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in New Issue