mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 07:34:12 +08:00
Merge branch 'x86/fpu' into x86/smap
Reason for merge: x86/fpu changed the structure of some of the code that x86/smap changes; mostly fpu-internal.h but also minor changes to the signal code. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Resolved Conflicts: arch/x86/ia32/ia32_signal.c arch/x86/include/asm/fpu-internal.h arch/x86/kernel/signal.c
This commit is contained in:
commit
49b8c695e3
@ -1837,6 +1837,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
and restore using xsave. The kernel will fallback to
|
||||
enabling legacy floating-point and sse state.
|
||||
|
||||
eagerfpu= [X86]
|
||||
on enable eager fpu restore
|
||||
off disable eager fpu restore
|
||||
auto selects the default scheme, which automatically
|
||||
enables eagerfpu restore for xsaveopt.
|
||||
|
||||
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
||||
wfi(ARM) instruction doesn't work correctly and not to
|
||||
use it. This is also useful when using JTAG debugger.
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <asm/sigframe.h>
|
||||
#include <asm/sighandling.h>
|
||||
#include <asm/sys_ia32.h>
|
||||
#include <asm/smap.h>
|
||||
|
||||
#define FIX_EFLAGS __FIX_EFLAGS
|
||||
|
||||
@ -162,7 +163,8 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
|
||||
}
|
||||
seg = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
|
||||
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
|
||||
(stack_t __force __user *) &uoss, regs->sp);
|
||||
set_fs(seg);
|
||||
if (ret >= 0 && uoss_ptr) {
|
||||
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
|
||||
@ -254,7 +256,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
||||
get_user_ex(*pax, &sc->ax);
|
||||
} get_user_catch(err);
|
||||
|
||||
err |= restore_i387_xstate_ia32(buf);
|
||||
err |= restore_xstate_sig(buf, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -362,7 +364,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
||||
*/
|
||||
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
size_t frame_size,
|
||||
void **fpstate)
|
||||
void __user **fpstate)
|
||||
{
|
||||
unsigned long sp;
|
||||
|
||||
@ -382,9 +384,12 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
sp = (unsigned long) ka->sa.sa_restorer;
|
||||
|
||||
if (used_math()) {
|
||||
sp = sp - sig_xstate_ia32_size;
|
||||
*fpstate = (struct _fpstate_ia32 *) sp;
|
||||
if (save_i387_xstate_ia32(*fpstate) < 0)
|
||||
unsigned long fx_aligned, math_size;
|
||||
|
||||
sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
|
||||
*fpstate = (struct _fpstate_ia32 __user *) sp;
|
||||
if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
|
||||
math_size) < 0)
|
||||
return (void __user *) -1L;
|
||||
}
|
||||
|
||||
@ -449,7 +454,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
||||
* These are actually not used anymore, but left because some
|
||||
* gdb versions depend on them as a marker.
|
||||
*/
|
||||
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
||||
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
||||
} put_user_catch(err);
|
||||
|
||||
if (err)
|
||||
@ -526,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
* Not actually used anymore, but left because some gdb
|
||||
* versions need it.
|
||||
*/
|
||||
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
||||
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
||||
} put_user_catch(err);
|
||||
|
||||
err |= copy_siginfo_to_user32(&frame->info, info);
|
||||
|
@ -287,7 +287,7 @@ asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
|
||||
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
|
||||
int options)
|
||||
{
|
||||
return compat_sys_wait4(pid, stat_addr, options, NULL);
|
||||
|
@ -97,6 +97,7 @@
|
||||
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
|
||||
#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
|
||||
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
|
||||
#define X86_FEATURE_EAGER_FPU (3*32+29) /* "eagerfpu" Non lazy FPU restore */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
|
||||
@ -300,12 +301,14 @@ extern const char * const x86_power_flags[32];
|
||||
#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2)
|
||||
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
|
||||
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
|
||||
#define cpu_has_xsaveopt boot_cpu_has(X86_FEATURE_XSAVEOPT)
|
||||
#define cpu_has_osxsave boot_cpu_has(X86_FEATURE_OSXSAVE)
|
||||
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
|
||||
#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
|
||||
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
|
||||
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
|
||||
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
||||
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
|
||||
|
||||
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
||||
# define cpu_has_invlpg 1
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/cpufeature.h>
|
||||
@ -20,43 +21,76 @@
|
||||
#include <asm/user.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/xsave.h>
|
||||
#include <asm/smap.h>
|
||||
|
||||
extern unsigned int sig_xstate_size;
|
||||
#ifdef CONFIG_X86_64
|
||||
# include <asm/sigcontext32.h>
|
||||
# include <asm/user32.h>
|
||||
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
compat_sigset_t *set, struct pt_regs *regs);
|
||||
int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
||||
compat_sigset_t *set, struct pt_regs *regs);
|
||||
#else
|
||||
# define user_i387_ia32_struct user_i387_struct
|
||||
# define user32_fxsr_struct user_fxsr_struct
|
||||
# define ia32_setup_frame __setup_frame
|
||||
# define ia32_setup_rt_frame __setup_rt_frame
|
||||
#endif
|
||||
|
||||
extern unsigned int mxcsr_feature_mask;
|
||||
extern void fpu_init(void);
|
||||
extern void eager_fpu_init(void);
|
||||
|
||||
DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
|
||||
|
||||
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
|
||||
struct task_struct *tsk);
|
||||
extern void convert_to_fxsr(struct task_struct *tsk,
|
||||
const struct user_i387_ia32_struct *env);
|
||||
|
||||
extern user_regset_active_fn fpregs_active, xfpregs_active;
|
||||
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
||||
xstateregs_get;
|
||||
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
|
||||
xstateregs_set;
|
||||
|
||||
|
||||
/*
|
||||
* xstateregs_active == fpregs_active. Please refer to the comment
|
||||
* at the definition of fpregs_active.
|
||||
*/
|
||||
#define xstateregs_active fpregs_active
|
||||
|
||||
extern struct _fpx_sw_bytes fx_sw_reserved;
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
extern unsigned int sig_xstate_ia32_size;
|
||||
extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
|
||||
struct _fpstate_ia32;
|
||||
struct _xstate_ia32;
|
||||
extern int save_i387_xstate_ia32(void __user *buf);
|
||||
extern int restore_i387_xstate_ia32(void __user *buf);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MATH_EMULATION
|
||||
# define HAVE_HWFP (boot_cpu_data.hard_math)
|
||||
extern void finit_soft_fpu(struct i387_soft_struct *soft);
|
||||
#else
|
||||
# define HAVE_HWFP 1
|
||||
static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
|
||||
#endif
|
||||
|
||||
static inline int is_ia32_compat_frame(void)
|
||||
{
|
||||
return config_enabled(CONFIG_IA32_EMULATION) &&
|
||||
test_thread_flag(TIF_IA32);
|
||||
}
|
||||
|
||||
static inline int is_ia32_frame(void)
|
||||
{
|
||||
return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
|
||||
}
|
||||
|
||||
static inline int is_x32_frame(void)
|
||||
{
|
||||
return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
|
||||
}
|
||||
|
||||
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
||||
|
||||
static __always_inline __pure bool use_eager_fpu(void)
|
||||
{
|
||||
return static_cpu_has(X86_FEATURE_EAGER_FPU);
|
||||
}
|
||||
|
||||
static __always_inline __pure bool use_xsaveopt(void)
|
||||
{
|
||||
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
||||
@ -72,6 +106,13 @@ static __always_inline __pure bool use_fxsr(void)
|
||||
return static_cpu_has(X86_FEATURE_FXSR);
|
||||
}
|
||||
|
||||
static inline void fx_finit(struct i387_fxsave_struct *fx)
|
||||
{
|
||||
memset(fx, 0, xstate_size);
|
||||
fx->cwd = 0x37f;
|
||||
fx->mxcsr = MXCSR_DEFAULT;
|
||||
}
|
||||
|
||||
extern void __sanitize_i387_state(struct task_struct *);
|
||||
|
||||
static inline void sanitize_i387_state(struct task_struct *tsk)
|
||||
@ -81,133 +122,104 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
|
||||
__sanitize_i387_state(tsk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
|
||||
{
|
||||
int err;
|
||||
#define user_insn(insn, output, input...) \
|
||||
({ \
|
||||
int err; \
|
||||
asm volatile(ASM_STAC "\n" \
|
||||
"1:" #insn "\n\t" \
|
||||
"2: " ASM_CLAC "\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: movl $-1,%[err]\n" \
|
||||
" jmp 2b\n" \
|
||||
".previous\n" \
|
||||
_ASM_EXTABLE(1b, 3b) \
|
||||
: [err] "=r" (err), output \
|
||||
: "0"(0), input); \
|
||||
err; \
|
||||
})
|
||||
|
||||
/* See comment in fxsave() below. */
|
||||
#ifdef CONFIG_AS_FXSAVEQ
|
||||
asm volatile("1: fxrstorq %[fx]\n\t"
|
||||
"2:\n"
|
||||
".section .fixup,\"ax\"\n"
|
||||
"3: movl $-1,%[err]\n"
|
||||
" jmp 2b\n"
|
||||
".previous\n"
|
||||
_ASM_EXTABLE(1b, 3b)
|
||||
: [err] "=r" (err)
|
||||
: [fx] "m" (*fx), "0" (0));
|
||||
#else
|
||||
asm volatile("1: rex64/fxrstor (%[fx])\n\t"
|
||||
"2:\n"
|
||||
".section .fixup,\"ax\"\n"
|
||||
"3: movl $-1,%[err]\n"
|
||||
" jmp 2b\n"
|
||||
".previous\n"
|
||||
_ASM_EXTABLE(1b, 3b)
|
||||
: [err] "=r" (err)
|
||||
: [fx] "R" (fx), "m" (*fx), "0" (0));
|
||||
#endif
|
||||
return err;
|
||||
#define check_insn(insn, output, input...) \
|
||||
({ \
|
||||
int err; \
|
||||
asm volatile("1:" #insn "\n\t" \
|
||||
"2:\n" \
|
||||
".section .fixup,\"ax\"\n" \
|
||||
"3: movl $-1,%[err]\n" \
|
||||
" jmp 2b\n" \
|
||||
".previous\n" \
|
||||
_ASM_EXTABLE(1b, 3b) \
|
||||
: [err] "=r" (err), output \
|
||||
: "0"(0), input); \
|
||||
err; \
|
||||
})
|
||||
|
||||
static inline int fsave_user(struct i387_fsave_struct __user *fx)
|
||||
{
|
||||
return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
|
||||
}
|
||||
|
||||
static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
|
||||
{
|
||||
int err;
|
||||
if (config_enabled(CONFIG_X86_32))
|
||||
return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
|
||||
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||
return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
|
||||
|
||||
/*
|
||||
* Clear the bytes not touched by the fxsave and reserved
|
||||
* for the SW usage.
|
||||
*/
|
||||
err = __clear_user(&fx->sw_reserved,
|
||||
sizeof(struct _fpx_sw_bytes));
|
||||
if (unlikely(err))
|
||||
return -EFAULT;
|
||||
|
||||
/* See comment in fxsave() below. */
|
||||
#ifdef CONFIG_AS_FXSAVEQ
|
||||
asm volatile(ASM_STAC "\n"
|
||||
"1: fxsaveq %[fx]\n\t"
|
||||
"2: " ASM_CLAC "\n"
|
||||
".section .fixup,\"ax\"\n"
|
||||
"3: movl $-1,%[err]\n"
|
||||
" jmp 2b\n"
|
||||
".previous\n"
|
||||
_ASM_EXTABLE(1b, 3b)
|
||||
: [err] "=r" (err), [fx] "=m" (*fx)
|
||||
: "0" (0));
|
||||
#else
|
||||
asm volatile(ASM_STAC "\n"
|
||||
"1: rex64/fxsave (%[fx])\n\t"
|
||||
"2: " ASM_CLAC "\n"
|
||||
".section .fixup,\"ax\"\n"
|
||||
"3: movl $-1,%[err]\n"
|
||||
" jmp 2b\n"
|
||||
".previous\n"
|
||||
_ASM_EXTABLE(1b, 3b)
|
||||
: [err] "=r" (err), "=m" (*fx)
|
||||
: [fx] "R" (fx), "0" (0));
|
||||
#endif
|
||||
if (unlikely(err) &&
|
||||
__clear_user(fx, sizeof(struct i387_fxsave_struct)))
|
||||
err = -EFAULT;
|
||||
/* No need to clear here because the caller clears USED_MATH */
|
||||
return err;
|
||||
/* See comment in fpu_fxsave() below. */
|
||||
return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
|
||||
}
|
||||
|
||||
static inline void fpu_fxsave(struct fpu *fpu)
|
||||
{
|
||||
/* Using "rex64; fxsave %0" is broken because, if the memory operand
|
||||
uses any extended registers for addressing, a second REX prefix
|
||||
will be generated (to the assembler, rex64 followed by semicolon
|
||||
is a separate instruction), and hence the 64-bitness is lost. */
|
||||
|
||||
#ifdef CONFIG_AS_FXSAVEQ
|
||||
/* Using "fxsaveq %0" would be the ideal choice, but is only supported
|
||||
starting with gas 2.16. */
|
||||
__asm__ __volatile__("fxsaveq %0"
|
||||
: "=m" (fpu->state->fxsave));
|
||||
#else
|
||||
/* Using, as a workaround, the properly prefixed form below isn't
|
||||
accepted by any binutils version so far released, complaining that
|
||||
the same type of prefix is used twice if an extended register is
|
||||
needed for addressing (fix submitted to mainline 2005-11-21).
|
||||
asm volatile("rex64/fxsave %0"
|
||||
: "=m" (fpu->state->fxsave));
|
||||
This, however, we can work around by forcing the compiler to select
|
||||
an addressing mode that doesn't require extended registers. */
|
||||
asm volatile("rex64/fxsave (%[fx])"
|
||||
: "=m" (fpu->state->fxsave)
|
||||
: [fx] "R" (&fpu->state->fxsave));
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* CONFIG_X86_32 */
|
||||
|
||||
/* perform fxrstor iff the processor has extended states, otherwise frstor */
|
||||
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
|
||||
{
|
||||
/*
|
||||
* The "nop" is needed to make the instructions the same
|
||||
* length.
|
||||
*/
|
||||
alternative_input(
|
||||
"nop ; frstor %1",
|
||||
"fxrstor %1",
|
||||
X86_FEATURE_FXSR,
|
||||
"m" (*fx));
|
||||
if (config_enabled(CONFIG_X86_32))
|
||||
return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||
return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||
|
||||
return 0;
|
||||
/* See comment in fpu_fxsave() below. */
|
||||
return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
|
||||
"m" (*fx));
|
||||
}
|
||||
|
||||
static inline int frstor_checking(struct i387_fsave_struct *fx)
|
||||
{
|
||||
return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||
}
|
||||
|
||||
static inline void fpu_fxsave(struct fpu *fpu)
|
||||
{
|
||||
asm volatile("fxsave %[fx]"
|
||||
: [fx] "=m" (fpu->state->fxsave));
|
||||
if (config_enabled(CONFIG_X86_32))
|
||||
asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
|
||||
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||
asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave));
|
||||
else {
|
||||
/* Using "rex64; fxsave %0" is broken because, if the memory
|
||||
* operand uses any extended registers for addressing, a second
|
||||
* REX prefix will be generated (to the assembler, rex64
|
||||
* followed by semicolon is a separate instruction), and hence
|
||||
* the 64-bitness is lost.
|
||||
*
|
||||
* Using "fxsaveq %0" would be the ideal choice, but is only
|
||||
* supported starting with gas 2.16.
|
||||
*
|
||||
* Using, as a workaround, the properly prefixed form below
|
||||
* isn't accepted by any binutils version so far released,
|
||||
* complaining that the same type of prefix is used twice if
|
||||
* an extended register is needed for addressing (fix submitted
|
||||
* to mainline 2005-11-21).
|
||||
*
|
||||
* asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
|
||||
*
|
||||
* This, however, we can work around by forcing the compiler to
|
||||
* select an addressing mode that doesn't require extended
|
||||
* registers.
|
||||
*/
|
||||
asm volatile( "rex64/fxsave (%[fx])"
|
||||
: "=m" (fpu->state->fxsave)
|
||||
: [fx] "R" (&fpu->state->fxsave));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
/*
|
||||
* These must be called with preempt disabled. Returns
|
||||
* 'true' if the FPU state is still intact.
|
||||
@ -250,17 +262,14 @@ static inline int __save_init_fpu(struct task_struct *tsk)
|
||||
return fpu_save_init(&tsk->thread.fpu);
|
||||
}
|
||||
|
||||
static inline int fpu_fxrstor_checking(struct fpu *fpu)
|
||||
{
|
||||
return fxrstor_checking(&fpu->state->fxsave);
|
||||
}
|
||||
|
||||
static inline int fpu_restore_checking(struct fpu *fpu)
|
||||
{
|
||||
if (use_xsave())
|
||||
return fpu_xrstor_checking(fpu);
|
||||
return fpu_xrstor_checking(&fpu->state->xsave);
|
||||
else if (use_fxsr())
|
||||
return fxrstor_checking(&fpu->state->fxsave);
|
||||
else
|
||||
return fpu_fxrstor_checking(fpu);
|
||||
return frstor_checking(&fpu->state->fsave);
|
||||
}
|
||||
|
||||
static inline int restore_fpu_checking(struct task_struct *tsk)
|
||||
@ -312,15 +321,52 @@ static inline void __thread_set_has_fpu(struct task_struct *tsk)
|
||||
static inline void __thread_fpu_end(struct task_struct *tsk)
|
||||
{
|
||||
__thread_clear_has_fpu(tsk);
|
||||
stts();
|
||||
if (!use_eager_fpu())
|
||||
stts();
|
||||
}
|
||||
|
||||
static inline void __thread_fpu_begin(struct task_struct *tsk)
|
||||
{
|
||||
clts();
|
||||
if (!use_eager_fpu())
|
||||
clts();
|
||||
__thread_set_has_fpu(tsk);
|
||||
}
|
||||
|
||||
static inline void __drop_fpu(struct task_struct *tsk)
|
||||
{
|
||||
if (__thread_has_fpu(tsk)) {
|
||||
/* Ignore delayed exceptions from user space */
|
||||
asm volatile("1: fwait\n"
|
||||
"2:\n"
|
||||
_ASM_EXTABLE(1b, 2b));
|
||||
__thread_fpu_end(tsk);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void drop_fpu(struct task_struct *tsk)
|
||||
{
|
||||
/*
|
||||
* Forget coprocessor state..
|
||||
*/
|
||||
preempt_disable();
|
||||
tsk->fpu_counter = 0;
|
||||
__drop_fpu(tsk);
|
||||
clear_used_math();
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void drop_init_fpu(struct task_struct *tsk)
|
||||
{
|
||||
if (!use_eager_fpu())
|
||||
drop_fpu(tsk);
|
||||
else {
|
||||
if (use_xsave())
|
||||
xrstor_state(init_xstate_buf, -1);
|
||||
else
|
||||
fxrstor_checking(&init_xstate_buf->i387);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FPU state switching for scheduling.
|
||||
*
|
||||
@ -354,7 +400,12 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
||||
{
|
||||
fpu_switch_t fpu;
|
||||
|
||||
fpu.preload = tsk_used_math(new) && new->fpu_counter > 5;
|
||||
/*
|
||||
* If the task has used the math, pre-load the FPU on xsave processors
|
||||
* or if the past 5 consecutive context-switches used math.
|
||||
*/
|
||||
fpu.preload = tsk_used_math(new) && (use_eager_fpu() ||
|
||||
new->fpu_counter > 5);
|
||||
if (__thread_has_fpu(old)) {
|
||||
if (!__save_init_fpu(old))
|
||||
cpu = ~0;
|
||||
@ -366,14 +417,14 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
||||
new->fpu_counter++;
|
||||
__thread_set_has_fpu(new);
|
||||
prefetch(new->thread.fpu.state);
|
||||
} else
|
||||
} else if (!use_eager_fpu())
|
||||
stts();
|
||||
} else {
|
||||
old->fpu_counter = 0;
|
||||
old->thread.fpu.last_cpu = ~0;
|
||||
if (fpu.preload) {
|
||||
new->fpu_counter++;
|
||||
if (fpu_lazy_restore(new, cpu))
|
||||
if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
|
||||
fpu.preload = 0;
|
||||
else
|
||||
prefetch(new->thread.fpu.state);
|
||||
@ -393,44 +444,40 @@ static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
|
||||
{
|
||||
if (fpu.preload) {
|
||||
if (unlikely(restore_fpu_checking(new)))
|
||||
__thread_fpu_end(new);
|
||||
drop_init_fpu(new);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal frame handlers...
|
||||
*/
|
||||
extern int save_i387_xstate(void __user *buf);
|
||||
extern int restore_i387_xstate(void __user *buf);
|
||||
extern int save_xstate_sig(void __user *buf, void __user *fx, int size);
|
||||
extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size);
|
||||
|
||||
static inline void __clear_fpu(struct task_struct *tsk)
|
||||
static inline int xstate_sigframe_size(void)
|
||||
{
|
||||
if (__thread_has_fpu(tsk)) {
|
||||
/* Ignore delayed exceptions from user space */
|
||||
asm volatile("1: fwait\n"
|
||||
"2:\n"
|
||||
_ASM_EXTABLE(1b, 2b));
|
||||
__thread_fpu_end(tsk);
|
||||
return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
|
||||
}
|
||||
|
||||
static inline int restore_xstate_sig(void __user *buf, int ia32_frame)
|
||||
{
|
||||
void __user *buf_fx = buf;
|
||||
int size = xstate_sigframe_size();
|
||||
|
||||
if (ia32_frame && use_fxsr()) {
|
||||
buf_fx = buf + sizeof(struct i387_fsave_struct);
|
||||
size += sizeof(struct i387_fsave_struct);
|
||||
}
|
||||
|
||||
return __restore_xstate_sig(buf, buf_fx, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* The actual user_fpu_begin/end() functions
|
||||
* need to be preemption-safe.
|
||||
* Need to be preemption-safe.
|
||||
*
|
||||
* NOTE! user_fpu_end() must be used only after you
|
||||
* have saved the FP state, and user_fpu_begin() must
|
||||
* be used only immediately before restoring it.
|
||||
* These functions do not do any save/restore on
|
||||
* their own.
|
||||
* NOTE! user_fpu_begin() must be used only immediately before restoring
|
||||
* it. This function does not do any save/restore on their own.
|
||||
*/
|
||||
static inline void user_fpu_end(void)
|
||||
{
|
||||
preempt_disable();
|
||||
__thread_fpu_end(current);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void user_fpu_begin(void)
|
||||
{
|
||||
preempt_disable();
|
||||
@ -439,25 +486,32 @@ static inline void user_fpu_begin(void)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void __save_fpu(struct task_struct *tsk)
|
||||
{
|
||||
if (use_xsave())
|
||||
xsave_state(&tsk->thread.fpu.state->xsave, -1);
|
||||
else
|
||||
fpu_fxsave(&tsk->thread.fpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* These disable preemption on their own and are safe
|
||||
*/
|
||||
static inline void save_init_fpu(struct task_struct *tsk)
|
||||
{
|
||||
WARN_ON_ONCE(!__thread_has_fpu(tsk));
|
||||
|
||||
if (use_eager_fpu()) {
|
||||
__save_fpu(tsk);
|
||||
return;
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
__save_init_fpu(tsk);
|
||||
__thread_fpu_end(tsk);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void clear_fpu(struct task_struct *tsk)
|
||||
{
|
||||
preempt_disable();
|
||||
__clear_fpu(tsk);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* i387 state interaction
|
||||
*/
|
||||
@ -512,11 +566,34 @@ static inline void fpu_free(struct fpu *fpu)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fpu_copy(struct fpu *dst, struct fpu *src)
|
||||
static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
|
||||
{
|
||||
memcpy(dst->state, src->state, xstate_size);
|
||||
if (use_eager_fpu()) {
|
||||
memset(&dst->thread.fpu.state->xsave, 0, xstate_size);
|
||||
__save_fpu(dst);
|
||||
} else {
|
||||
struct fpu *dfpu = &dst->thread.fpu;
|
||||
struct fpu *sfpu = &src->thread.fpu;
|
||||
|
||||
unlazy_fpu(src);
|
||||
memcpy(dfpu->state, sfpu->state, xstate_size);
|
||||
}
|
||||
}
|
||||
|
||||
extern void fpu_finit(struct fpu *fpu);
|
||||
static inline unsigned long
|
||||
alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx,
|
||||
unsigned long *size)
|
||||
{
|
||||
unsigned long frame_size = xstate_sigframe_size();
|
||||
|
||||
*buf_fx = sp = round_down(sp - frame_size, 64);
|
||||
if (ia32_frame && use_fxsr()) {
|
||||
frame_size += sizeof(struct i387_fsave_struct);
|
||||
sp -= sizeof(struct i387_fsave_struct);
|
||||
}
|
||||
|
||||
*size = frame_size;
|
||||
return sp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -19,12 +19,37 @@ struct pt_regs;
|
||||
struct user_i387_struct;
|
||||
|
||||
extern int init_fpu(struct task_struct *child);
|
||||
extern void fpu_finit(struct fpu *fpu);
|
||||
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
|
||||
extern void math_state_restore(void);
|
||||
|
||||
extern bool irq_fpu_usable(void);
|
||||
extern void kernel_fpu_begin(void);
|
||||
extern void kernel_fpu_end(void);
|
||||
|
||||
/*
|
||||
* Careful: __kernel_fpu_begin/end() must be called with preempt disabled
|
||||
* and they don't touch the preempt state on their own.
|
||||
* If you enable preemption after __kernel_fpu_begin(), preempt notifier
|
||||
* should call the __kernel_fpu_end() to prevent the kernel/user FPU
|
||||
* state from getting corrupted. KVM for example uses this model.
|
||||
*
|
||||
* All other cases use kernel_fpu_begin/end() which disable preemption
|
||||
* during kernel FPU usage.
|
||||
*/
|
||||
extern void __kernel_fpu_begin(void);
|
||||
extern void __kernel_fpu_end(void);
|
||||
|
||||
static inline void kernel_fpu_begin(void)
|
||||
{
|
||||
WARN_ON_ONCE(!irq_fpu_usable());
|
||||
preempt_disable();
|
||||
__kernel_fpu_begin();
|
||||
}
|
||||
|
||||
static inline void kernel_fpu_end(void)
|
||||
{
|
||||
__kernel_fpu_end();
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Some instructions like VIA's padlock instructions generate a spurious
|
||||
|
@ -48,7 +48,7 @@ struct iommu_table_entry {
|
||||
|
||||
|
||||
#define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
|
||||
static const struct iommu_table_entry const \
|
||||
static const struct iommu_table_entry \
|
||||
__iommu_entry_##_detect __used \
|
||||
__attribute__ ((unused, __section__(".iommu_table"), \
|
||||
aligned((sizeof(void *))))) \
|
||||
@ -63,10 +63,10 @@ struct iommu_table_entry {
|
||||
* to stop detecting the other IOMMUs after yours has been detected.
|
||||
*/
|
||||
#define IOMMU_INIT_POST(_detect) \
|
||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 0)
|
||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 0)
|
||||
|
||||
#define IOMMU_INIT_POST_FINISH(detect) \
|
||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 1)
|
||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 1)
|
||||
|
||||
/*
|
||||
* A more sophisticated version of IOMMU_INIT. This variant requires:
|
||||
|
@ -31,6 +31,10 @@ typedef struct {
|
||||
unsigned long sig[_NSIG_WORDS];
|
||||
} sigset_t;
|
||||
|
||||
#ifndef CONFIG_COMPAT
|
||||
typedef sigset_t compat_sigset_t;
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* Here we must cater to libcs that poke about in kernel headers. */
|
||||
|
||||
|
@ -40,7 +40,7 @@ asmlinkage long sys32_sigaction(int, struct old_sigaction32 __user *,
|
||||
struct old_sigaction32 __user *);
|
||||
asmlinkage long sys32_alarm(unsigned int);
|
||||
|
||||
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int *, int);
|
||||
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
|
||||
asmlinkage long sys32_sysfs(int, u32, u32);
|
||||
|
||||
asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
|
||||
|
@ -11,7 +11,8 @@ extern const char VDSO32_PRELINK[];
|
||||
#define VDSO32_SYMBOL(base, name) \
|
||||
({ \
|
||||
extern const char VDSO32_##name[]; \
|
||||
(void *)(VDSO32_##name - VDSO32_PRELINK + (unsigned long)(base)); \
|
||||
(void __user *)(VDSO32_##name - VDSO32_PRELINK + \
|
||||
(unsigned long)(base)); \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
@ -534,38 +534,6 @@ static struct xor_block_template xor_block_p5_mmx = {
|
||||
* Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
|
||||
*/
|
||||
|
||||
#define XMMS_SAVE \
|
||||
do { \
|
||||
preempt_disable(); \
|
||||
cr0 = read_cr0(); \
|
||||
clts(); \
|
||||
asm volatile( \
|
||||
"movups %%xmm0,(%0) ;\n\t" \
|
||||
"movups %%xmm1,0x10(%0) ;\n\t" \
|
||||
"movups %%xmm2,0x20(%0) ;\n\t" \
|
||||
"movups %%xmm3,0x30(%0) ;\n\t" \
|
||||
: \
|
||||
: "r" (xmm_save) \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#define XMMS_RESTORE \
|
||||
do { \
|
||||
asm volatile( \
|
||||
"sfence ;\n\t" \
|
||||
"movups (%0),%%xmm0 ;\n\t" \
|
||||
"movups 0x10(%0),%%xmm1 ;\n\t" \
|
||||
"movups 0x20(%0),%%xmm2 ;\n\t" \
|
||||
"movups 0x30(%0),%%xmm3 ;\n\t" \
|
||||
: \
|
||||
: "r" (xmm_save) \
|
||||
: "memory"); \
|
||||
write_cr0(cr0); \
|
||||
preempt_enable(); \
|
||||
} while (0)
|
||||
|
||||
#define ALIGN16 __attribute__((aligned(16)))
|
||||
|
||||
#define OFFS(x) "16*("#x")"
|
||||
#define PF_OFFS(x) "256+16*("#x")"
|
||||
#define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n"
|
||||
@ -587,10 +555,8 @@ static void
|
||||
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||
{
|
||||
unsigned long lines = bytes >> 8;
|
||||
char xmm_save[16*4] ALIGN16;
|
||||
int cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -633,7 +599,7 @@ xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -641,10 +607,8 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3)
|
||||
{
|
||||
unsigned long lines = bytes >> 8;
|
||||
char xmm_save[16*4] ALIGN16;
|
||||
int cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -694,7 +658,7 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
:
|
||||
: "memory" );
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -702,10 +666,8 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3, unsigned long *p4)
|
||||
{
|
||||
unsigned long lines = bytes >> 8;
|
||||
char xmm_save[16*4] ALIGN16;
|
||||
int cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -762,7 +724,7 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
:
|
||||
: "memory" );
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -770,10 +732,8 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
||||
{
|
||||
unsigned long lines = bytes >> 8;
|
||||
char xmm_save[16*4] ALIGN16;
|
||||
int cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
/* Make sure GCC forgets anything it knows about p4 or p5,
|
||||
such that it won't pass to the asm volatile below a
|
||||
@ -850,7 +810,7 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
like assuming they have some legal value. */
|
||||
asm("" : "=r" (p4), "=r" (p5));
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static struct xor_block_template xor_block_pIII_sse = {
|
||||
|
@ -34,41 +34,7 @@
|
||||
* no advantages to be gotten from x86-64 here anyways.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned long a, b;
|
||||
} __attribute__((aligned(16))) xmm_store_t;
|
||||
|
||||
/* Doesn't use gcc to save the XMM registers, because there is no easy way to
|
||||
tell it to do a clts before the register saving. */
|
||||
#define XMMS_SAVE \
|
||||
do { \
|
||||
preempt_disable(); \
|
||||
asm volatile( \
|
||||
"movq %%cr0,%0 ;\n\t" \
|
||||
"clts ;\n\t" \
|
||||
"movups %%xmm0,(%1) ;\n\t" \
|
||||
"movups %%xmm1,0x10(%1) ;\n\t" \
|
||||
"movups %%xmm2,0x20(%1) ;\n\t" \
|
||||
"movups %%xmm3,0x30(%1) ;\n\t" \
|
||||
: "=&r" (cr0) \
|
||||
: "r" (xmm_save) \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#define XMMS_RESTORE \
|
||||
do { \
|
||||
asm volatile( \
|
||||
"sfence ;\n\t" \
|
||||
"movups (%1),%%xmm0 ;\n\t" \
|
||||
"movups 0x10(%1),%%xmm1 ;\n\t" \
|
||||
"movups 0x20(%1),%%xmm2 ;\n\t" \
|
||||
"movups 0x30(%1),%%xmm3 ;\n\t" \
|
||||
"movq %0,%%cr0 ;\n\t" \
|
||||
: \
|
||||
: "r" (cr0), "r" (xmm_save) \
|
||||
: "memory"); \
|
||||
preempt_enable(); \
|
||||
} while (0)
|
||||
#include <asm/i387.h>
|
||||
|
||||
#define OFFS(x) "16*("#x")"
|
||||
#define PF_OFFS(x) "256+16*("#x")"
|
||||
@ -91,10 +57,8 @@ static void
|
||||
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||
{
|
||||
unsigned int lines = bytes >> 8;
|
||||
unsigned long cr0;
|
||||
xmm_store_t xmm_save[4];
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -135,7 +99,7 @@ xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||
: [inc] "r" (256UL)
|
||||
: "memory");
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -143,11 +107,8 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3)
|
||||
{
|
||||
unsigned int lines = bytes >> 8;
|
||||
xmm_store_t xmm_save[4];
|
||||
unsigned long cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
|
||||
kernel_fpu_begin();
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
#define BLOCK(i) \
|
||||
@ -194,7 +155,7 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
|
||||
: [inc] "r" (256UL)
|
||||
: "memory");
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -202,10 +163,8 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3, unsigned long *p4)
|
||||
{
|
||||
unsigned int lines = bytes >> 8;
|
||||
xmm_store_t xmm_save[4];
|
||||
unsigned long cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -261,7 +220,7 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
: [inc] "r" (256UL)
|
||||
: "memory" );
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -269,10 +228,8 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
||||
{
|
||||
unsigned int lines = bytes >> 8;
|
||||
xmm_store_t xmm_save[4];
|
||||
unsigned long cr0;
|
||||
|
||||
XMMS_SAVE;
|
||||
kernel_fpu_begin();
|
||||
|
||||
asm volatile(
|
||||
#undef BLOCK
|
||||
@ -336,7 +293,7 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||
: [inc] "r" (256UL)
|
||||
: "memory");
|
||||
|
||||
XMMS_RESTORE;
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static struct xor_block_template xor_block_sse = {
|
||||
|
@ -20,32 +20,6 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/i387.h>
|
||||
|
||||
#define ALIGN32 __aligned(32)
|
||||
|
||||
#define YMM_SAVED_REGS 4
|
||||
|
||||
#define YMMS_SAVE \
|
||||
do { \
|
||||
preempt_disable(); \
|
||||
cr0 = read_cr0(); \
|
||||
clts(); \
|
||||
asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
|
||||
asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
|
||||
asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
|
||||
asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
|
||||
} while (0);
|
||||
|
||||
#define YMMS_RESTORE \
|
||||
do { \
|
||||
asm volatile("sfence" : : : "memory"); \
|
||||
asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
|
||||
asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
|
||||
asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
|
||||
asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
|
||||
write_cr0(cr0); \
|
||||
preempt_enable(); \
|
||||
} while (0);
|
||||
|
||||
#define BLOCK4(i) \
|
||||
BLOCK(32 * i, 0) \
|
||||
BLOCK(32 * (i + 1), 1) \
|
||||
@ -60,10 +34,9 @@ do { \
|
||||
|
||||
static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
|
||||
{
|
||||
unsigned long cr0, lines = bytes >> 9;
|
||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
||||
unsigned long lines = bytes >> 9;
|
||||
|
||||
YMMS_SAVE
|
||||
kernel_fpu_begin();
|
||||
|
||||
while (lines--) {
|
||||
#undef BLOCK
|
||||
@ -82,16 +55,15 @@ do { \
|
||||
p1 = (unsigned long *)((uintptr_t)p1 + 512);
|
||||
}
|
||||
|
||||
YMMS_RESTORE
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||
unsigned long *p2)
|
||||
{
|
||||
unsigned long cr0, lines = bytes >> 9;
|
||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
||||
unsigned long lines = bytes >> 9;
|
||||
|
||||
YMMS_SAVE
|
||||
kernel_fpu_begin();
|
||||
|
||||
while (lines--) {
|
||||
#undef BLOCK
|
||||
@ -113,16 +85,15 @@ do { \
|
||||
p2 = (unsigned long *)((uintptr_t)p2 + 512);
|
||||
}
|
||||
|
||||
YMMS_RESTORE
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||
unsigned long *p2, unsigned long *p3)
|
||||
{
|
||||
unsigned long cr0, lines = bytes >> 9;
|
||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
||||
unsigned long lines = bytes >> 9;
|
||||
|
||||
YMMS_SAVE
|
||||
kernel_fpu_begin();
|
||||
|
||||
while (lines--) {
|
||||
#undef BLOCK
|
||||
@ -147,16 +118,15 @@ do { \
|
||||
p3 = (unsigned long *)((uintptr_t)p3 + 512);
|
||||
}
|
||||
|
||||
YMMS_RESTORE
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||
unsigned long *p2, unsigned long *p3, unsigned long *p4)
|
||||
{
|
||||
unsigned long cr0, lines = bytes >> 9;
|
||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
||||
unsigned long lines = bytes >> 9;
|
||||
|
||||
YMMS_SAVE
|
||||
kernel_fpu_begin();
|
||||
|
||||
while (lines--) {
|
||||
#undef BLOCK
|
||||
@ -184,7 +154,7 @@ do { \
|
||||
p4 = (unsigned long *)((uintptr_t)p4 + 512);
|
||||
}
|
||||
|
||||
YMMS_RESTORE
|
||||
kernel_fpu_end();
|
||||
}
|
||||
|
||||
static struct xor_block_template xor_block_avx = {
|
||||
|
@ -34,17 +34,14 @@
|
||||
extern unsigned int xstate_size;
|
||||
extern u64 pcntxt_mask;
|
||||
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
|
||||
extern struct xsave_struct *init_xstate_buf;
|
||||
|
||||
extern void xsave_init(void);
|
||||
extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
|
||||
extern int init_fpu(struct task_struct *child);
|
||||
extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
||||
void __user *fpstate,
|
||||
struct _fpx_sw_bytes *sw);
|
||||
|
||||
static inline int fpu_xrstor_checking(struct fpu *fpu)
|
||||
static inline int fpu_xrstor_checking(struct xsave_struct *fx)
|
||||
{
|
||||
struct xsave_struct *fx = &fpu->state->xsave;
|
||||
int err;
|
||||
|
||||
asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
|
||||
@ -69,8 +66,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
|
||||
* Clear the xsave header first, so that reserved fields are
|
||||
* initialized to zero.
|
||||
*/
|
||||
err = __clear_user(&buf->xsave_hdr,
|
||||
sizeof(struct xsave_hdr_struct));
|
||||
err = __clear_user(&buf->xsave_hdr, sizeof(buf->xsave_hdr));
|
||||
if (unlikely(err))
|
||||
return -EFAULT;
|
||||
|
||||
@ -85,9 +81,6 @@ static inline int xsave_user(struct xsave_struct __user *buf)
|
||||
: [err] "=r" (err)
|
||||
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
|
||||
: "memory");
|
||||
if (unlikely(err) && __clear_user(buf, xstate_size))
|
||||
err = -EFAULT;
|
||||
/* No need to clear here because the caller clears USED_MATH */
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -165,10 +165,15 @@ void __init check_bugs(void)
|
||||
print_cpu_info(&boot_cpu_data);
|
||||
#endif
|
||||
check_config();
|
||||
check_fpu();
|
||||
check_hlt();
|
||||
check_popad();
|
||||
init_utsname()->machine[1] =
|
||||
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
|
||||
alternative_instructions();
|
||||
|
||||
/*
|
||||
* kernel_fpu_begin/end() in check_fpu() relies on the patched
|
||||
* alternative instructions.
|
||||
*/
|
||||
check_fpu();
|
||||
}
|
||||
|
@ -1324,7 +1324,6 @@ void __cpuinit cpu_init(void)
|
||||
dbg_restore_debug_regs();
|
||||
|
||||
fpu_init();
|
||||
xsave_init();
|
||||
|
||||
raw_local_save_flags(kernel_eflags);
|
||||
|
||||
@ -1379,6 +1378,5 @@ void __cpuinit cpu_init(void)
|
||||
dbg_restore_debug_regs();
|
||||
|
||||
fpu_init();
|
||||
xsave_init();
|
||||
}
|
||||
#endif
|
||||
|
@ -19,24 +19,17 @@
|
||||
#include <asm/fpu-internal.h>
|
||||
#include <asm/user.h>
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
# include <asm/sigcontext32.h>
|
||||
# include <asm/user32.h>
|
||||
#else
|
||||
# define save_i387_xstate_ia32 save_i387_xstate
|
||||
# define restore_i387_xstate_ia32 restore_i387_xstate
|
||||
# define _fpstate_ia32 _fpstate
|
||||
# define _xstate_ia32 _xstate
|
||||
# define sig_xstate_ia32_size sig_xstate_size
|
||||
# define fx_sw_reserved_ia32 fx_sw_reserved
|
||||
# define user_i387_ia32_struct user_i387_struct
|
||||
# define user32_fxsr_struct user_fxsr_struct
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Were we in an interrupt that interrupted kernel mode?
|
||||
*
|
||||
* We can do a kernel_fpu_begin/end() pair *ONLY* if that
|
||||
* For now, with eagerfpu we will return interrupted kernel FPU
|
||||
* state as not-idle. TBD: Ideally we can change the return value
|
||||
* to something like __thread_has_fpu(current). But we need to
|
||||
* be careful of doing __thread_clear_has_fpu() before saving
|
||||
* the FPU etc for supporting nested uses etc. For now, take
|
||||
* the simple route!
|
||||
*
|
||||
* On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
|
||||
* pair does nothing at all: the thread must not have fpu (so
|
||||
* that we don't try to save the FPU state), and TS must
|
||||
* be set (so that the clts/stts pair does nothing that is
|
||||
@ -44,6 +37,9 @@
|
||||
*/
|
||||
static inline bool interrupted_kernel_fpu_idle(void)
|
||||
{
|
||||
if (use_eager_fpu())
|
||||
return 0;
|
||||
|
||||
return !__thread_has_fpu(current) &&
|
||||
(read_cr0() & X86_CR0_TS);
|
||||
}
|
||||
@ -77,29 +73,29 @@ bool irq_fpu_usable(void)
|
||||
}
|
||||
EXPORT_SYMBOL(irq_fpu_usable);
|
||||
|
||||
void kernel_fpu_begin(void)
|
||||
void __kernel_fpu_begin(void)
|
||||
{
|
||||
struct task_struct *me = current;
|
||||
|
||||
WARN_ON_ONCE(!irq_fpu_usable());
|
||||
preempt_disable();
|
||||
if (__thread_has_fpu(me)) {
|
||||
__save_init_fpu(me);
|
||||
__thread_clear_has_fpu(me);
|
||||
/* We do 'stts()' in kernel_fpu_end() */
|
||||
} else {
|
||||
/* We do 'stts()' in __kernel_fpu_end() */
|
||||
} else if (!use_eager_fpu()) {
|
||||
this_cpu_write(fpu_owner_task, NULL);
|
||||
clts();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_fpu_begin);
|
||||
EXPORT_SYMBOL(__kernel_fpu_begin);
|
||||
|
||||
void kernel_fpu_end(void)
|
||||
void __kernel_fpu_end(void)
|
||||
{
|
||||
stts();
|
||||
preempt_enable();
|
||||
if (use_eager_fpu())
|
||||
math_state_restore();
|
||||
else
|
||||
stts();
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_fpu_end);
|
||||
EXPORT_SYMBOL(__kernel_fpu_end);
|
||||
|
||||
void unlazy_fpu(struct task_struct *tsk)
|
||||
{
|
||||
@ -113,23 +109,15 @@ void unlazy_fpu(struct task_struct *tsk)
|
||||
}
|
||||
EXPORT_SYMBOL(unlazy_fpu);
|
||||
|
||||
#ifdef CONFIG_MATH_EMULATION
|
||||
# define HAVE_HWFP (boot_cpu_data.hard_math)
|
||||
#else
|
||||
# define HAVE_HWFP 1
|
||||
#endif
|
||||
|
||||
static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
|
||||
unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
|
||||
unsigned int xstate_size;
|
||||
EXPORT_SYMBOL_GPL(xstate_size);
|
||||
unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
|
||||
static struct i387_fxsave_struct fx_scratch __cpuinitdata;
|
||||
|
||||
static void __cpuinit mxcsr_feature_mask_init(void)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
|
||||
clts();
|
||||
if (cpu_has_fxsr) {
|
||||
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
|
||||
asm volatile("fxsave %0" : : "m" (fx_scratch));
|
||||
@ -138,7 +126,6 @@ static void __cpuinit mxcsr_feature_mask_init(void)
|
||||
mask = 0x0000ffbf;
|
||||
}
|
||||
mxcsr_feature_mask &= mask;
|
||||
stts();
|
||||
}
|
||||
|
||||
static void __cpuinit init_thread_xstate(void)
|
||||
@ -192,9 +179,8 @@ void __cpuinit fpu_init(void)
|
||||
init_thread_xstate();
|
||||
|
||||
mxcsr_feature_mask_init();
|
||||
/* clean state in init */
|
||||
current_thread_info()->status = 0;
|
||||
clear_used_math();
|
||||
xsave_init();
|
||||
eager_fpu_init();
|
||||
}
|
||||
|
||||
void fpu_finit(struct fpu *fpu)
|
||||
@ -205,12 +191,7 @@ void fpu_finit(struct fpu *fpu)
|
||||
}
|
||||
|
||||
if (cpu_has_fxsr) {
|
||||
struct i387_fxsave_struct *fx = &fpu->state->fxsave;
|
||||
|
||||
memset(fx, 0, xstate_size);
|
||||
fx->cwd = 0x37f;
|
||||
if (cpu_has_xmm)
|
||||
fx->mxcsr = MXCSR_DEFAULT;
|
||||
fx_finit(&fpu->state->fxsave);
|
||||
} else {
|
||||
struct i387_fsave_struct *fp = &fpu->state->fsave;
|
||||
memset(fp, 0, xstate_size);
|
||||
@ -454,7 +435,7 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
|
||||
* FXSR floating point environment conversions.
|
||||
*/
|
||||
|
||||
static void
|
||||
void
|
||||
convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
|
||||
{
|
||||
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
|
||||
@ -491,8 +472,8 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
|
||||
memcpy(&to[i], &from[i], sizeof(to[0]));
|
||||
}
|
||||
|
||||
static void convert_to_fxsr(struct task_struct *tsk,
|
||||
const struct user_i387_ia32_struct *env)
|
||||
void convert_to_fxsr(struct task_struct *tsk,
|
||||
const struct user_i387_ia32_struct *env)
|
||||
|
||||
{
|
||||
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
|
||||
@ -588,223 +569,6 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal frame handlers.
|
||||
*/
|
||||
|
||||
static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave;
|
||||
|
||||
fp->status = fp->swd;
|
||||
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
|
||||
struct user_i387_ia32_struct env;
|
||||
int err = 0;
|
||||
|
||||
convert_from_fxsr(&env, tsk);
|
||||
if (__copy_to_user(buf, &env, sizeof(env)))
|
||||
return -1;
|
||||
|
||||
err |= __put_user(fx->swd, &buf->status);
|
||||
err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int save_i387_xsave(void __user *buf)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct _fpstate_ia32 __user *fx = buf;
|
||||
int err = 0;
|
||||
|
||||
|
||||
sanitize_i387_state(tsk);
|
||||
|
||||
/*
|
||||
* For legacy compatible, we always set FP/SSE bits in the bit
|
||||
* vector while saving the state to the user context.
|
||||
* This will enable us capturing any changes(during sigreturn) to
|
||||
* the FP/SSE bits by the legacy applications which don't touch
|
||||
* xstate_bv in the xsave header.
|
||||
*
|
||||
* xsave aware applications can change the xstate_bv in the xsave
|
||||
* header as well as change any contents in the memory layout.
|
||||
* xrestore as part of sigreturn will capture all the changes.
|
||||
*/
|
||||
tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
|
||||
|
||||
if (save_i387_fxsave(fx) < 0)
|
||||
return -1;
|
||||
|
||||
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
|
||||
sizeof(struct _fpx_sw_bytes));
|
||||
err |= __put_user(FP_XSTATE_MAGIC2,
|
||||
(__u32 __user *) (buf + sig_xstate_ia32_size
|
||||
- FP_XSTATE_MAGIC2_SIZE));
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_i387_xstate_ia32(void __user *buf)
|
||||
{
|
||||
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
if (!used_math())
|
||||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
|
||||
return -EACCES;
|
||||
/*
|
||||
* This will cause a "finit" to be triggered by the next
|
||||
* attempted FPU operation by the 'current' process.
|
||||
*/
|
||||
clear_used_math();
|
||||
|
||||
if (!HAVE_HWFP) {
|
||||
return fpregs_soft_get(current, NULL,
|
||||
0, sizeof(struct user_i387_ia32_struct),
|
||||
NULL, fp) ? -1 : 1;
|
||||
}
|
||||
|
||||
unlazy_fpu(tsk);
|
||||
|
||||
if (cpu_has_xsave)
|
||||
return save_i387_xsave(fp);
|
||||
if (cpu_has_fxsr)
|
||||
return save_i387_fxsave(fp);
|
||||
else
|
||||
return save_i387_fsave(fp);
|
||||
}
|
||||
|
||||
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
return __copy_from_user(&tsk->thread.fpu.state->fsave, buf,
|
||||
sizeof(struct i387_fsave_struct));
|
||||
}
|
||||
|
||||
static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct user_i387_ia32_struct env;
|
||||
int err;
|
||||
|
||||
err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0],
|
||||
size);
|
||||
/* mxcsr reserved bits must be masked to zero for security reasons */
|
||||
tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
|
||||
if (err || __copy_from_user(&env, buf, sizeof(env)))
|
||||
return 1;
|
||||
convert_to_fxsr(tsk, &env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restore_i387_xsave(void __user *buf)
|
||||
{
|
||||
struct _fpx_sw_bytes fx_sw_user;
|
||||
struct _fpstate_ia32 __user *fx_user =
|
||||
((struct _fpstate_ia32 __user *) buf);
|
||||
struct i387_fxsave_struct __user *fx =
|
||||
(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
|
||||
struct xsave_hdr_struct *xsave_hdr =
|
||||
¤t->thread.fpu.state->xsave.xsave_hdr;
|
||||
u64 mask;
|
||||
int err;
|
||||
|
||||
if (check_for_xstate(fx, buf, &fx_sw_user))
|
||||
goto fx_only;
|
||||
|
||||
mask = fx_sw_user.xstate_bv;
|
||||
|
||||
err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
|
||||
|
||||
xsave_hdr->xstate_bv &= pcntxt_mask;
|
||||
/*
|
||||
* These bits must be zero.
|
||||
*/
|
||||
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
|
||||
|
||||
/*
|
||||
* Init the state that is not present in the memory layout
|
||||
* and enabled by the OS.
|
||||
*/
|
||||
mask = ~(pcntxt_mask & ~mask);
|
||||
xsave_hdr->xstate_bv &= mask;
|
||||
|
||||
return err;
|
||||
fx_only:
|
||||
/*
|
||||
* Couldn't find the extended state information in the memory
|
||||
* layout. Restore the FP/SSE and init the other extended state
|
||||
* enabled by the OS.
|
||||
*/
|
||||
xsave_hdr->xstate_bv = XSTATE_FPSSE;
|
||||
return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
|
||||
}
|
||||
|
||||
int restore_i387_xstate_ia32(void __user *buf)
|
||||
{
|
||||
int err;
|
||||
struct task_struct *tsk = current;
|
||||
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
||||
|
||||
if (HAVE_HWFP)
|
||||
clear_fpu(tsk);
|
||||
|
||||
if (!buf) {
|
||||
if (used_math()) {
|
||||
clear_fpu(tsk);
|
||||
clear_used_math();
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else
|
||||
if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
|
||||
return -EACCES;
|
||||
|
||||
if (!used_math()) {
|
||||
err = init_fpu(tsk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (HAVE_HWFP) {
|
||||
if (cpu_has_xsave)
|
||||
err = restore_i387_xsave(buf);
|
||||
else if (cpu_has_fxsr)
|
||||
err = restore_i387_fxsave(fp, sizeof(struct
|
||||
i387_fxsave_struct));
|
||||
else
|
||||
err = restore_i387_fsave(fp);
|
||||
} else {
|
||||
err = fpregs_soft_set(current, NULL,
|
||||
0, sizeof(struct user_i387_ia32_struct),
|
||||
NULL, fp) != 0;
|
||||
}
|
||||
set_used_math();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* FPU state for core dumps.
|
||||
* This is only used for a.out dumps now.
|
||||
|
@ -150,7 +150,7 @@ static struct resource *find_oprom(struct pci_dev *pdev)
|
||||
return oprom;
|
||||
}
|
||||
|
||||
void *pci_map_biosrom(struct pci_dev *pdev)
|
||||
void __iomem *pci_map_biosrom(struct pci_dev *pdev)
|
||||
{
|
||||
struct resource *oprom = find_oprom(pdev);
|
||||
|
||||
|
@ -66,15 +66,13 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||
{
|
||||
int ret;
|
||||
|
||||
unlazy_fpu(src);
|
||||
|
||||
*dst = *src;
|
||||
if (fpu_allocated(&src->thread.fpu)) {
|
||||
memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
|
||||
ret = fpu_alloc(&dst->thread.fpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
fpu_copy(&dst->thread.fpu, &src->thread.fpu);
|
||||
fpu_copy(dst, src);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -97,16 +95,6 @@ void arch_task_cache_init(void)
|
||||
SLAB_PANIC | SLAB_NOTRACK, NULL);
|
||||
}
|
||||
|
||||
static inline void drop_fpu(struct task_struct *tsk)
|
||||
{
|
||||
/*
|
||||
* Forget coprocessor state..
|
||||
*/
|
||||
tsk->fpu_counter = 0;
|
||||
clear_fpu(tsk);
|
||||
clear_used_math();
|
||||
}
|
||||
|
||||
/*
|
||||
* Free current thread data structures etc..
|
||||
*/
|
||||
@ -163,7 +151,13 @@ void flush_thread(void)
|
||||
|
||||
flush_ptrace_hw_breakpoint(tsk);
|
||||
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
|
||||
drop_fpu(tsk);
|
||||
drop_init_fpu(tsk);
|
||||
/*
|
||||
* Free the FPU state for non xsave platforms. They get reallocated
|
||||
* lazily at the first use.
|
||||
*/
|
||||
if (!use_eager_fpu())
|
||||
free_thread_xstate(tsk);
|
||||
}
|
||||
|
||||
static void hard_disable_TSC(void)
|
||||
|
@ -190,10 +190,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
|
||||
regs->cs = __USER_CS;
|
||||
regs->ip = new_ip;
|
||||
regs->sp = new_sp;
|
||||
/*
|
||||
* Free the old FP and other extended state
|
||||
*/
|
||||
free_thread_xstate(current);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(start_thread);
|
||||
|
||||
|
@ -232,10 +232,6 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
|
||||
regs->cs = _cs;
|
||||
regs->ss = _ss;
|
||||
regs->flags = X86_EFLAGS_IF;
|
||||
/*
|
||||
* Free the old FP and other extended state
|
||||
*/
|
||||
free_thread_xstate(current);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1332,9 +1332,6 @@ static const struct user_regset_view user_x86_64_view = {
|
||||
#define genregs32_get genregs_get
|
||||
#define genregs32_set genregs_set
|
||||
|
||||
#define user_i387_ia32_struct user_i387_struct
|
||||
#define user32_fxsr_struct user_fxsr_struct
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
|
||||
|
@ -118,7 +118,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||
get_user_ex(*pax, &sc->ax);
|
||||
} get_user_catch(err);
|
||||
|
||||
err |= restore_i387_xstate(buf);
|
||||
err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -207,35 +207,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
||||
void __user **fpstate)
|
||||
{
|
||||
/* Default to using normal stack */
|
||||
unsigned long math_size = 0;
|
||||
unsigned long sp = regs->sp;
|
||||
unsigned long buf_fx = 0;
|
||||
int onsigstack = on_sig_stack(sp);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* redzone */
|
||||
sp -= 128;
|
||||
#endif /* CONFIG_X86_64 */
|
||||
if (config_enabled(CONFIG_X86_64))
|
||||
sp -= 128;
|
||||
|
||||
if (!onsigstack) {
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (ka->sa.sa_flags & SA_ONSTACK) {
|
||||
if (current->sas_ss_size)
|
||||
sp = current->sas_ss_sp + current->sas_ss_size;
|
||||
} else {
|
||||
#ifdef CONFIG_X86_32
|
||||
/* This is the legacy signal stack switching. */
|
||||
if ((regs->ss & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||
ka->sa.sa_restorer)
|
||||
} else if (config_enabled(CONFIG_X86_32) &&
|
||||
(regs->ss & 0xffff) != __USER_DS &&
|
||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||
ka->sa.sa_restorer) {
|
||||
/* This is the legacy signal stack switching. */
|
||||
sp = (unsigned long) ka->sa.sa_restorer;
|
||||
#endif /* CONFIG_X86_32 */
|
||||
}
|
||||
}
|
||||
|
||||
if (used_math()) {
|
||||
sp -= sig_xstate_size;
|
||||
#ifdef CONFIG_X86_64
|
||||
sp = round_down(sp, 64);
|
||||
#endif /* CONFIG_X86_64 */
|
||||
sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
|
||||
&buf_fx, &math_size);
|
||||
*fpstate = (void __user *)sp;
|
||||
}
|
||||
|
||||
@ -248,8 +245,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
||||
if (onsigstack && !likely(on_sig_stack(sp)))
|
||||
return (void __user *)-1L;
|
||||
|
||||
/* save i387 state */
|
||||
if (used_math() && save_i387_xstate(*fpstate) < 0)
|
||||
/* save i387 and extended state */
|
||||
if (used_math() &&
|
||||
save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)
|
||||
return (void __user *)-1L;
|
||||
|
||||
return (void __user *)sp;
|
||||
@ -385,7 +383,7 @@ 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_catch(err);
|
||||
|
||||
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||
regs, set->sig[0]);
|
||||
@ -477,6 +475,75 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
}
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, compat_sigset_t *set,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
struct rt_sigframe_x32 __user *frame;
|
||||
void __user *restorer;
|
||||
int err = 0;
|
||||
void __user *fpstate = NULL;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
if (ka->sa.sa_flags & SA_SIGINFO) {
|
||||
if (copy_siginfo_to_user32(&frame->info, info))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
put_user_try {
|
||||
/* Create the ucontext. */
|
||||
if (cpu_has_xsave)
|
||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
||||
else
|
||||
put_user_ex(0, &frame->uc.uc_flags);
|
||||
put_user_ex(0, &frame->uc.uc_link);
|
||||
put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||
put_user_ex(sas_ss_flags(regs->sp),
|
||||
&frame->uc.uc_stack.ss_flags);
|
||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
put_user_ex(0, &frame->uc.uc__pad0);
|
||||
|
||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||
restorer = ka->sa.sa_restorer;
|
||||
} else {
|
||||
/* could use a vstub here */
|
||||
restorer = NULL;
|
||||
err |= -EFAULT;
|
||||
}
|
||||
put_user_ex(restorer, &frame->pretcode);
|
||||
} 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)
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
regs->sp = (unsigned long) frame;
|
||||
regs->ip = (unsigned long) ka->sa.sa_handler;
|
||||
|
||||
/* We use the x32 calling convention here... */
|
||||
regs->di = sig;
|
||||
regs->si = (unsigned long) &frame->info;
|
||||
regs->dx = (unsigned long) &frame->uc;
|
||||
|
||||
loadsegment(ds, __USER_DS);
|
||||
loadsegment(es, __USER_DS);
|
||||
|
||||
regs->cs = __USER_CS;
|
||||
regs->ss = __USER_DS;
|
||||
#endif /* CONFIG_X86_X32_ABI */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
* Atomically swap in the new signal mask, and wait for a signal.
|
||||
@ -615,55 +682,22 @@ static int signr_convert(int sig)
|
||||
return sig;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
#define is_ia32 1
|
||||
#define ia32_setup_frame __setup_frame
|
||||
#define ia32_setup_rt_frame __setup_rt_frame
|
||||
|
||||
#else /* !CONFIG_X86_32 */
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
#define is_ia32 test_thread_flag(TIF_IA32)
|
||||
#else /* !CONFIG_IA32_EMULATION */
|
||||
#define is_ia32 0
|
||||
#endif /* CONFIG_IA32_EMULATION */
|
||||
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
#define is_x32 test_thread_flag(TIF_X32)
|
||||
|
||||
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, compat_sigset_t *set,
|
||||
struct pt_regs *regs);
|
||||
#else /* !CONFIG_X86_X32_ABI */
|
||||
#define is_x32 0
|
||||
#endif /* CONFIG_X86_X32_ABI */
|
||||
|
||||
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
sigset_t *set, struct pt_regs *regs);
|
||||
int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
||||
sigset_t *set, struct pt_regs *regs);
|
||||
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
static int
|
||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
int usig = signr_convert(sig);
|
||||
sigset_t *set = sigmask_to_save();
|
||||
compat_sigset_t *cset = (compat_sigset_t *) set;
|
||||
|
||||
/* Set up the stack frame */
|
||||
if (is_ia32) {
|
||||
if (is_ia32_frame()) {
|
||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||
return ia32_setup_rt_frame(usig, ka, info, set, regs);
|
||||
return ia32_setup_rt_frame(usig, ka, info, cset, regs);
|
||||
else
|
||||
return ia32_setup_frame(usig, ka, set, regs);
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
} else if (is_x32) {
|
||||
return x32_setup_rt_frame(usig, ka, info,
|
||||
(compat_sigset_t *)set, regs);
|
||||
#endif
|
||||
return ia32_setup_frame(usig, ka, cset, regs);
|
||||
} else if (is_x32_frame()) {
|
||||
return x32_setup_rt_frame(usig, ka, info, cset, regs);
|
||||
} else {
|
||||
return __setup_rt_frame(sig, ka, info, set, regs);
|
||||
}
|
||||
@ -827,73 +861,6 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_X32_ABI
|
||||
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
||||
siginfo_t *info, compat_sigset_t *set,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct rt_sigframe_x32 __user *frame;
|
||||
void __user *restorer;
|
||||
int err = 0;
|
||||
void __user *fpstate = NULL;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||
return -EFAULT;
|
||||
|
||||
if (ka->sa.sa_flags & SA_SIGINFO) {
|
||||
if (copy_siginfo_to_user32(&frame->info, info))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
put_user_try {
|
||||
/* Create the ucontext. */
|
||||
if (cpu_has_xsave)
|
||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
||||
else
|
||||
put_user_ex(0, &frame->uc.uc_flags);
|
||||
put_user_ex(0, &frame->uc.uc_link);
|
||||
put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||
put_user_ex(sas_ss_flags(regs->sp),
|
||||
&frame->uc.uc_stack.ss_flags);
|
||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
put_user_ex(0, &frame->uc.uc__pad0);
|
||||
|
||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||
restorer = ka->sa.sa_restorer;
|
||||
} else {
|
||||
/* could use a vstub here */
|
||||
restorer = NULL;
|
||||
err |= -EFAULT;
|
||||
}
|
||||
put_user_ex(restorer, &frame->pretcode);
|
||||
} 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)
|
||||
return -EFAULT;
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
regs->sp = (unsigned long) frame;
|
||||
regs->ip = (unsigned long) ka->sa.sa_handler;
|
||||
|
||||
/* We use the x32 calling convention here... */
|
||||
regs->di = sig;
|
||||
regs->si = (unsigned long) &frame->info;
|
||||
regs->dx = (unsigned long) &frame->uc;
|
||||
|
||||
loadsegment(ds, __USER_DS);
|
||||
loadsegment(es, __USER_DS);
|
||||
|
||||
regs->cs = __USER_CS;
|
||||
regs->ss = __USER_DS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
|
||||
{
|
||||
struct rt_sigframe_x32 __user *frame;
|
||||
|
@ -613,11 +613,12 @@ void math_state_restore(void)
|
||||
}
|
||||
|
||||
__thread_fpu_begin(tsk);
|
||||
|
||||
/*
|
||||
* Paranoid restore. send a SIGSEGV if we fail to restore the state.
|
||||
*/
|
||||
if (unlikely(restore_fpu_checking(tsk))) {
|
||||
__thread_fpu_end(tsk);
|
||||
drop_init_fpu(tsk);
|
||||
force_sig(SIGSEGV, tsk);
|
||||
return;
|
||||
}
|
||||
@ -629,6 +630,8 @@ EXPORT_SYMBOL_GPL(math_state_restore);
|
||||
dotraplinkage void __kprobes
|
||||
do_device_not_available(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
BUG_ON(use_eager_fpu());
|
||||
|
||||
#ifdef CONFIG_MATH_EMULATION
|
||||
if (read_cr0() & X86_CR0_EM) {
|
||||
struct math_emu_info info = { };
|
||||
|
@ -10,9 +10,7 @@
|
||||
#include <linux/compat.h>
|
||||
#include <asm/i387.h>
|
||||
#include <asm/fpu-internal.h>
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
#include <asm/sigcontext32.h>
|
||||
#endif
|
||||
#include <asm/sigframe.h>
|
||||
#include <asm/xcr.h>
|
||||
|
||||
/*
|
||||
@ -23,13 +21,9 @@ u64 pcntxt_mask;
|
||||
/*
|
||||
* Represents init state for the supported extended state.
|
||||
*/
|
||||
static struct xsave_struct *init_xstate_buf;
|
||||
|
||||
struct _fpx_sw_bytes fx_sw_reserved;
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
struct _fpx_sw_bytes fx_sw_reserved_ia32;
|
||||
#endif
|
||||
struct xsave_struct *init_xstate_buf;
|
||||
|
||||
static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
|
||||
static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
|
||||
|
||||
/*
|
||||
@ -44,9 +38,9 @@ static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
|
||||
*/
|
||||
void __sanitize_i387_state(struct task_struct *tsk)
|
||||
{
|
||||
u64 xstate_bv;
|
||||
int feature_bit = 0x2;
|
||||
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
|
||||
int feature_bit = 0x2;
|
||||
u64 xstate_bv;
|
||||
|
||||
if (!fx)
|
||||
return;
|
||||
@ -104,213 +98,326 @@ void __sanitize_i387_state(struct task_struct *tsk)
|
||||
* Check for the presence of extended state information in the
|
||||
* user fpstate pointer in the sigcontext.
|
||||
*/
|
||||
int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
||||
void __user *fpstate,
|
||||
struct _fpx_sw_bytes *fx_sw_user)
|
||||
static inline int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
||||
void __user *fpstate,
|
||||
struct _fpx_sw_bytes *fx_sw)
|
||||
{
|
||||
int min_xstate_size = sizeof(struct i387_fxsave_struct) +
|
||||
sizeof(struct xsave_hdr_struct);
|
||||
unsigned int magic2;
|
||||
int err;
|
||||
|
||||
err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
|
||||
sizeof(struct _fpx_sw_bytes));
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* First Magic check failed.
|
||||
*/
|
||||
if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
|
||||
return -EINVAL;
|
||||
/* Check for the first magic field and other error scenarios. */
|
||||
if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
|
||||
fx_sw->xstate_size < min_xstate_size ||
|
||||
fx_sw->xstate_size > xstate_size ||
|
||||
fx_sw->xstate_size > fx_sw->extended_size)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Check for error scenarios.
|
||||
*/
|
||||
if (fx_sw_user->xstate_size < min_xstate_size ||
|
||||
fx_sw_user->xstate_size > xstate_size ||
|
||||
fx_sw_user->xstate_size > fx_sw_user->extended_size)
|
||||
return -EINVAL;
|
||||
|
||||
err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
|
||||
fx_sw_user->extended_size -
|
||||
FP_XSTATE_MAGIC2_SIZE));
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* Check for the presence of second magic word at the end of memory
|
||||
* layout. This detects the case where the user just copied the legacy
|
||||
* fpstate layout with out copying the extended state information
|
||||
* in the memory layout.
|
||||
*/
|
||||
if (magic2 != FP_XSTATE_MAGIC2)
|
||||
return -EFAULT;
|
||||
if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
|
||||
|| magic2 != FP_XSTATE_MAGIC2)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Signal frame handlers.
|
||||
*/
|
||||
|
||||
int save_i387_xstate(void __user *buf)
|
||||
static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
int err = 0;
|
||||
if (use_fxsr()) {
|
||||
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||
struct user_i387_ia32_struct env;
|
||||
struct _fpstate_ia32 __user *fp = buf;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
|
||||
return -EACCES;
|
||||
convert_from_fxsr(&env, tsk);
|
||||
|
||||
BUG_ON(sig_xstate_size < xstate_size);
|
||||
|
||||
if ((unsigned long)buf % 64)
|
||||
pr_err("%s: bad fpstate %p\n", __func__, buf);
|
||||
|
||||
if (!used_math())
|
||||
return 0;
|
||||
|
||||
if (user_has_fpu()) {
|
||||
if (use_xsave())
|
||||
err = xsave_user(buf);
|
||||
else
|
||||
err = fxsave_user(buf);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
user_fpu_end();
|
||||
if (__copy_to_user(buf, &env, sizeof(env)) ||
|
||||
__put_user(xsave->i387.swd, &fp->status) ||
|
||||
__put_user(X86_FXSR_MAGIC, &fp->magic))
|
||||
return -1;
|
||||
} else {
|
||||
sanitize_i387_state(tsk);
|
||||
if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave,
|
||||
xstate_size))
|
||||
struct i387_fsave_struct __user *fp = buf;
|
||||
u32 swd;
|
||||
if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
|
||||
return -1;
|
||||
}
|
||||
|
||||
clear_used_math(); /* trigger finit */
|
||||
|
||||
if (use_xsave()) {
|
||||
struct _fpstate __user *fx = buf;
|
||||
struct _xstate __user *x = buf;
|
||||
u64 xstate_bv;
|
||||
|
||||
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
|
||||
sizeof(struct _fpx_sw_bytes));
|
||||
|
||||
err |= __put_user(FP_XSTATE_MAGIC2,
|
||||
(__u32 __user *) (buf + sig_xstate_size
|
||||
- FP_XSTATE_MAGIC2_SIZE));
|
||||
|
||||
/*
|
||||
* Read the xstate_bv which we copied (directly from the cpu or
|
||||
* from the state in task struct) to the user buffers and
|
||||
* set the FP/SSE bits.
|
||||
*/
|
||||
err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
|
||||
|
||||
/*
|
||||
* For legacy compatible, we always set FP/SSE bits in the bit
|
||||
* vector while saving the state to the user context. This will
|
||||
* enable us capturing any changes(during sigreturn) to
|
||||
* the FP/SSE bits by the legacy applications which don't touch
|
||||
* xstate_bv in the xsave header.
|
||||
*
|
||||
* xsave aware apps can change the xstate_bv in the xsave
|
||||
* header as well as change any contents in the memory layout.
|
||||
* xrestore as part of sigreturn will capture all the changes.
|
||||
*/
|
||||
xstate_bv |= XSTATE_FPSSE;
|
||||
|
||||
err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the extended state if present. Otherwise, restore the FP/SSE
|
||||
* state.
|
||||
*/
|
||||
static int restore_user_xstate(void __user *buf)
|
||||
static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
|
||||
{
|
||||
struct _fpx_sw_bytes fx_sw_user;
|
||||
u64 mask;
|
||||
struct xsave_struct __user *x = buf;
|
||||
struct _fpx_sw_bytes *sw_bytes;
|
||||
u32 xstate_bv;
|
||||
int err;
|
||||
|
||||
if (((unsigned long)buf % 64) ||
|
||||
check_for_xstate(buf, buf, &fx_sw_user))
|
||||
goto fx_only;
|
||||
/* Setup the bytes not touched by the [f]xsave and reserved for SW. */
|
||||
sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
|
||||
err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
|
||||
|
||||
mask = fx_sw_user.xstate_bv;
|
||||
|
||||
/*
|
||||
* restore the state passed by the user.
|
||||
*/
|
||||
err = xrestore_user(buf, mask);
|
||||
if (err)
|
||||
if (!use_xsave())
|
||||
return err;
|
||||
|
||||
/*
|
||||
* init the state skipped by the user.
|
||||
*/
|
||||
mask = pcntxt_mask & ~mask;
|
||||
if (unlikely(mask))
|
||||
xrstor_state(init_xstate_buf, mask);
|
||||
err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
|
||||
|
||||
return 0;
|
||||
|
||||
fx_only:
|
||||
/*
|
||||
* couldn't find the extended state information in the
|
||||
* memory layout. Restore just the FP/SSE and init all
|
||||
* the other extended state.
|
||||
* Read the xstate_bv which we copied (directly from the cpu or
|
||||
* from the state in task struct) to the user buffers.
|
||||
*/
|
||||
xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
|
||||
return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
|
||||
err |= __get_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
|
||||
|
||||
/*
|
||||
* For legacy compatible, we always set FP/SSE bits in the bit
|
||||
* vector while saving the state to the user context. This will
|
||||
* enable us capturing any changes(during sigreturn) to
|
||||
* the FP/SSE bits by the legacy applications which don't touch
|
||||
* xstate_bv in the xsave header.
|
||||
*
|
||||
* xsave aware apps can change the xstate_bv in the xsave
|
||||
* header as well as change any contents in the memory layout.
|
||||
* xrestore as part of sigreturn will capture all the changes.
|
||||
*/
|
||||
xstate_bv |= XSTATE_FPSSE;
|
||||
|
||||
err |= __put_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int save_user_xstate(struct xsave_struct __user *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (use_xsave())
|
||||
err = xsave_user(buf);
|
||||
else if (use_fxsr())
|
||||
err = fxsave_user((struct i387_fxsave_struct __user *) buf);
|
||||
else
|
||||
err = fsave_user((struct i387_fsave_struct __user *) buf);
|
||||
|
||||
if (unlikely(err) && __clear_user(buf, xstate_size))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* This restores directly out of user space. Exceptions are handled.
|
||||
* Save the fpu, extended register state to the user signal frame.
|
||||
*
|
||||
* 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
|
||||
* state is copied.
|
||||
* 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
|
||||
*
|
||||
* buf == buf_fx for 64-bit frames and 32-bit fsave frame.
|
||||
* buf != buf_fx for 32-bit frames with fxstate.
|
||||
*
|
||||
* If the fpu, extended register state is live, save the state directly
|
||||
* to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
|
||||
* copy the thread's fpu state to the user frame starting at 'buf_fx'.
|
||||
*
|
||||
* If this is a 32-bit frame with fxstate, put a fsave header before
|
||||
* the aligned state at 'buf_fx'.
|
||||
*
|
||||
* For [f]xsave state, update the SW reserved fields in the [f]xsave frame
|
||||
* indicating the absence/presence of the extended state to the user.
|
||||
*/
|
||||
int restore_i387_xstate(void __user *buf)
|
||||
int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
|
||||
{
|
||||
struct xsave_struct *xsave = ¤t->thread.fpu.state->xsave;
|
||||
struct task_struct *tsk = current;
|
||||
int err = 0;
|
||||
int ia32_fxstate = (buf != buf_fx);
|
||||
|
||||
ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
|
||||
config_enabled(CONFIG_IA32_EMULATION));
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, buf, size))
|
||||
return -EACCES;
|
||||
|
||||
if (!HAVE_HWFP)
|
||||
return fpregs_soft_get(current, NULL, 0,
|
||||
sizeof(struct user_i387_ia32_struct), NULL,
|
||||
(struct _fpstate_ia32 __user *) buf) ? -1 : 1;
|
||||
|
||||
if (user_has_fpu()) {
|
||||
/* Save the live register state to the user directly. */
|
||||
if (save_user_xstate(buf_fx))
|
||||
return -1;
|
||||
/* Update the thread's fxstate to save the fsave header. */
|
||||
if (ia32_fxstate)
|
||||
fpu_fxsave(&tsk->thread.fpu);
|
||||
} else {
|
||||
sanitize_i387_state(tsk);
|
||||
if (__copy_to_user(buf_fx, xsave, xstate_size))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save the fsave header for the 32-bit frames. */
|
||||
if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
|
||||
return -1;
|
||||
|
||||
if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
|
||||
return -1;
|
||||
|
||||
drop_init_fpu(tsk); /* trigger finit */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
sanitize_restored_xstate(struct task_struct *tsk,
|
||||
struct user_i387_ia32_struct *ia32_env,
|
||||
u64 xstate_bv, int fx_only)
|
||||
{
|
||||
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||
struct xsave_hdr_struct *xsave_hdr = &xsave->xsave_hdr;
|
||||
|
||||
if (use_xsave()) {
|
||||
/* These bits must be zero. */
|
||||
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
|
||||
|
||||
/*
|
||||
* Init the state that is not present in the memory
|
||||
* layout and not enabled by the OS.
|
||||
*/
|
||||
if (fx_only)
|
||||
xsave_hdr->xstate_bv = XSTATE_FPSSE;
|
||||
else
|
||||
xsave_hdr->xstate_bv &= (pcntxt_mask & xstate_bv);
|
||||
}
|
||||
|
||||
if (use_fxsr()) {
|
||||
/*
|
||||
* mscsr reserved bits must be masked to zero for security
|
||||
* reasons.
|
||||
*/
|
||||
xsave->i387.mxcsr &= mxcsr_feature_mask;
|
||||
|
||||
convert_to_fxsr(tsk, ia32_env);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the extended state if present. Otherwise, restore the FP/SSE state.
|
||||
*/
|
||||
static inline int restore_user_xstate(void __user *buf, u64 xbv, int fx_only)
|
||||
{
|
||||
if (use_xsave()) {
|
||||
if ((unsigned long)buf % 64 || fx_only) {
|
||||
u64 init_bv = pcntxt_mask & ~XSTATE_FPSSE;
|
||||
xrstor_state(init_xstate_buf, init_bv);
|
||||
return fxrstor_checking((__force void *) buf);
|
||||
} else {
|
||||
u64 init_bv = pcntxt_mask & ~xbv;
|
||||
if (unlikely(init_bv))
|
||||
xrstor_state(init_xstate_buf, init_bv);
|
||||
return xrestore_user(buf, xbv);
|
||||
}
|
||||
} else if (use_fxsr()) {
|
||||
return fxrstor_checking((__force void *) buf);
|
||||
} else
|
||||
return frstor_checking((__force void *) buf);
|
||||
}
|
||||
|
||||
int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
|
||||
{
|
||||
int ia32_fxstate = (buf != buf_fx);
|
||||
struct task_struct *tsk = current;
|
||||
int state_size = xstate_size;
|
||||
u64 xstate_bv = 0;
|
||||
int fx_only = 0;
|
||||
|
||||
ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
|
||||
config_enabled(CONFIG_IA32_EMULATION));
|
||||
|
||||
if (!buf) {
|
||||
if (used_math())
|
||||
goto clear;
|
||||
drop_init_fpu(tsk);
|
||||
return 0;
|
||||
} else
|
||||
if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
|
||||
return -EACCES;
|
||||
|
||||
if (!used_math()) {
|
||||
err = init_fpu(tsk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
user_fpu_begin();
|
||||
if (use_xsave())
|
||||
err = restore_user_xstate(buf);
|
||||
else
|
||||
err = fxrstor_checking((__force struct i387_fxsave_struct *)
|
||||
buf);
|
||||
if (unlikely(err)) {
|
||||
if (!access_ok(VERIFY_READ, buf, size))
|
||||
return -EACCES;
|
||||
|
||||
if (!used_math() && init_fpu(tsk))
|
||||
return -1;
|
||||
|
||||
if (!HAVE_HWFP) {
|
||||
return fpregs_soft_set(current, NULL,
|
||||
0, sizeof(struct user_i387_ia32_struct),
|
||||
NULL, buf) != 0;
|
||||
}
|
||||
|
||||
if (use_xsave()) {
|
||||
struct _fpx_sw_bytes fx_sw_user;
|
||||
if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
|
||||
/*
|
||||
* Couldn't find the extended state information in the
|
||||
* memory layout. Restore just the FP/SSE and init all
|
||||
* the other extended state.
|
||||
*/
|
||||
state_size = sizeof(struct i387_fxsave_struct);
|
||||
fx_only = 1;
|
||||
} else {
|
||||
state_size = fx_sw_user.xstate_size;
|
||||
xstate_bv = fx_sw_user.xstate_bv;
|
||||
}
|
||||
}
|
||||
|
||||
if (ia32_fxstate) {
|
||||
/*
|
||||
* Encountered an error while doing the restore from the
|
||||
* user buffer, clear the fpu state.
|
||||
* For 32-bit frames with fxstate, copy the user state to the
|
||||
* thread's fpu state, reconstruct fxstate from the fsave
|
||||
* header. Sanitize the copied state etc.
|
||||
*/
|
||||
clear:
|
||||
clear_fpu(tsk);
|
||||
clear_used_math();
|
||||
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||
struct user_i387_ia32_struct env;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* Drop the current fpu which clears used_math(). This ensures
|
||||
* that any context-switch during the copy of the new state,
|
||||
* avoids the intermediate state from getting restored/saved.
|
||||
* Thus avoiding the new restored state from getting corrupted.
|
||||
* We will be ready to restore/save the state only after
|
||||
* set_used_math() is again set.
|
||||
*/
|
||||
drop_fpu(tsk);
|
||||
|
||||
if (__copy_from_user(xsave, buf_fx, state_size) ||
|
||||
__copy_from_user(&env, buf, sizeof(env))) {
|
||||
err = -1;
|
||||
} else {
|
||||
sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
|
||||
set_used_math();
|
||||
}
|
||||
|
||||
if (use_eager_fpu())
|
||||
math_state_restore();
|
||||
|
||||
return err;
|
||||
} else {
|
||||
/*
|
||||
* For 64-bit frames and 32-bit fsave frames, restore the user
|
||||
* state to the registers directly (with exceptions handled).
|
||||
*/
|
||||
user_fpu_begin();
|
||||
if (restore_user_xstate(buf_fx, xstate_bv, fx_only)) {
|
||||
drop_init_fpu(tsk);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prepare the SW reserved portion of the fxsave memory layout, indicating
|
||||
@ -321,31 +428,22 @@ clear:
|
||||
*/
|
||||
static void prepare_fx_sw_frame(void)
|
||||
{
|
||||
int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
|
||||
FP_XSTATE_MAGIC2_SIZE;
|
||||
int fsave_header_size = sizeof(struct i387_fsave_struct);
|
||||
int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
|
||||
|
||||
sig_xstate_size = sizeof(struct _fpstate) + size_extended;
|
||||
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
|
||||
#endif
|
||||
|
||||
memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
|
||||
if (config_enabled(CONFIG_X86_32))
|
||||
size += fsave_header_size;
|
||||
|
||||
fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
|
||||
fx_sw_reserved.extended_size = sig_xstate_size;
|
||||
fx_sw_reserved.extended_size = size;
|
||||
fx_sw_reserved.xstate_bv = pcntxt_mask;
|
||||
fx_sw_reserved.xstate_size = xstate_size;
|
||||
#ifdef CONFIG_IA32_EMULATION
|
||||
memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
|
||||
sizeof(struct _fpx_sw_bytes));
|
||||
fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
unsigned int sig_xstate_size = sizeof(struct _fpstate);
|
||||
#endif
|
||||
if (config_enabled(CONFIG_IA32_EMULATION)) {
|
||||
fx_sw_reserved_ia32 = fx_sw_reserved;
|
||||
fx_sw_reserved_ia32.extended_size += fsave_header_size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the extended processor state save/restore feature
|
||||
@ -384,19 +482,21 @@ static void __init setup_xstate_features(void)
|
||||
/*
|
||||
* setup the xstate image representing the init state
|
||||
*/
|
||||
static void __init setup_xstate_init(void)
|
||||
static void __init setup_init_fpu_buf(void)
|
||||
{
|
||||
setup_xstate_features();
|
||||
|
||||
/*
|
||||
* Setup init_xstate_buf to represent the init state of
|
||||
* all the features managed by the xsave
|
||||
*/
|
||||
init_xstate_buf = alloc_bootmem_align(xstate_size,
|
||||
__alignof__(struct xsave_struct));
|
||||
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
|
||||
fx_finit(&init_xstate_buf->i387);
|
||||
|
||||
if (!cpu_has_xsave)
|
||||
return;
|
||||
|
||||
setup_xstate_features();
|
||||
|
||||
clts();
|
||||
/*
|
||||
* Init all the features state with header_bv being 0x0
|
||||
*/
|
||||
@ -406,9 +506,21 @@ static void __init setup_xstate_init(void)
|
||||
* of any feature which is not represented by all zero's.
|
||||
*/
|
||||
xsave_state(init_xstate_buf, -1);
|
||||
stts();
|
||||
}
|
||||
|
||||
static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
|
||||
static int __init eager_fpu_setup(char *s)
|
||||
{
|
||||
if (!strcmp(s, "on"))
|
||||
eagerfpu = ENABLE;
|
||||
else if (!strcmp(s, "off"))
|
||||
eagerfpu = DISABLE;
|
||||
else if (!strcmp(s, "auto"))
|
||||
eagerfpu = AUTO;
|
||||
return 1;
|
||||
}
|
||||
__setup("eagerfpu=", eager_fpu_setup);
|
||||
|
||||
/*
|
||||
* Enable and initialize the xsave feature.
|
||||
*/
|
||||
@ -445,8 +557,11 @@ static void __init xstate_enable_boot_cpu(void)
|
||||
|
||||
update_regset_xstate_info(xstate_size, pcntxt_mask);
|
||||
prepare_fx_sw_frame();
|
||||
setup_init_fpu_buf();
|
||||
|
||||
setup_xstate_init();
|
||||
/* Auto enable eagerfpu for xsaveopt */
|
||||
if (cpu_has_xsaveopt && eagerfpu != DISABLE)
|
||||
eagerfpu = ENABLE;
|
||||
|
||||
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
||||
pcntxt_mask, xstate_size);
|
||||
@ -471,3 +586,43 @@ void __cpuinit xsave_init(void)
|
||||
next_func = xstate_enable;
|
||||
this_func();
|
||||
}
|
||||
|
||||
static inline void __init eager_fpu_init_bp(void)
|
||||
{
|
||||
current->thread.fpu.state =
|
||||
alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
|
||||
if (!init_xstate_buf)
|
||||
setup_init_fpu_buf();
|
||||
}
|
||||
|
||||
void __cpuinit eager_fpu_init(void)
|
||||
{
|
||||
static __refdata void (*boot_func)(void) = eager_fpu_init_bp;
|
||||
|
||||
clear_used_math();
|
||||
current_thread_info()->status = 0;
|
||||
|
||||
if (eagerfpu == ENABLE)
|
||||
setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
|
||||
|
||||
if (!cpu_has_eager_fpu) {
|
||||
stts();
|
||||
return;
|
||||
}
|
||||
|
||||
if (boot_func) {
|
||||
boot_func();
|
||||
boot_func = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is same as math_state_restore(). But use_xsave() is
|
||||
* not yet patched to use math_state_restore().
|
||||
*/
|
||||
init_fpu(current);
|
||||
__thread_fpu_begin(current);
|
||||
if (cpu_has_xsave)
|
||||
xrstor_state(init_xstate_buf, -1);
|
||||
else
|
||||
fxrstor_checking(&init_xstate_buf->i387);
|
||||
}
|
||||
|
@ -1493,8 +1493,12 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||
#ifdef CONFIG_X86_64
|
||||
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
|
||||
#endif
|
||||
if (user_has_fpu())
|
||||
clts();
|
||||
/*
|
||||
* If the FPU is not active (through the host task or
|
||||
* the guest vcpu), then restore the cr0.TS bit.
|
||||
*/
|
||||
if (!user_has_fpu() && !vmx->vcpu.guest_fpu_loaded)
|
||||
stts();
|
||||
load_gdt(&__get_cpu_var(host_gdt));
|
||||
}
|
||||
|
||||
@ -3730,7 +3734,7 @@ static void vmx_set_constant_host_state(void)
|
||||
unsigned long tmpl;
|
||||
struct desc_ptr dt;
|
||||
|
||||
vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS); /* 22.2.3 */
|
||||
vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS); /* 22.2.3 */
|
||||
vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */
|
||||
vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */
|
||||
|
||||
|
@ -5972,7 +5972,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
kvm_put_guest_xcr0(vcpu);
|
||||
vcpu->guest_fpu_loaded = 1;
|
||||
unlazy_fpu(current);
|
||||
__kernel_fpu_begin();
|
||||
fpu_restore_checking(&vcpu->arch.guest_fpu);
|
||||
trace_kvm_fpu(1);
|
||||
}
|
||||
@ -5986,6 +5986,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
||||
|
||||
vcpu->guest_fpu_loaded = 0;
|
||||
fpu_save_init(&vcpu->arch.guest_fpu);
|
||||
__kernel_fpu_end();
|
||||
++vcpu->stat.fpu_reload;
|
||||
kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
|
||||
trace_kvm_fpu(0);
|
||||
|
@ -203,8 +203,8 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||
* we set it now, so we can trap and pass that trap to the Guest if it
|
||||
* uses the FPU.
|
||||
*/
|
||||
if (cpu->ts)
|
||||
unlazy_fpu(current);
|
||||
if (cpu->ts && user_has_fpu())
|
||||
stts();
|
||||
|
||||
/*
|
||||
* SYSENTER is an optimized way of doing system calls. We can't allow
|
||||
@ -234,6 +234,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||
if (boot_cpu_has(X86_FEATURE_SEP))
|
||||
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
||||
|
||||
/* Clear the host TS bit if it was set above. */
|
||||
if (cpu->ts && user_has_fpu())
|
||||
clts();
|
||||
|
||||
/*
|
||||
* If the Guest page faulted, then the cr2 register will tell us the
|
||||
* bad virtual address. We have to grab this now, because once we
|
||||
@ -249,7 +253,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||
* a different CPU. So all the critical stuff should be done
|
||||
* before this.
|
||||
*/
|
||||
else if (cpu->regs->trapnum == 7)
|
||||
else if (cpu->regs->trapnum == 7 && !user_has_fpu())
|
||||
math_state_restore();
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,9 @@ static int sp_probe(struct platform_device *pdev)
|
||||
priv = netdev_priv(dev);
|
||||
|
||||
dev->irq = res_irq->start;
|
||||
priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED);
|
||||
priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
|
||||
if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
|
||||
priv->irq_flags |= IRQF_SHARED;
|
||||
priv->reg_base = addr;
|
||||
/* The CAN clock frequency is half the oscillator clock frequency */
|
||||
priv->can.clock.freq = pdata->osc_freq / 2;
|
||||
|
@ -150,7 +150,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
const uint8_t *mem, *end, *dat;
|
||||
uint16_t type, len;
|
||||
uint32_t addr;
|
||||
uint8_t *buf = NULL;
|
||||
uint8_t *buf = NULL, *new_buf;
|
||||
int buflen = 0;
|
||||
int8_t type_end = 0;
|
||||
|
||||
@ -199,11 +199,12 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||
if (len > buflen) {
|
||||
/* align buflen */
|
||||
buflen = (len + (1024-1)) & ~(1024-1);
|
||||
buf = krealloc(buf, buflen, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
new_buf = krealloc(buf, buflen, GFP_KERNEL);
|
||||
if (!new_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
buf = new_buf;
|
||||
}
|
||||
/* verify record data */
|
||||
memcpy_fromio(buf, &dpram[addr + offset], len);
|
||||
|
@ -1708,9 +1708,6 @@ struct bnx2x_func_init_params {
|
||||
continue; \
|
||||
else
|
||||
|
||||
#define for_each_napi_rx_queue(bp, var) \
|
||||
for ((var) = 0; (var) < bp->num_napi_queues; (var)++)
|
||||
|
||||
/* Skip OOO FP */
|
||||
#define for_each_tx_queue(bp, var) \
|
||||
for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \
|
||||
|
@ -2046,6 +2046,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
||||
*/
|
||||
bnx2x_setup_tc(bp->dev, bp->max_cos);
|
||||
|
||||
/* Add all NAPI objects */
|
||||
bnx2x_add_all_napi(bp);
|
||||
bnx2x_napi_enable(bp);
|
||||
|
||||
/* set pf load just before approaching the MCP */
|
||||
@ -2408,6 +2410,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
|
||||
|
||||
/* Disable HW interrupts, NAPI */
|
||||
bnx2x_netif_stop(bp, 1);
|
||||
/* Delete all NAPI objects */
|
||||
bnx2x_del_all_napi(bp);
|
||||
|
||||
/* Release IRQs */
|
||||
bnx2x_free_irq(bp);
|
||||
|
@ -792,7 +792,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
|
||||
bp->num_napi_queues = bp->num_queues;
|
||||
|
||||
/* Add NAPI objects */
|
||||
for_each_napi_rx_queue(bp, i)
|
||||
for_each_rx_queue(bp, i)
|
||||
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
|
||||
bnx2x_poll, BNX2X_NAPI_WEIGHT);
|
||||
}
|
||||
@ -801,7 +801,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for_each_napi_rx_queue(bp, i)
|
||||
for_each_rx_queue(bp, i)
|
||||
netif_napi_del(&bnx2x_fp(bp, i, napi));
|
||||
}
|
||||
|
||||
|
@ -2888,11 +2888,9 @@ static void bnx2x_get_channels(struct net_device *dev,
|
||||
*/
|
||||
static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss)
|
||||
{
|
||||
bnx2x_del_all_napi(bp);
|
||||
bnx2x_disable_msi(bp);
|
||||
BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE;
|
||||
bnx2x_set_int_mode(bp);
|
||||
bnx2x_add_all_napi(bp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8427,6 +8427,8 @@ unload_error:
|
||||
|
||||
/* Disable HW interrupts, NAPI */
|
||||
bnx2x_netif_stop(bp, 1);
|
||||
/* Delete all NAPI objects */
|
||||
bnx2x_del_all_napi(bp);
|
||||
|
||||
/* Release IRQs */
|
||||
bnx2x_free_irq(bp);
|
||||
@ -11229,10 +11231,12 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
static void poll_bnx2x(struct net_device *dev)
|
||||
{
|
||||
struct bnx2x *bp = netdev_priv(dev);
|
||||
int i;
|
||||
|
||||
disable_irq(bp->pdev->irq);
|
||||
bnx2x_interrupt(bp->pdev->irq, dev);
|
||||
enable_irq(bp->pdev->irq);
|
||||
for_each_eth_queue(bp, i) {
|
||||
struct bnx2x_fastpath *fp = &bp->fp[i];
|
||||
napi_schedule(&bnx2x_fp(bp, fp->index, napi));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -11899,9 +11903,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
|
||||
*/
|
||||
bnx2x_set_int_mode(bp);
|
||||
|
||||
/* Add all NAPI objects */
|
||||
bnx2x_add_all_napi(bp);
|
||||
|
||||
rc = register_netdev(dev);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Cannot register net device\n");
|
||||
@ -11976,9 +11977,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
/* Delete all NAPI objects */
|
||||
bnx2x_del_all_napi(bp);
|
||||
|
||||
/* Power on: we can't let PCI layer write to us while we are in D3 */
|
||||
bnx2x_set_power_state(bp, PCI_D0);
|
||||
|
||||
@ -12025,6 +12023,8 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
|
||||
bnx2x_tx_disable(bp);
|
||||
|
||||
bnx2x_netif_stop(bp, 0);
|
||||
/* Delete all NAPI objects */
|
||||
bnx2x_del_all_napi(bp);
|
||||
|
||||
del_timer_sync(&bp->timer);
|
||||
|
||||
|
@ -1243,6 +1243,7 @@ static void set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
struct net_local *lp = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
u16 cfg;
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
@ -1260,11 +1261,10 @@ static void set_multicast_list(struct net_device *dev)
|
||||
/* in promiscuous mode, we accept errored packets,
|
||||
* so we have to enable interrupts on them also
|
||||
*/
|
||||
writereg(dev, PP_RxCFG,
|
||||
(lp->curr_rx_cfg |
|
||||
(lp->rx_mode == RX_ALL_ACCEPT)
|
||||
? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
|
||||
: 0));
|
||||
cfg = lp->curr_rx_cfg;
|
||||
if (lp->rx_mode == RX_ALL_ACCEPT)
|
||||
cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL;
|
||||
writereg(dev, PP_RxCFG, cfg);
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,7 @@ int be_process_mcc(struct be_adapter *adapter)
|
||||
int num = 0, status = 0;
|
||||
struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
|
||||
|
||||
spin_lock_bh(&adapter->mcc_cq_lock);
|
||||
spin_lock(&adapter->mcc_cq_lock);
|
||||
while ((compl = be_mcc_compl_get(adapter))) {
|
||||
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
|
||||
/* Interpret flags as an async trailer */
|
||||
@ -280,7 +280,7 @@ int be_process_mcc(struct be_adapter *adapter)
|
||||
if (num)
|
||||
be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
|
||||
|
||||
spin_unlock_bh(&adapter->mcc_cq_lock);
|
||||
spin_unlock(&adapter->mcc_cq_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -295,7 +295,9 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
|
||||
if (be_error(adapter))
|
||||
return -EIO;
|
||||
|
||||
local_bh_disable();
|
||||
status = be_process_mcc(adapter);
|
||||
local_bh_enable();
|
||||
|
||||
if (atomic_read(&mcc_obj->q.used) == 0)
|
||||
break;
|
||||
|
@ -3763,7 +3763,9 @@ static void be_worker(struct work_struct *work)
|
||||
/* when interrupts are not yet enabled, just reap any pending
|
||||
* mcc completions */
|
||||
if (!netif_running(adapter->netdev)) {
|
||||
local_bh_disable();
|
||||
be_process_mcc(adapter);
|
||||
local_bh_enable();
|
||||
goto reschedule;
|
||||
}
|
||||
|
||||
|
@ -1041,7 +1041,7 @@ static int gfar_probe(struct platform_device *ofdev)
|
||||
|
||||
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
|
||||
dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||
dev->features |= NETIF_F_HW_VLAN_RX;
|
||||
}
|
||||
|
||||
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
|
||||
|
@ -310,6 +310,7 @@ struct e1000_adapter {
|
||||
*/
|
||||
struct e1000_ring *tx_ring /* One per active queue */
|
||||
____cacheline_aligned_in_smp;
|
||||
u32 tx_fifo_limit;
|
||||
|
||||
struct napi_struct napi;
|
||||
|
||||
|
@ -3516,6 +3516,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Alignment of Tx data is on an arbitrary byte boundary with the
|
||||
* maximum size per Tx descriptor limited only to the transmit
|
||||
* allocation of the packet buffer minus 96 bytes with an upper
|
||||
* limit of 24KB due to receive synchronization limitations.
|
||||
*/
|
||||
adapter->tx_fifo_limit = min_t(u32, ((er32(PBA) >> 16) << 10) - 96,
|
||||
24 << 10);
|
||||
|
||||
/*
|
||||
* Disable Adaptive Interrupt Moderation if 2 full packets cannot
|
||||
* fit in receive buffer.
|
||||
@ -4785,12 +4794,9 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define E1000_MAX_PER_TXD 8192
|
||||
#define E1000_MAX_TXD_PWR 12
|
||||
|
||||
static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
|
||||
unsigned int first, unsigned int max_per_txd,
|
||||
unsigned int nr_frags, unsigned int mss)
|
||||
unsigned int nr_frags)
|
||||
{
|
||||
struct e1000_adapter *adapter = tx_ring->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
@ -5023,20 +5029,19 @@ static int __e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||||
|
||||
static int e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||||
{
|
||||
BUG_ON(size > tx_ring->count);
|
||||
|
||||
if (e1000_desc_unused(tx_ring) >= size)
|
||||
return 0;
|
||||
return __e1000_maybe_stop_tx(tx_ring, size);
|
||||
}
|
||||
|
||||
#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1)
|
||||
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_ring *tx_ring = adapter->tx_ring;
|
||||
unsigned int first;
|
||||
unsigned int max_per_txd = E1000_MAX_PER_TXD;
|
||||
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
|
||||
unsigned int tx_flags = 0;
|
||||
unsigned int len = skb_headlen(skb);
|
||||
unsigned int nr_frags;
|
||||
@ -5056,18 +5061,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
mss = skb_shinfo(skb)->gso_size;
|
||||
/*
|
||||
* The controller does a simple calculation to
|
||||
* make sure there is enough room in the FIFO before
|
||||
* initiating the DMA for each buffer. The calc is:
|
||||
* 4 = ceil(buffer len/mss). To make sure we don't
|
||||
* overrun the FIFO, adjust the max buffer len if mss
|
||||
* drops.
|
||||
*/
|
||||
if (mss) {
|
||||
u8 hdr_len;
|
||||
max_per_txd = min(mss << 2, max_per_txd);
|
||||
max_txd_pwr = fls(max_per_txd) - 1;
|
||||
|
||||
/*
|
||||
* TSO Workaround for 82571/2/3 Controllers -- if skb->data
|
||||
@ -5097,12 +5092,12 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||
count++;
|
||||
count++;
|
||||
|
||||
count += TXD_USE_COUNT(len, max_txd_pwr);
|
||||
count += DIV_ROUND_UP(len, adapter->tx_fifo_limit);
|
||||
|
||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
for (f = 0; f < nr_frags; f++)
|
||||
count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
||||
max_txd_pwr);
|
||||
count += DIV_ROUND_UP(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
||||
adapter->tx_fifo_limit);
|
||||
|
||||
if (adapter->hw.mac.tx_pkt_filtering)
|
||||
e1000_transfer_dhcp_info(adapter, skb);
|
||||
@ -5144,15 +5139,18 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||
tx_flags |= E1000_TX_FLAGS_NO_FCS;
|
||||
|
||||
/* if count is 0 then mapping error has occurred */
|
||||
count = e1000_tx_map(tx_ring, skb, first, max_per_txd, nr_frags, mss);
|
||||
count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
|
||||
nr_frags);
|
||||
if (count) {
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
netdev_sent_queue(netdev, skb->len);
|
||||
e1000_tx_queue(tx_ring, tx_flags, count);
|
||||
/* Make sure there is space in the ring for the next send. */
|
||||
e1000_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 2);
|
||||
|
||||
e1000_maybe_stop_tx(tx_ring,
|
||||
(MAX_SKB_FRAGS *
|
||||
DIV_ROUND_UP(PAGE_SIZE,
|
||||
adapter->tx_fifo_limit) + 2));
|
||||
} else {
|
||||
dev_kfree_skb_any(skb);
|
||||
tx_ring->buffer_info[first].time_stamp = 0;
|
||||
@ -6327,8 +6325,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
||||
adapter->hw.phy.autoneg_advertised = 0x2f;
|
||||
|
||||
/* ring size defaults */
|
||||
adapter->rx_ring->count = 256;
|
||||
adapter->tx_ring->count = 256;
|
||||
adapter->rx_ring->count = E1000_DEFAULT_RXD;
|
||||
adapter->tx_ring->count = E1000_DEFAULT_TXD;
|
||||
|
||||
/*
|
||||
* Initial Wake on LAN setting - If APM wake is enabled in
|
||||
|
@ -863,8 +863,8 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||
&ip_entry->ip4dst, &ip_entry->pdst);
|
||||
if (rc != 0) {
|
||||
rc = efx_filter_get_ipv4_full(
|
||||
&spec, &proto, &ip_entry->ip4src, &ip_entry->psrc,
|
||||
&ip_entry->ip4dst, &ip_entry->pdst);
|
||||
&spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst,
|
||||
&ip_entry->ip4src, &ip_entry->psrc);
|
||||
EFX_WARN_ON_PARANOID(rc);
|
||||
ip_mask->ip4src = ~0;
|
||||
ip_mask->psrc = ~0;
|
||||
|
@ -22,6 +22,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
@ -366,3 +369,5 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
extern const struct stmmac_ring_mode_ops ring_mode_ops;
|
||||
|
||||
#endif /* __COMMON_H__ */
|
||||
|
@ -20,6 +20,10 @@
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESCS_H__
|
||||
#define __DESCS_H__
|
||||
|
||||
struct dma_desc {
|
||||
/* Receive descriptor */
|
||||
union {
|
||||
@ -166,3 +170,5 @@ enum tdes_csum_insertion {
|
||||
* is not calculated */
|
||||
cic_full = 3, /* IP header and pseudoheader */
|
||||
};
|
||||
|
||||
#endif /* __DESCS_H__ */
|
||||
|
@ -27,6 +27,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESC_COM_H__
|
||||
#define __DESC_COM_H__
|
||||
|
||||
#if defined(CONFIG_STMMAC_RING)
|
||||
static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
@ -124,3 +127,5 @@ static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
|
||||
p->des01.tx.buffer1_size = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DESC_COM_H__ */
|
||||
|
@ -22,6 +22,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC100_H__
|
||||
#define __DWMAC100_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
@ -119,3 +122,5 @@ enum ttc_control {
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
|
||||
#endif /* __DWMAC100_H__ */
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
#ifndef __DWMAC1000_H__
|
||||
#define __DWMAC1000_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
@ -229,6 +231,7 @@ enum rtc_control {
|
||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||
|
||||
/* Synopsys Core versions */
|
||||
#define DWMAC_CORE_3_40 34
|
||||
#define DWMAC_CORE_3_40 0x34
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
#endif /* __DWMAC1000_H__ */
|
||||
|
@ -22,6 +22,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC_DMA_H__
|
||||
#define __DWMAC_DMA_H__
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||
@ -109,3 +112,5 @@ extern void dwmac_dma_start_rx(void __iomem *ioaddr);
|
||||
extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
|
||||
extern int dwmac_dma_interrupt(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x);
|
||||
|
||||
#endif /* __DWMAC_DMA_H__ */
|
||||
|
@ -22,6 +22,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MMC_H__
|
||||
#define __MMC_H__
|
||||
|
||||
/* MMC control register */
|
||||
/* When set, all counter are reset */
|
||||
#define MMC_CNTRL_COUNTER_RESET 0x1
|
||||
@ -129,3 +132,5 @@ struct stmmac_counters {
|
||||
extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
|
||||
extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
|
||||
extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||
|
||||
#endif /* __MMC_H__ */
|
||||
|
@ -33,7 +33,7 @@
|
||||
#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
|
||||
#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
|
||||
#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
|
||||
#define MMC_DEFAUL_MASK 0xffffffff
|
||||
#define MMC_DEFAULT_MASK 0xffffffff
|
||||
|
||||
/* MMC TX counter registers */
|
||||
|
||||
@ -147,8 +147,8 @@ void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode)
|
||||
/* To mask all all interrupts.*/
|
||||
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
|
||||
{
|
||||
writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
|
@ -20,6 +20,9 @@
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||
#define DRV_MODULE_VERSION "March_2012"
|
||||
|
||||
@ -166,3 +169,5 @@ static inline void stmmac_unregister_pci(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_PCI */
|
||||
|
||||
#endif /* __STMMAC_H__ */
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
#ifndef __STMMAC_TIMER_H__
|
||||
#define __STMMAC_TIMER_H__
|
||||
|
||||
struct stmmac_timer {
|
||||
void (*timer_start) (unsigned int new_freq);
|
||||
@ -40,3 +42,5 @@ void stmmac_schedule(struct net_device *dev);
|
||||
extern int tmu2_register_user(void *fnt, void *data);
|
||||
extern void tmu2_unregister_user(void);
|
||||
#endif
|
||||
|
||||
#endif /* __STMMAC_TIMER_H__ */
|
||||
|
@ -394,8 +394,10 @@ static int __devexit davinci_mdio_remove(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (data->bus)
|
||||
if (data->bus) {
|
||||
mdiobus_unregister(data->bus);
|
||||
mdiobus_free(data->bus);
|
||||
}
|
||||
|
||||
if (data->clk)
|
||||
clk_put(data->clk);
|
||||
|
@ -673,7 +673,7 @@ void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
|
||||
sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
|
||||
break ;
|
||||
case SMT_P_REASON :
|
||||
* (u_long *) to = 0 ;
|
||||
*(u32 *)to = 0 ;
|
||||
sp_len = 4 ;
|
||||
goto sp_done ;
|
||||
case SMT_P1033 : /* time stamp */
|
||||
|
@ -413,7 +413,9 @@ static const struct usb_device_id products[] = {
|
||||
|
||||
/* 5. Gobi 2000 and 3000 devices */
|
||||
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
|
||||
{QMI_GOBI_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */
|
||||
{QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
|
||||
{QMI_GOBI_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */
|
||||
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
|
||||
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
|
||||
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
|
||||
@ -441,6 +443,8 @@ static const struct usb_device_id products[] = {
|
||||
{QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */
|
||||
{QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */
|
||||
{QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
|
||||
{QMI_GOBI_DEVICE(0x12d1, 0x14f1)}, /* Sony Gobi 3000 Composite */
|
||||
{QMI_GOBI_DEVICE(0x1410, 0xa021)}, /* Foxconn Gobi 3000 Modem device (Novatel E396) */
|
||||
|
||||
{ } /* END */
|
||||
};
|
||||
|
@ -1573,7 +1573,7 @@ int usbnet_resume (struct usb_interface *intf)
|
||||
netif_device_present(dev->net) &&
|
||||
!timer_pending(&dev->delay) &&
|
||||
!test_bit(EVENT_RX_HALT, &dev->flags))
|
||||
rx_alloc_submit(dev, GFP_KERNEL);
|
||||
rx_alloc_submit(dev, GFP_NOIO);
|
||||
|
||||
if (!(dev->txq.qlen >= TX_QLEN(dev)))
|
||||
netif_tx_wake_all_queues(dev->net);
|
||||
|
@ -1482,7 +1482,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
|
||||
rate_pcal_info = ee->ee_rate_tpwr_a;
|
||||
ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
|
||||
ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_RATE_CHAN;
|
||||
break;
|
||||
case AR5K_EEPROM_MODE_11B:
|
||||
offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
|
||||
|
@ -182,6 +182,7 @@
|
||||
#define AR5K_EEPROM_EEP_DELTA 10
|
||||
#define AR5K_EEPROM_N_MODES 3
|
||||
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
||||
#define AR5K_EEPROM_N_5GHZ_RATE_CHAN 8
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
|
||||
#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4
|
||||
|
@ -1233,6 +1233,9 @@ uint brcms_reset(struct brcms_info *wl)
|
||||
/* dpc will not be rescheduled */
|
||||
wl->resched = false;
|
||||
|
||||
/* inform publicly that interface is down */
|
||||
wl->pub->up = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2042,7 +2042,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
|
||||
return;
|
||||
}
|
||||
len = ETH_ALEN;
|
||||
ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
|
||||
ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
|
||||
&len);
|
||||
if (ret) {
|
||||
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
|
||||
__LINE__);
|
||||
|
@ -124,6 +124,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||
const struct fw_img *img;
|
||||
size_t bufsz;
|
||||
|
||||
if (!iwl_is_ready_rf(priv))
|
||||
return -EAGAIN;
|
||||
|
||||
/* default is to dump the entire data segment */
|
||||
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
|
||||
priv->dbgfs_sram_offset = 0x800000;
|
||||
|
@ -350,7 +350,7 @@ int iwl_queue_space(const struct iwl_queue *q);
|
||||
/*****************************************************
|
||||
* Error handling
|
||||
******************************************************/
|
||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
|
||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf);
|
||||
void iwl_dump_csr(struct iwl_trans *trans);
|
||||
|
||||
/*****************************************************
|
||||
|
@ -555,7 +555,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
|
||||
}
|
||||
|
||||
iwl_dump_csr(trans);
|
||||
iwl_dump_fh(trans, NULL, false);
|
||||
iwl_dump_fh(trans, NULL);
|
||||
|
||||
iwl_op_mode_nic_error(trans->op_mode);
|
||||
}
|
||||
|
@ -1649,13 +1649,9 @@ static const char *get_fh_string(int cmd)
|
||||
#undef IWL_CMD
|
||||
}
|
||||
|
||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf)
|
||||
{
|
||||
int i;
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
int pos = 0;
|
||||
size_t bufsz = 0;
|
||||
#endif
|
||||
static const u32 fh_tbl[] = {
|
||||
FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||||
FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
||||
@ -1667,29 +1663,35 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
||||
FH_TSSR_TX_STATUS_REG,
|
||||
FH_TSSR_TX_ERROR_REG
|
||||
};
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
if (display) {
|
||||
bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (buf) {
|
||||
int pos = 0;
|
||||
size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
||||
|
||||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!*buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"FH register values:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
" %34s: 0X%08x\n",
|
||||
get_fh_string(fh_tbl[i]),
|
||||
iwl_read_direct32(trans, fh_tbl[i]));
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
IWL_ERR(trans, "FH register values:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||||
IWL_ERR(trans, " %34s: 0X%08x\n",
|
||||
get_fh_string(fh_tbl[i]),
|
||||
iwl_read_direct32(trans, fh_tbl[i]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1982,11 +1984,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_trans *trans = file->private_data;
|
||||
char *buf;
|
||||
char *buf = NULL;
|
||||
int pos = 0;
|
||||
ssize_t ret = -EFAULT;
|
||||
|
||||
ret = pos = iwl_dump_fh(trans, &buf, true);
|
||||
ret = pos = iwl_dump_fh(trans, &buf);
|
||||
if (buf) {
|
||||
ret = simple_read_from_buffer(user_buf,
|
||||
count, ppos, buf, pos);
|
||||
|
@ -57,8 +57,7 @@
|
||||
static const struct ethtool_ops xennet_ethtool_ops;
|
||||
|
||||
struct netfront_cb {
|
||||
struct page *page;
|
||||
unsigned offset;
|
||||
int pull_to;
|
||||
};
|
||||
|
||||
#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
|
||||
@ -867,15 +866,9 @@ static int handle_incoming_queue(struct net_device *dev,
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = __skb_dequeue(rxq)) != NULL) {
|
||||
struct page *page = NETFRONT_SKB_CB(skb)->page;
|
||||
void *vaddr = page_address(page);
|
||||
unsigned offset = NETFRONT_SKB_CB(skb)->offset;
|
||||
int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
|
||||
|
||||
memcpy(skb->data, vaddr + offset,
|
||||
skb_headlen(skb));
|
||||
|
||||
if (page != skb_frag_page(&skb_shinfo(skb)->frags[0]))
|
||||
__free_page(page);
|
||||
__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
|
||||
|
||||
/* Ethernet work: Delayed to here as it peeks the header. */
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
@ -913,7 +906,6 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
||||
struct sk_buff_head errq;
|
||||
struct sk_buff_head tmpq;
|
||||
unsigned long flags;
|
||||
unsigned int len;
|
||||
int err;
|
||||
|
||||
spin_lock(&np->rx_lock);
|
||||
@ -955,24 +947,13 @@ err:
|
||||
}
|
||||
}
|
||||
|
||||
NETFRONT_SKB_CB(skb)->page =
|
||||
skb_frag_page(&skb_shinfo(skb)->frags[0]);
|
||||
NETFRONT_SKB_CB(skb)->offset = rx->offset;
|
||||
NETFRONT_SKB_CB(skb)->pull_to = rx->status;
|
||||
if (NETFRONT_SKB_CB(skb)->pull_to > RX_COPY_THRESHOLD)
|
||||
NETFRONT_SKB_CB(skb)->pull_to = RX_COPY_THRESHOLD;
|
||||
|
||||
len = rx->status;
|
||||
if (len > RX_COPY_THRESHOLD)
|
||||
len = RX_COPY_THRESHOLD;
|
||||
skb_put(skb, len);
|
||||
|
||||
if (rx->status > len) {
|
||||
skb_shinfo(skb)->frags[0].page_offset =
|
||||
rx->offset + len;
|
||||
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status - len);
|
||||
skb->data_len = rx->status - len;
|
||||
} else {
|
||||
__skb_fill_page_desc(skb, 0, NULL, 0, 0);
|
||||
skb_shinfo(skb)->nr_frags = 0;
|
||||
}
|
||||
skb_shinfo(skb)->frags[0].page_offset = rx->offset;
|
||||
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status);
|
||||
skb->data_len = rx->status;
|
||||
|
||||
i = xennet_fill_frags(np, skb, &tmpq);
|
||||
|
||||
@ -999,7 +980,7 @@ err:
|
||||
* receive throughout using the standard receive
|
||||
* buffer size was cut by 25%(!!!).
|
||||
*/
|
||||
skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
|
||||
skb->truesize += skb->data_len - RX_COPY_THRESHOLD;
|
||||
skb->len += skb->data_len;
|
||||
|
||||
if (rx->flags & XEN_NETRXF_csum_blank)
|
||||
|
@ -1576,9 +1576,14 @@ cifs_readv_callback(struct mid_q_entry *mid)
|
||||
/* result already set, check signature */
|
||||
if (server->sec_mode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||
if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
|
||||
server, mid->sequence_number + 1))
|
||||
cERROR(1, "Unexpected SMB signature");
|
||||
int rc = 0;
|
||||
|
||||
rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
|
||||
server,
|
||||
mid->sequence_number + 1);
|
||||
if (rc)
|
||||
cERROR(1, "SMB signature verification returned "
|
||||
"error = %d", rc);
|
||||
}
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->bytes);
|
||||
|
@ -356,19 +356,12 @@ cifs_create_get_file_info:
|
||||
cifs_create_set_dentry:
|
||||
if (rc != 0) {
|
||||
cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
|
||||
CIFSSMBClose(xid, tcon, *fileHandle);
|
||||
goto out;
|
||||
}
|
||||
d_drop(direntry);
|
||||
d_add(direntry, newinode);
|
||||
|
||||
/* ENOENT for create? How weird... */
|
||||
rc = -ENOENT;
|
||||
if (!newinode) {
|
||||
CIFSSMBClose(xid, tcon, *fileHandle);
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(full_path);
|
||||
|
@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
{
|
||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
unsigned long oldtime = cifs_i->time;
|
||||
|
||||
cifs_revalidate_cache(inode, fattr);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_atime = fattr->cf_atime;
|
||||
inode->i_mtime = fattr->cf_mtime;
|
||||
inode->i_ctime = fattr->cf_ctime;
|
||||
@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
else
|
||||
cifs_i->time = jiffies;
|
||||
|
||||
cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
|
||||
oldtime, cifs_i->time);
|
||||
|
||||
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
||||
|
||||
cifs_i->server_eof = fattr->cf_eof;
|
||||
@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||
* Can't safely change the file size here if the client is writing to
|
||||
* it due to potential races.
|
||||
*/
|
||||
spin_lock(&inode->i_lock);
|
||||
if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
|
||||
i_size_write(inode, fattr->cf_eof);
|
||||
|
||||
@ -859,12 +855,14 @@ struct inode *cifs_root_iget(struct super_block *sb)
|
||||
|
||||
if (rc && tcon->ipc) {
|
||||
cFYI(1, "ipc connection - fake read inode");
|
||||
spin_lock(&inode->i_lock);
|
||||
inode->i_mode |= S_IFDIR;
|
||||
set_nlink(inode, 2);
|
||||
inode->i_op = &cifs_ipc_inode_ops;
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
inode->i_uid = cifs_sb->mnt_uid;
|
||||
inode->i_gid = cifs_sb->mnt_gid;
|
||||
spin_unlock(&inode->i_lock);
|
||||
} else if (rc) {
|
||||
iget_failed(inode);
|
||||
inode = ERR_PTR(rc);
|
||||
@ -1110,6 +1108,15 @@ undo_setattr:
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
/* copied from fs/nfs/dir.c with small changes */
|
||||
static void
|
||||
cifs_drop_nlink(struct inode *inode)
|
||||
{
|
||||
spin_lock(&inode->i_lock);
|
||||
if (inode->i_nlink > 0)
|
||||
drop_nlink(inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* If dentry->d_inode is null (usually meaning the cached dentry
|
||||
@ -1166,13 +1173,13 @@ retry_std_delete:
|
||||
psx_del_no_retry:
|
||||
if (!rc) {
|
||||
if (inode)
|
||||
drop_nlink(inode);
|
||||
cifs_drop_nlink(inode);
|
||||
} else if (rc == -ENOENT) {
|
||||
d_drop(dentry);
|
||||
} else if (rc == -ETXTBSY) {
|
||||
rc = cifs_rename_pending_delete(full_path, dentry, xid);
|
||||
if (rc == 0)
|
||||
drop_nlink(inode);
|
||||
cifs_drop_nlink(inode);
|
||||
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
|
||||
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
|
||||
if (attrs == NULL) {
|
||||
@ -1241,9 +1248,10 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
|
||||
* setting nlink not necessary except in cases where we failed to get it
|
||||
* from the server or was set bogus
|
||||
*/
|
||||
spin_lock(&dentry->d_inode->i_lock);
|
||||
if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
|
||||
set_nlink(dentry->d_inode, 2);
|
||||
|
||||
spin_unlock(&dentry->d_inode->i_lock);
|
||||
mode &= ~current_umask();
|
||||
/* must turn on setgid bit if parent dir has it */
|
||||
if (inode->i_mode & S_ISGID)
|
||||
|
@ -433,7 +433,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
|
||||
if (old_file->d_inode) {
|
||||
cifsInode = CIFS_I(old_file->d_inode);
|
||||
if (rc == 0) {
|
||||
spin_lock(&old_file->d_inode->i_lock);
|
||||
inc_nlink(old_file->d_inode);
|
||||
spin_unlock(&old_file->d_inode->i_lock);
|
||||
/* BB should we make this contingent on superblock flag NOATIME? */
|
||||
/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
|
||||
/* parent dir timestamps will update from srv
|
||||
|
@ -52,7 +52,8 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
|
||||
cERROR(1, "Bad protocol string signature header %x",
|
||||
*(unsigned int *) hdr->ProtocolId);
|
||||
if (mid != hdr->MessageId)
|
||||
cERROR(1, "Mids do not match");
|
||||
cERROR(1, "Mids do not match: %llu and %llu", mid,
|
||||
hdr->MessageId);
|
||||
}
|
||||
cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId);
|
||||
return 1;
|
||||
@ -107,7 +108,7 @@ smb2_check_message(char *buf, unsigned int length)
|
||||
* ie Validate the wct via smb2_struct_sizes table above
|
||||
*/
|
||||
|
||||
if (length < 2 + sizeof(struct smb2_hdr)) {
|
||||
if (length < sizeof(struct smb2_pdu)) {
|
||||
if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
|
||||
pdu->StructureSize2 = 0;
|
||||
/*
|
||||
@ -121,15 +122,15 @@ smb2_check_message(char *buf, unsigned int length)
|
||||
return 1;
|
||||
}
|
||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
|
||||
cERROR(1, "SMB length greater than maximum, mid=%lld", mid);
|
||||
cERROR(1, "SMB length greater than maximum, mid=%llu", mid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (check_smb2_hdr(hdr, mid))
|
||||
return 1;
|
||||
|
||||
if (hdr->StructureSize != SMB2_HEADER_SIZE) {
|
||||
cERROR(1, "Illegal structure size %d",
|
||||
if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
|
||||
cERROR(1, "Illegal structure size %u",
|
||||
le16_to_cpu(hdr->StructureSize));
|
||||
return 1;
|
||||
}
|
||||
@ -161,8 +162,9 @@ smb2_check_message(char *buf, unsigned int length)
|
||||
if (4 + len != clc_len) {
|
||||
cFYI(1, "Calculated size %u length %u mismatch mid %llu",
|
||||
clc_len, 4 + len, mid);
|
||||
if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
|
||||
return 0; /* BB workaround Samba 3 bug SessSetup rsp */
|
||||
/* server can return one byte more */
|
||||
if (clc_len == 4 + len + 1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -87,10 +87,6 @@
|
||||
|
||||
#define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe)
|
||||
|
||||
#define SMB2_HEADER_SIZE __constant_le16_to_cpu(64)
|
||||
|
||||
#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
|
||||
|
||||
/*
|
||||
* SMB2 Header Definition
|
||||
*
|
||||
@ -99,6 +95,9 @@
|
||||
* "PDU" : "Protocol Data Unit" (ie a network "frame")
|
||||
*
|
||||
*/
|
||||
|
||||
#define SMB2_HEADER_STRUCTURE_SIZE __constant_le16_to_cpu(64)
|
||||
|
||||
struct smb2_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/* length is only two or three bytes - with
|
||||
@ -140,6 +139,9 @@ struct smb2_pdu {
|
||||
* command code name for the struct. Note that structures must be packed.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
|
||||
|
||||
struct smb2_err_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize;
|
||||
|
@ -503,13 +503,16 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||
/* convert the length into a more usable form */
|
||||
if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||
struct kvec iov;
|
||||
int rc = 0;
|
||||
|
||||
iov.iov_base = mid->resp_buf;
|
||||
iov.iov_len = len;
|
||||
/* FIXME: add code to kill session */
|
||||
if (cifs_verify_signature(&iov, 1, server,
|
||||
mid->sequence_number + 1) != 0)
|
||||
cERROR(1, "Unexpected SMB signature");
|
||||
rc = cifs_verify_signature(&iov, 1, server,
|
||||
mid->sequence_number + 1);
|
||||
if (rc)
|
||||
cERROR(1, "SMB signature verification returned error = "
|
||||
"%d", rc);
|
||||
}
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
|
@ -2149,7 +2149,7 @@
|
||||
#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
|
||||
#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9
|
||||
#define PCI_DEVICE_ID_NX2_5706S 0x16aa
|
||||
#define PCI_DEVICE_ID_NX2_57840_MF 0x16ab
|
||||
#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4
|
||||
#define PCI_DEVICE_ID_NX2_5708S 0x16ac
|
||||
#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad
|
||||
#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae
|
||||
|
@ -18,6 +18,7 @@ struct nf_conntrack_ecache {
|
||||
u16 ctmask; /* bitmask of ct events to be delivered */
|
||||
u16 expmask; /* bitmask of expect events to be delivered */
|
||||
u32 pid; /* netlink pid of destroyer */
|
||||
struct timer_list timeout;
|
||||
};
|
||||
|
||||
static inline struct nf_conntrack_ecache *
|
||||
|
@ -168,24 +168,16 @@ static void poll_napi(struct net_device *dev)
|
||||
struct napi_struct *napi;
|
||||
int budget = 16;
|
||||
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
|
||||
list_for_each_entry(napi, &dev->napi_list, dev_list) {
|
||||
local_irq_enable();
|
||||
if (napi->poll_owner != smp_processor_id() &&
|
||||
spin_trylock(&napi->poll_lock)) {
|
||||
rcu_read_lock_bh();
|
||||
budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
|
||||
napi, budget);
|
||||
rcu_read_unlock_bh();
|
||||
spin_unlock(&napi->poll_lock);
|
||||
|
||||
if (!budget) {
|
||||
local_irq_disable();
|
||||
if (!budget)
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
|
||||
static struct kmem_cache *mrt_cachep __read_mostly;
|
||||
|
||||
static struct mr_table *ipmr_new_table(struct net *net, u32 id);
|
||||
static void ipmr_free_table(struct mr_table *mrt);
|
||||
|
||||
static int ip_mr_forward(struct net *net, struct mr_table *mrt,
|
||||
struct sk_buff *skb, struct mfc_cache *cache,
|
||||
int local);
|
||||
@ -131,6 +133,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
|
||||
struct sk_buff *pkt, vifi_t vifi, int assert);
|
||||
static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
|
||||
struct mfc_cache *c, struct rtmsg *rtm);
|
||||
static void mroute_clean_tables(struct mr_table *mrt);
|
||||
static void ipmr_expire_process(unsigned long arg);
|
||||
|
||||
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
|
||||
@ -271,7 +274,7 @@ static void __net_exit ipmr_rules_exit(struct net *net)
|
||||
|
||||
list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
|
||||
list_del(&mrt->list);
|
||||
kfree(mrt);
|
||||
ipmr_free_table(mrt);
|
||||
}
|
||||
fib_rules_unregister(net->ipv4.mr_rules_ops);
|
||||
}
|
||||
@ -299,7 +302,7 @@ static int __net_init ipmr_rules_init(struct net *net)
|
||||
|
||||
static void __net_exit ipmr_rules_exit(struct net *net)
|
||||
{
|
||||
kfree(net->ipv4.mrt);
|
||||
ipmr_free_table(net->ipv4.mrt);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -336,6 +339,13 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
|
||||
return mrt;
|
||||
}
|
||||
|
||||
static void ipmr_free_table(struct mr_table *mrt)
|
||||
{
|
||||
del_timer_sync(&mrt->ipmr_expire_timer);
|
||||
mroute_clean_tables(mrt);
|
||||
kfree(mrt);
|
||||
}
|
||||
|
||||
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
|
||||
|
||||
static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
|
||||
|
@ -502,7 +502,10 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
|
||||
ret = nf_ct_expect_related(rtcp_exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
else if (ret == -EBUSY) {
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
port = 0;
|
||||
break;
|
||||
|
@ -934,12 +934,14 @@ static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
|
||||
if (mtu < ip_rt_min_pmtu)
|
||||
mtu = ip_rt_min_pmtu;
|
||||
|
||||
rcu_read_lock();
|
||||
if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) {
|
||||
struct fib_nh *nh = &FIB_RES_NH(res);
|
||||
|
||||
update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
|
||||
jiffies + ip_rt_mtu_expires);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return mtu;
|
||||
}
|
||||
|
||||
@ -956,7 +958,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
||||
dst->obsolete = DST_OBSOLETE_KILL;
|
||||
} else {
|
||||
rt->rt_pmtu = mtu;
|
||||
dst_set_expires(&rt->dst, ip_rt_mtu_expires);
|
||||
rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,7 +1265,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
|
||||
{
|
||||
struct rtable *rt = (struct rtable *) dst;
|
||||
|
||||
if (dst->flags & DST_NOCACHE) {
|
||||
if (!list_empty(&rt->rt_uncached)) {
|
||||
spin_lock_bh(&rt_uncached_lock);
|
||||
list_del(&rt->rt_uncached);
|
||||
spin_unlock_bh(&rt_uncached_lock);
|
||||
|
@ -2926,13 +2926,14 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
|
||||
* tcp_xmit_retransmit_queue().
|
||||
*/
|
||||
static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||
int newly_acked_sacked, bool is_dupack,
|
||||
int prior_sacked, bool is_dupack,
|
||||
int flag)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
|
||||
(tcp_fackets_out(tp) > tp->reordering));
|
||||
int newly_acked_sacked = 0;
|
||||
int fast_rexmit = 0;
|
||||
|
||||
if (WARN_ON(!tp->packets_out && tp->sacked_out))
|
||||
@ -2992,6 +2993,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||
tcp_add_reno_sack(sk);
|
||||
} else
|
||||
do_lost = tcp_try_undo_partial(sk, pkts_acked);
|
||||
newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked;
|
||||
break;
|
||||
case TCP_CA_Loss:
|
||||
if (flag & FLAG_DATA_ACKED)
|
||||
@ -3013,6 +3015,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||
if (is_dupack)
|
||||
tcp_add_reno_sack(sk);
|
||||
}
|
||||
newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked;
|
||||
|
||||
if (icsk->icsk_ca_state <= TCP_CA_Disorder)
|
||||
tcp_try_undo_dsack(sk);
|
||||
@ -3590,7 +3593,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||
int prior_packets;
|
||||
int prior_sacked = tp->sacked_out;
|
||||
int pkts_acked = 0;
|
||||
int newly_acked_sacked = 0;
|
||||
bool frto_cwnd = false;
|
||||
|
||||
/* If the ack is older than previous acks
|
||||
@ -3666,8 +3668,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
|
||||
|
||||
pkts_acked = prior_packets - tp->packets_out;
|
||||
newly_acked_sacked = (prior_packets - prior_sacked) -
|
||||
(tp->packets_out - tp->sacked_out);
|
||||
|
||||
if (tp->frto_counter)
|
||||
frto_cwnd = tcp_process_frto(sk, flag);
|
||||
@ -3681,7 +3681,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||
tcp_may_raise_cwnd(sk, flag))
|
||||
tcp_cong_avoid(sk, ack, prior_in_flight);
|
||||
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
|
||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
||||
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||
is_dupack, flag);
|
||||
} else {
|
||||
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
|
||||
@ -3698,7 +3698,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||
no_queue:
|
||||
/* If data was DSACKed, see if we can undo a cwnd reduction. */
|
||||
if (flag & FLAG_DSACKING_ACK)
|
||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
||||
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||
is_dupack, flag);
|
||||
/* If this ack opens up a zero window, clear backoff. It was
|
||||
* being used to time the probes, and is probably far higher than
|
||||
@ -3718,8 +3718,7 @@ old_ack:
|
||||
*/
|
||||
if (TCP_SKB_CB(skb)->sacked) {
|
||||
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
|
||||
newly_acked_sacked = tp->sacked_out - prior_sacked;
|
||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
||||
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||
is_dupack, flag);
|
||||
}
|
||||
|
||||
|
@ -167,8 +167,6 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
struct esp_data *esp = x->data;
|
||||
|
||||
/* skb is pure payload to encrypt */
|
||||
err = -ENOMEM;
|
||||
|
||||
aead = esp->aead;
|
||||
alen = crypto_aead_authsize(aead);
|
||||
|
||||
@ -203,8 +201,10 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
|
||||
if (!tmp)
|
||||
if (!tmp) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
seqhi = esp_tmp_seqhi(tmp);
|
||||
iv = esp_tmp_iv(aead, tmp, seqhilen);
|
||||
|
@ -1347,11 +1347,10 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
||||
/* Remove from tunnel list */
|
||||
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
|
||||
list_del_rcu(&tunnel->list);
|
||||
kfree_rcu(tunnel, rcu);
|
||||
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
|
||||
synchronize_rcu();
|
||||
|
||||
atomic_dec(&l2tp_tunnel_count);
|
||||
kfree(tunnel);
|
||||
}
|
||||
|
||||
/* Create a socket for the tunnel, if one isn't set up by
|
||||
|
@ -163,6 +163,7 @@ struct l2tp_tunnel_cfg {
|
||||
|
||||
struct l2tp_tunnel {
|
||||
int magic; /* Should be L2TP_TUNNEL_MAGIC */
|
||||
struct rcu_head rcu;
|
||||
rwlock_t hlist_lock; /* protect session_hlist */
|
||||
struct hlist_head session_hlist[L2TP_HASH_SIZE];
|
||||
/* hashed list of sessions,
|
||||
|
@ -1811,37 +1811,31 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata, NULL, NULL);
|
||||
} else {
|
||||
int is_mesh_mcast = 1;
|
||||
const u8 *mesh_da;
|
||||
/* DS -> MBSS (802.11-2012 13.11.3.3).
|
||||
* For unicast with unknown forwarding information,
|
||||
* destination might be in the MBSS or if that fails
|
||||
* forwarded to another mesh gate. In either case
|
||||
* resolution will be handled in ieee80211_xmit(), so
|
||||
* leave the original DA. This also works for mcast */
|
||||
const u8 *mesh_da = skb->data;
|
||||
|
||||
if (mppath)
|
||||
mesh_da = mppath->mpp;
|
||||
else if (mpath)
|
||||
mesh_da = mpath->dst;
|
||||
rcu_read_unlock();
|
||||
|
||||
if (is_multicast_ether_addr(skb->data))
|
||||
/* DA TA mSA AE:SA */
|
||||
mesh_da = skb->data;
|
||||
else {
|
||||
static const u8 bcast[ETH_ALEN] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
if (mppath) {
|
||||
/* RA TA mDA mSA AE:DA SA */
|
||||
mesh_da = mppath->mpp;
|
||||
is_mesh_mcast = 0;
|
||||
} else if (mpath) {
|
||||
mesh_da = mpath->dst;
|
||||
is_mesh_mcast = 0;
|
||||
} else {
|
||||
/* DA TA mSA AE:SA */
|
||||
mesh_da = bcast;
|
||||
}
|
||||
}
|
||||
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
||||
mesh_da, sdata->vif.addr);
|
||||
rcu_read_unlock();
|
||||
if (is_mesh_mcast)
|
||||
if (is_multicast_ether_addr(mesh_da))
|
||||
/* DA TA mSA AE:SA */
|
||||
meshhdrlen =
|
||||
ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata,
|
||||
skb->data + ETH_ALEN,
|
||||
NULL);
|
||||
else
|
||||
/* RA TA mDA mSA AE:DA SA */
|
||||
meshhdrlen =
|
||||
ieee80211_new_mesh_header(&mesh_hdr,
|
||||
sdata,
|
||||
|
@ -1171,8 +1171,10 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
||||
goto out_err;
|
||||
}
|
||||
svc->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats);
|
||||
if (!svc->stats.cpustats)
|
||||
if (!svc->stats.cpustats) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* I'm the first user of the service */
|
||||
atomic_set(&svc->usecnt, 0);
|
||||
|
@ -249,12 +249,15 @@ static void death_by_event(unsigned long ul_conntrack)
|
||||
{
|
||||
struct nf_conn *ct = (void *)ul_conntrack;
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
||||
|
||||
BUG_ON(ecache == NULL);
|
||||
|
||||
if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
|
||||
/* bad luck, let's retry again */
|
||||
ct->timeout.expires = jiffies +
|
||||
ecache->timeout.expires = jiffies +
|
||||
(random32() % net->ct.sysctl_events_retry_timeout);
|
||||
add_timer(&ct->timeout);
|
||||
add_timer(&ecache->timeout);
|
||||
return;
|
||||
}
|
||||
/* we've got the event delivered, now it's dying */
|
||||
@ -268,6 +271,9 @@ static void death_by_event(unsigned long ul_conntrack)
|
||||
void nf_ct_insert_dying_list(struct nf_conn *ct)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
||||
|
||||
BUG_ON(ecache == NULL);
|
||||
|
||||
/* add this conntrack to the dying list */
|
||||
spin_lock_bh(&nf_conntrack_lock);
|
||||
@ -275,10 +281,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct)
|
||||
&net->ct.dying);
|
||||
spin_unlock_bh(&nf_conntrack_lock);
|
||||
/* set a new timer to retry event delivery */
|
||||
setup_timer(&ct->timeout, death_by_event, (unsigned long)ct);
|
||||
ct->timeout.expires = jiffies +
|
||||
setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
|
||||
ecache->timeout.expires = jiffies +
|
||||
(random32() % net->ct.sysctl_events_retry_timeout);
|
||||
add_timer(&ct->timeout);
|
||||
add_timer(&ecache->timeout);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
|
||||
|
||||
|
@ -2790,7 +2790,8 @@ static int __init ctnetlink_init(void)
|
||||
goto err_unreg_subsys;
|
||||
}
|
||||
|
||||
if (register_pernet_subsys(&ctnetlink_net_ops)) {
|
||||
ret = register_pernet_subsys(&ctnetlink_net_ops);
|
||||
if (ret < 0) {
|
||||
pr_err("ctnetlink_init: cannot register pernet operations\n");
|
||||
goto err_unreg_exp_subsys;
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ __build_packet_message(struct nfulnl_instance *inst,
|
||||
}
|
||||
|
||||
if (indev && skb_mac_header_was_set(skb)) {
|
||||
if (nla_put_be32(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
|
||||
if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
|
||||
nla_put_be16(inst->skb, NFULA_HWLEN,
|
||||
htons(skb->dev->hard_header_len)) ||
|
||||
nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
|
||||
@ -996,8 +996,10 @@ static int __init nfnetlink_log_init(void)
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create("nfnetlink_log", 0440,
|
||||
proc_net_netfilter, &nful_file_ops))
|
||||
proc_net_netfilter, &nful_file_ops)) {
|
||||
status = -ENOMEM;
|
||||
goto cleanup_logger;
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
|
||||
|
@ -1373,7 +1373,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
||||
dst_pid = addr->nl_pid;
|
||||
dst_group = ffs(addr->nl_groups);
|
||||
err = -EPERM;
|
||||
if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
|
||||
if ((dst_group || dst_pid) &&
|
||||
!netlink_capable(sock, NL_NONROOT_SEND))
|
||||
goto out;
|
||||
} else {
|
||||
dst_pid = nlk->dst_pid;
|
||||
@ -2147,6 +2148,7 @@ static void __init netlink_add_usersock_entry(void)
|
||||
rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
|
||||
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
|
||||
nl_table[NETLINK_USERSOCK].registered = 1;
|
||||
nl_table[NETLINK_USERSOCK].nl_nonroot = NL_NONROOT_SEND;
|
||||
|
||||
netlink_table_ungrab();
|
||||
}
|
||||
|
@ -1273,7 +1273,7 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
|
||||
spin_unlock(&f->lock);
|
||||
}
|
||||
|
||||
bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
|
||||
static bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
|
||||
{
|
||||
if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout)
|
||||
return true;
|
||||
|
@ -1994,8 +1994,10 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay)
|
||||
goto error;
|
||||
|
||||
x->outer_mode = xfrm_get_mode(x->props.mode, family);
|
||||
if (x->outer_mode == NULL)
|
||||
if (x->outer_mode == NULL) {
|
||||
err = -EPROTONOSUPPORT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (init_replay) {
|
||||
err = xfrm_init_replay(x);
|
||||
|
Loading…
Reference in New Issue
Block a user