summaryrefslogtreecommitdiff
path: root/arch/x86/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-14 13:54:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-14 13:54:17 -0700
commit2ee08a89634caf79bffc515f8e163988f83b7398 (patch)
treee090693dc1c76a2dad454cb0b5ad9f17d6b00f44 /arch/x86/include
parent1c3b68f0d55b5932eb38eda602a61aec6d6f5e5e (diff)
parent3b19e22cffe61bcdf10ee5e7584cfa3c1c54dc92 (diff)
downloadlwn-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.h9
-rw-r--r--arch/x86/include/asm/fsgsbase.h4
-rw-r--r--arch/x86/include/asm/segment.h59
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__ */