Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/gsseg: Use the LKGS instruction if available for load_gs_index()

The LKGS instruction atomically loads a segment descriptor into the
%gs descriptor registers, *except* that %gs.base is unchanged, and the
base is instead loaded into MSR_IA32_KERNEL_GS_BASE, which is exactly
what we want this function to do.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Xin Li <xin3.li@intel.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20230112072032.35626-6-xin3.li@intel.com
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>

authored by

H. Peter Anvin (Intel) and committed by
Ingo Molnar
92cbbadf ae53fa18

+31 -4
+29 -4
arch/x86/include/asm/gsseg.h
··· 14 14 15 15 extern asmlinkage void asm_load_gs_index(u16 selector); 16 16 17 + /* Replace with "lkgs %di" once binutils support LKGS instruction */ 18 + #define LKGS_DI _ASM_BYTES(0xf2,0x0f,0x00,0xf7) 19 + 20 + static inline void native_lkgs(unsigned int selector) 21 + { 22 + u16 sel = selector; 23 + asm_inline volatile("1: " LKGS_DI 24 + _ASM_EXTABLE_TYPE_REG(1b, 1b, EX_TYPE_ZERO_REG, %k[sel]) 25 + : [sel] "+D" (sel)); 26 + } 27 + 17 28 static inline void native_load_gs_index(unsigned int selector) 18 29 { 19 - unsigned long flags; 30 + if (cpu_feature_enabled(X86_FEATURE_LKGS)) { 31 + native_lkgs(selector); 32 + } else { 33 + unsigned long flags; 20 34 21 - local_irq_save(flags); 22 - asm_load_gs_index(selector); 23 - local_irq_restore(flags); 35 + local_irq_save(flags); 36 + asm_load_gs_index(selector); 37 + local_irq_restore(flags); 38 + } 24 39 } 25 40 26 41 #endif /* CONFIG_X86_64 */ 42 + 43 + static inline void __init lkgs_init(void) 44 + { 45 + #ifdef CONFIG_PARAVIRT_XXL 46 + #ifdef CONFIG_X86_64 47 + if (cpu_feature_enabled(X86_FEATURE_LKGS)) 48 + pv_ops.cpu.load_gs_index = native_lkgs; 49 + #endif 50 + #endif 51 + } 27 52 28 53 #ifndef CONFIG_PARAVIRT_XXL 29 54
+1
arch/x86/kernel/cpu/common.c
··· 1960 1960 setup_cr_pinning(); 1961 1961 1962 1962 tsx_init(); 1963 + lkgs_init(); 1963 1964 } 1964 1965 1965 1966 void identify_secondary_cpu(struct cpuinfo_x86 *c)
+1
arch/x86/xen/enlighten_pv.c
··· 276 276 setup_clear_cpu_cap(X86_FEATURE_ACC); 277 277 setup_clear_cpu_cap(X86_FEATURE_X2APIC); 278 278 setup_clear_cpu_cap(X86_FEATURE_SME); 279 + setup_clear_cpu_cap(X86_FEATURE_LKGS); 279 280 280 281 /* 281 282 * Xen PV would need some work to support PCID: CR3 handling as well