lkml.org 
[lkml]   [2020]   [Jun]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip: x86/fsgsbase] x86/fsgsbase/64: Enable FSGSBASE instructions in helper functions
    The following commit has been merged into the x86/fsgsbase branch of tip:

    Commit-ID: 58edfd2e0a93c9adc2f29902a0335af0584041a0
    Gitweb: https://git.kernel.org/tip/58edfd2e0a93c9adc2f29902a0335af0584041a0
    Author: Chang S. Bae <chang.seok.bae@intel.com>
    AuthorDate: Thu, 28 May 2020 16:13:50 -04:00
    Committer: Thomas Gleixner <tglx@linutronix.de>
    CommitterDate: Thu, 18 Jun 2020 15:47:00 +02:00

    x86/fsgsbase/64: Enable FSGSBASE instructions in helper functions

    Add cpu feature conditional FSGSBASE access to the relevant helper
    functions. That allows to accelerate certain FS/GS base operations in
    subsequent changes.

    Note, that while possible, the user space entry/exit GSBASE operations are
    not going to use the new FSGSBASE instructions. The reason is that it would
    require additional storage for the user space value which adds more
    complexity to the low level code and experiments have shown marginal
    benefit. This may be revisited later but for now the SWAPGS based handling
    in the entry code is preserved except for the paranoid entry/exit code.

    To preserve the SWAPGS entry mechanism introduce __[rd|wr]gsbase_inactive()
    helpers. Note, for Xen PV, paravirt hooks can be added later as they might
    allow a very efficient but different implementation.

    [ tglx: Massaged changelog, convert it to noinstr and force inline
    native_swapgs() ]

    Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Link: https://lkml.kernel.org/r/1557309753-24073-7-git-send-email-chang.seok.bae@intel.com
    Link: https://lkml.kernel.org/r/20200528201402.1708239-5-sashal@kernel.org


    ---
    arch/x86/include/asm/fsgsbase.h | 27 +++++-------
    arch/x86/include/asm/processor.h | 2 +-
    arch/x86/kernel/process_64.c | 68 +++++++++++++++++++++++++++++++-
    3 files changed, 81 insertions(+), 16 deletions(-)

    diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h
    index fdd1177..aefd537 100644
    --- a/arch/x86/include/asm/fsgsbase.h
    +++ b/arch/x86/include/asm/fsgsbase.h
    @@ -49,35 +49,32 @@ static __always_inline void wrgsbase(unsigned long gsbase)
    asm volatile("wrgsbase %0" :: "r" (gsbase) : "memory");
    }

    +#include <asm/cpufeature.h>
    +
    /* Helper functions for reading/writing FS/GS base */

    static inline unsigned long x86_fsbase_read_cpu(void)
    {
    unsigned long fsbase;

    - rdmsrl(MSR_FS_BASE, fsbase);
    + if (static_cpu_has(X86_FEATURE_FSGSBASE))
    + fsbase = rdfsbase();
    + else
    + rdmsrl(MSR_FS_BASE, fsbase);

    return fsbase;
    }

    -static inline unsigned long x86_gsbase_read_cpu_inactive(void)
    -{
    - unsigned long gsbase;
    -
    - rdmsrl(MSR_KERNEL_GS_BASE, gsbase);
    -
    - return gsbase;
    -}
    -
    static inline void x86_fsbase_write_cpu(unsigned long fsbase)
    {
    - wrmsrl(MSR_FS_BASE, fsbase);
    + if (static_cpu_has(X86_FEATURE_FSGSBASE))
    + wrfsbase(fsbase);
    + else
    + wrmsrl(MSR_FS_BASE, fsbase);
    }

    -static inline void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
    -{
    - wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
    -}
    +extern unsigned long x86_gsbase_read_cpu_inactive(void);
    +extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase);

    #endif /* CONFIG_X86_64 */

    diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
    index 42cd333..f66202d 100644
    --- a/arch/x86/include/asm/processor.h
    +++ b/arch/x86/include/asm/processor.h
    @@ -575,7 +575,7 @@ native_load_sp0(unsigned long sp0)
    this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
    }

    -static inline void native_swapgs(void)
    +static __always_inline void native_swapgs(void)
    {
    #ifdef CONFIG_X86_64
    asm volatile("swapgs" ::: "memory");
    diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
    index 9a97415..c41e0aa 100644
    --- a/arch/x86/kernel/process_64.c
    +++ b/arch/x86/kernel/process_64.c
    @@ -150,6 +150,44 @@ enum which_selector {
    };

    /*
    + * Out of line to be protected from kprobes and tracing. If this would be
    + * traced or probed than any access to a per CPU variable happens with
    + * the wrong GS.
    + *
    + * It is not used on Xen paravirt. When paravirt support is needed, it
    + * needs to be renamed with native_ prefix.
    + */
    +static noinstr unsigned long __rdgsbase_inactive(void)
    +{
    + unsigned long gsbase;
    +
    + lockdep_assert_irqs_disabled();
    +
    + native_swapgs();
    + gsbase = rdgsbase();
    + native_swapgs();
    +
    + return gsbase;
    +}
    +
    +/*
    + * Out of line to be protected from kprobes and tracing. If this would be
    + * traced or probed than any access to a per CPU variable happens with
    + * the wrong GS.
    + *
    + * It is not used on Xen paravirt. When paravirt support is needed, it
    + * needs to be renamed with native_ prefix.
    + */
    +static noinstr void __wrgsbase_inactive(unsigned long gsbase)
    +{
    + lockdep_assert_irqs_disabled();
    +
    + native_swapgs();
    + wrgsbase(gsbase);
    + native_swapgs();
    +}
    +
    +/*
    * Saves the FS or GS base for an outgoing thread if FSGSBASE extensions are
    * not available. The goal is to be reasonably fast on non-FSGSBASE systems.
    * It's forcibly inlined because it'll generate better code and this function
    @@ -327,6 +365,36 @@ static unsigned long x86_fsgsbase_read_task(struct task_struct *task,
    return base;
    }

    +unsigned long x86_gsbase_read_cpu_inactive(void)
    +{
    + unsigned long gsbase;
    +
    + if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
    + unsigned long flags;
    +
    + local_irq_save(flags);
    + gsbase = __rdgsbase_inactive();
    + local_irq_restore(flags);
    + } else {
    + rdmsrl(MSR_KERNEL_GS_BASE, gsbase);
    + }
    +
    + return gsbase;
    +}
    +
    +void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
    +{
    + if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
    + unsigned long flags;
    +
    + local_irq_save(flags);
    + __wrgsbase_inactive(gsbase);
    + local_irq_restore(flags);
    + } else {
    + wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
    + }
    +}
    +
    unsigned long x86_fsbase_read_task(struct task_struct *task)
    {
    unsigned long fsbase;
    \
     
     \ /
      Last update: 2020-06-18 15:56    [W:9.067 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site