Commit 2ee08a89 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 1c3b68f0 3b19e22c
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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 */
+2 −2
Original line number Diff line number Diff line
@@ -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;
}
+36 −23
Original line number Diff line number Diff line
@@ -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"
	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__ */
+1 −1
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
{
	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
	unsigned long d0, d1, d2, d3, d6, d7;
	unsigned short gs;
	unsigned int gs;

	savesegment(gs, gs);

+4 −4
Original line number Diff line number Diff line
@@ -104,10 +104,10 @@ void __show_regs(struct pt_regs *regs, enum show_regs_mode mode,
		return;
	}

	asm("movl %%ds,%0" : "=r" (ds));
	asm("movl %%es,%0" : "=r" (es));
	asm("movl %%fs,%0" : "=r" (fsindex));
	asm("movl %%gs,%0" : "=r" (gsindex));
	savesegment(ds, ds);
	savesegment(es, es);
	savesegment(fs, fsindex);
	savesegment(gs, gsindex);

	rdmsrq(MSR_FS_BASE, fs);
	rdmsrq(MSR_GS_BASE, gs);
Loading