[PATCH -tip 1/1] x86_32/segment: Always return correctly zero-extended values from savesegment_*()

From: Uros Bizjak

Date: Tue Apr 14 2026 - 03:48:20 EST


On 32-bit x86, reading segment registers into a 32-bit type can expose
undefined upper bits on older processors (e.g. Intel Quark X1000,
Pentium, and earlier), where bits 31:16 are not defined.

Introduce __seg_return_t as an intermediate type for __savesegment_*():
u16 on CONFIG_X86_32 and unsigned long otherwise.

As a result, __savesegment_*() now returns correctly zero-extended
value in all cases, avoiding propagation of undefined high bits on
32-bit systems while preserving existing behavior on 64-bit.

Signed-off-by: Uros Bizjak <ubizjak@xxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxxxx>
Cc: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>
Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
---
arch/x86/include/asm/segment.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index dbd90fede5e7..070ed87063e0 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -341,13 +341,23 @@ static inline void __loadsegment_fs(u16 value)

#define loadsegment(seg, val) __loadsegment_##seg(val)

+#ifdef CONFIG_X86_32
+/*
+ * Bits 31:16 are undefined for Intel Quark X1000 processors,
+ * Pentium, and earlier processors.
+ */
+typedef u16 __seg_return_t;
+#else
+typedef unsigned long __seg_return_t;
+#endif
+
/*
* Save a segment register away:
*/
#define SAVE_SEGMENT(seg) \
static inline unsigned long __savesegment_##seg(void) \
{ \
- unsigned long v; \
+ __seg_return_t v; \
asm volatile("movl %%" #seg ",%k0" : "=r" (v)); \
return v; \
}
--
2.53.0