diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-14 13:54:17 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-04-14 13:54:17 -0700 |
| commit | 2ee08a89634caf79bffc515f8e163988f83b7398 (patch) | |
| tree | e090693dc1c76a2dad454cb0b5ad9f17d6b00f44 /arch/x86/include | |
| parent | 1c3b68f0d55b5932eb38eda602a61aec6d6f5e5e (diff) | |
| parent | 3b19e22cffe61bcdf10ee5e7584cfa3c1c54dc92 (diff) | |
| download | lwn-2ee08a89634caf79bffc515f8e163988f83b7398.tar.gz lwn-2ee08a89634caf79bffc515f8e163988f83b7398.zip | |
Merge tag 'x86-asm-2026-04-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 asm from Ingo Molnar:
"x86 asm cleanups by Uros Bizjak:
- Remove unnecessary memory clobbers from FS/GS base (read-)
accessors and savesegment()
- Use ASM_INPUT_RM in __loadsegment_fs() to work around clang code
generation problems
- Implement loadsegment()/savesegment() macros with static inline
helpers
- Use savesegment() for segment register reads in ELF core dump and
__show_regs()
- Use correct type for 'gs' variable in __show_regs() to avoid
zero-extension
- Clean up 'sel' variable usage in do_set_thread_area()"
* tag 'x86-asm-2026-04-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/tls: Clean up 'sel' variable usage in do_set_thread_area()
x86/process/32: Use correct type for 'gs' variable in __show_regs() to avoid zero-extension
x86/process/64: Use savesegment() in __show_regs() instead of inline asm
x86/elf: Use savesegment() for segment register reads in ELF core dump
x86/asm/segment: Implement loadsegment()/savesegment() macros with static inline helpers
x86/asm/segment: Use ASM_INPUT_RM in __loadsegment_fs()
x86/asm/segment: Remove unnecessary "memory" clobber from savesegment()
x86/asm/fsgsbase: Remove unnecessary "memory" clobbers from FS/GS base (read-) accessors
Diffstat (limited to 'arch/x86/include')
| -rw-r--r-- | arch/x86/include/asm/elf.h | 9 | ||||
| -rw-r--r-- | arch/x86/include/asm/fsgsbase.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/segment.h | 59 |
3 files changed, 42 insertions, 30 deletions
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index 2ba5f166e58f..c7f98977663c 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -187,7 +187,6 @@ void set_personality_ia32(bool); #define ELF_CORE_COPY_REGS(pr_reg, regs) \ do { \ - unsigned v; \ (pr_reg)[0] = (regs)->r15; \ (pr_reg)[1] = (regs)->r14; \ (pr_reg)[2] = (regs)->r13; \ @@ -211,10 +210,10 @@ do { \ (pr_reg)[20] = (regs)->ss; \ (pr_reg)[21] = x86_fsbase_read_cpu(); \ (pr_reg)[22] = x86_gsbase_read_cpu_inactive(); \ - asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \ - asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \ - asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \ - asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v; \ + savesegment(ds, (pr_reg)[23]); \ + savesegment(es, (pr_reg)[24]); \ + savesegment(fs, (pr_reg)[25]); \ + savesegment(gs, (pr_reg)[26]); \ } while (0); /* I'm not sure if we can use '-' here */ diff --git a/arch/x86/include/asm/fsgsbase.h b/arch/x86/include/asm/fsgsbase.h index ab2547f97c2c..70ff4ef457b1 100644 --- a/arch/x86/include/asm/fsgsbase.h +++ b/arch/x86/include/asm/fsgsbase.h @@ -25,7 +25,7 @@ static __always_inline unsigned long rdfsbase(void) { unsigned long fsbase; - asm volatile("rdfsbase %0" : "=r" (fsbase) :: "memory"); + asm volatile("rdfsbase %0" : "=r" (fsbase)); return fsbase; } @@ -34,7 +34,7 @@ static __always_inline unsigned long rdgsbase(void) { unsigned long gsbase; - asm volatile("rdgsbase %0" : "=r" (gsbase) :: "memory"); + asm volatile("rdgsbase %0" : "=r" (gsbase)); return gsbase; } diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 9f5be2bbd291..dbd90fede5e7 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h @@ -302,19 +302,17 @@ extern const char xen_early_idt_handler_array[NUM_EXCEPTION_VECTORS][XEN_EARLY_I * failure to fully clear the cached descriptor is only observable for * FS and GS. */ -#define __loadsegment_simple(seg, value) \ -do { \ - unsigned short __val = (value); \ - \ - asm volatile(" \n" \ - "1: movl %k0,%%" #seg " \n" \ +#define LOAD_SEGMENT(seg) \ +static inline void __loadsegment_##seg(u16 value) \ +{ \ + asm volatile("1: movl %k0,%%" #seg "\n" \ _ASM_EXTABLE_TYPE_REG(1b, 1b, EX_TYPE_ZERO_REG, %k0)\ - : "+r" (__val) : : "memory"); \ -} while (0) + : "+r" (value) : : "memory"); \ +} -#define __loadsegment_ss(value) __loadsegment_simple(ss, (value)) -#define __loadsegment_ds(value) __loadsegment_simple(ds, (value)) -#define __loadsegment_es(value) __loadsegment_simple(es, (value)) +LOAD_SEGMENT(ss) +LOAD_SEGMENT(ds) +LOAD_SEGMENT(es) #ifdef CONFIG_X86_32 @@ -322,33 +320,48 @@ do { \ * On 32-bit systems, the hidden parts of FS and GS are unobservable if * the selector is NULL, so there's no funny business here. */ -#define __loadsegment_fs(value) __loadsegment_simple(fs, (value)) -#define __loadsegment_gs(value) __loadsegment_simple(gs, (value)) +LOAD_SEGMENT(fs) +LOAD_SEGMENT(gs) #else -static inline void __loadsegment_fs(unsigned short value) +static inline void __loadsegment_fs(u16 value) { - asm volatile(" \n" - "1: movw %0, %%fs \n" - "2: \n" - + asm volatile("1: movw %0, %%fs\n" + "2:\n" _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_CLEAR_FS) - - : : "rm" (value) : "memory"); + : : ASM_INPUT_RM (value) : "memory"); } /* __loadsegment_gs is intentionally undefined. Use load_gs_index instead. */ #endif -#define loadsegment(seg, value) __loadsegment_ ## seg (value) +#undef LOAD_SEGMENT + +#define loadsegment(seg, val) __loadsegment_##seg(val) /* * Save a segment register away: */ -#define savesegment(seg, value) \ - asm("movl %%" #seg ",%k0" : "=r" (value) : : "memory") +#define SAVE_SEGMENT(seg) \ +static inline unsigned long __savesegment_##seg(void) \ +{ \ + unsigned long v; \ + asm volatile("movl %%" #seg ",%k0" : "=r" (v)); \ + return v; \ +} + +SAVE_SEGMENT(cs) +SAVE_SEGMENT(ss) +SAVE_SEGMENT(ds) +SAVE_SEGMENT(es) +SAVE_SEGMENT(fs) +SAVE_SEGMENT(gs) + +#undef SAVE_SEGMENT + +#define savesegment(seg, var) ((var) = __savesegment_##seg()) #endif /* !__ASSEMBLER__ */ #endif /* __KERNEL__ */ |
