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

From: Uros Bizjak

Date: Tue Apr 14 2026 - 03:48:06 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.

As a result, undefined upper bits may be stored in variables
(e.g. saved_fs and saved_gs in apm_32.c), structures (e.g. thread_struct.gs)
and arrays (e.g. elf_gregset_t[]). Some of these are later used, for
example in process_32.c::__switch_to():

if (prev->gs | next->gs)
loadsegment(gs, next->gs);

which results in unneccessary reloads.

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

This ensures that __savesegment_*() returns correctly zero-extended
values in all cases, avoiding propagation of undefined high bits on
32-bit systems while preserving existing behavior on 64-bit.

A follow-up patch can remove the majority of zero-extensions by addressing
a long-standing XXX comment in thread_struct and reusing gsindex instead of
gs for 32-bit x86 targets as well.

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>

Uros Bizjak (1):
x86_32/segment: Always return correctly zero-extended values from
savesegment_*()

arch/x86/include/asm/segment.h | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

--
2.53.0