Skip to content

Commit 58edfd2

Browse files
ChangSeokBaeKAGA-KOKO
authored andcommitted
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 <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent b15378c commit 58edfd2

File tree

3 files changed

+81
-16
lines changed

3 files changed

+81
-16
lines changed

arch/x86/include/asm/fsgsbase.h

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,35 +49,32 @@ static __always_inline void wrgsbase(unsigned long gsbase)
4949
asm volatile("wrgsbase %0" :: "r" (gsbase) : "memory");
5050
}
5151

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

5456
static inline unsigned long x86_fsbase_read_cpu(void)
5557
{
5658
unsigned long fsbase;
5759

58-
rdmsrl(MSR_FS_BASE, fsbase);
60+
if (static_cpu_has(X86_FEATURE_FSGSBASE))
61+
fsbase = rdfsbase();
62+
else
63+
rdmsrl(MSR_FS_BASE, fsbase);
5964

6065
return fsbase;
6166
}
6267

63-
static inline unsigned long x86_gsbase_read_cpu_inactive(void)
64-
{
65-
unsigned long gsbase;
66-
67-
rdmsrl(MSR_KERNEL_GS_BASE, gsbase);
68-
69-
return gsbase;
70-
}
71-
7268
static inline void x86_fsbase_write_cpu(unsigned long fsbase)
7369
{
74-
wrmsrl(MSR_FS_BASE, fsbase);
70+
if (static_cpu_has(X86_FEATURE_FSGSBASE))
71+
wrfsbase(fsbase);
72+
else
73+
wrmsrl(MSR_FS_BASE, fsbase);
7574
}
7675

77-
static inline void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
78-
{
79-
wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
80-
}
76+
extern unsigned long x86_gsbase_read_cpu_inactive(void);
77+
extern void x86_gsbase_write_cpu_inactive(unsigned long gsbase);
8178

8279
#endif /* CONFIG_X86_64 */
8380

arch/x86/include/asm/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ native_load_sp0(unsigned long sp0)
575575
this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
576576
}
577577

578-
static inline void native_swapgs(void)
578+
static __always_inline void native_swapgs(void)
579579
{
580580
#ifdef CONFIG_X86_64
581581
asm volatile("swapgs" ::: "memory");

arch/x86/kernel/process_64.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,44 @@ enum which_selector {
149149
GS
150150
};
151151

152+
/*
153+
* Out of line to be protected from kprobes and tracing. If this would be
154+
* traced or probed than any access to a per CPU variable happens with
155+
* the wrong GS.
156+
*
157+
* It is not used on Xen paravirt. When paravirt support is needed, it
158+
* needs to be renamed with native_ prefix.
159+
*/
160+
static noinstr unsigned long __rdgsbase_inactive(void)
161+
{
162+
unsigned long gsbase;
163+
164+
lockdep_assert_irqs_disabled();
165+
166+
native_swapgs();
167+
gsbase = rdgsbase();
168+
native_swapgs();
169+
170+
return gsbase;
171+
}
172+
173+
/*
174+
* Out of line to be protected from kprobes and tracing. If this would be
175+
* traced or probed than any access to a per CPU variable happens with
176+
* the wrong GS.
177+
*
178+
* It is not used on Xen paravirt. When paravirt support is needed, it
179+
* needs to be renamed with native_ prefix.
180+
*/
181+
static noinstr void __wrgsbase_inactive(unsigned long gsbase)
182+
{
183+
lockdep_assert_irqs_disabled();
184+
185+
native_swapgs();
186+
wrgsbase(gsbase);
187+
native_swapgs();
188+
}
189+
152190
/*
153191
* Saves the FS or GS base for an outgoing thread if FSGSBASE extensions are
154192
* not available. The goal is to be reasonably fast on non-FSGSBASE systems.
@@ -327,6 +365,36 @@ static unsigned long x86_fsgsbase_read_task(struct task_struct *task,
327365
return base;
328366
}
329367

368+
unsigned long x86_gsbase_read_cpu_inactive(void)
369+
{
370+
unsigned long gsbase;
371+
372+
if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
373+
unsigned long flags;
374+
375+
local_irq_save(flags);
376+
gsbase = __rdgsbase_inactive();
377+
local_irq_restore(flags);
378+
} else {
379+
rdmsrl(MSR_KERNEL_GS_BASE, gsbase);
380+
}
381+
382+
return gsbase;
383+
}
384+
385+
void x86_gsbase_write_cpu_inactive(unsigned long gsbase)
386+
{
387+
if (static_cpu_has(X86_FEATURE_FSGSBASE)) {
388+
unsigned long flags;
389+
390+
local_irq_save(flags);
391+
__wrgsbase_inactive(gsbase);
392+
local_irq_restore(flags);
393+
} else {
394+
wrmsrl(MSR_KERNEL_GS_BASE, gsbase);
395+
}
396+
}
397+
330398
unsigned long x86_fsbase_read_task(struct task_struct *task)
331399
{
332400
unsigned long fsbase;

0 commit comments

Comments
 (0)