Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+50 -36
+4 -5
arch/x86/include/asm/elf.h
··· 187 187 188 188 #define ELF_CORE_COPY_REGS(pr_reg, regs) \ 189 189 do { \ 190 - unsigned v; \ 191 190 (pr_reg)[0] = (regs)->r15; \ 192 191 (pr_reg)[1] = (regs)->r14; \ 193 192 (pr_reg)[2] = (regs)->r13; \ ··· 210 211 (pr_reg)[20] = (regs)->ss; \ 211 212 (pr_reg)[21] = x86_fsbase_read_cpu(); \ 212 213 (pr_reg)[22] = x86_gsbase_read_cpu_inactive(); \ 213 - asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \ 214 - asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \ 215 - asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \ 216 - asm("movl %%gs,%0" : "=r" (v)); (pr_reg)[26] = v; \ 214 + savesegment(ds, (pr_reg)[23]); \ 215 + savesegment(es, (pr_reg)[24]); \ 216 + savesegment(fs, (pr_reg)[25]); \ 217 + savesegment(gs, (pr_reg)[26]); \ 217 218 } while (0); 218 219 219 220 /* I'm not sure if we can use '-' here */
+2 -2
arch/x86/include/asm/fsgsbase.h
··· 25 25 { 26 26 unsigned long fsbase; 27 27 28 - asm volatile("rdfsbase %0" : "=r" (fsbase) :: "memory"); 28 + asm volatile("rdfsbase %0" : "=r" (fsbase)); 29 29 30 30 return fsbase; 31 31 } ··· 34 34 { 35 35 unsigned long gsbase; 36 36 37 - asm volatile("rdgsbase %0" : "=r" (gsbase) :: "memory"); 37 + asm volatile("rdgsbase %0" : "=r" (gsbase)); 38 38 39 39 return gsbase; 40 40 }
+36 -23
arch/x86/include/asm/segment.h
··· 302 302 * failure to fully clear the cached descriptor is only observable for 303 303 * FS and GS. 304 304 */ 305 - #define __loadsegment_simple(seg, value) \ 306 - do { \ 307 - unsigned short __val = (value); \ 308 - \ 309 - asm volatile(" \n" \ 310 - "1: movl %k0,%%" #seg " \n" \ 305 + #define LOAD_SEGMENT(seg) \ 306 + static inline void __loadsegment_##seg(u16 value) \ 307 + { \ 308 + asm volatile("1: movl %k0,%%" #seg "\n" \ 311 309 _ASM_EXTABLE_TYPE_REG(1b, 1b, EX_TYPE_ZERO_REG, %k0)\ 312 - : "+r" (__val) : : "memory"); \ 313 - } while (0) 310 + : "+r" (value) : : "memory"); \ 311 + } 314 312 315 - #define __loadsegment_ss(value) __loadsegment_simple(ss, (value)) 316 - #define __loadsegment_ds(value) __loadsegment_simple(ds, (value)) 317 - #define __loadsegment_es(value) __loadsegment_simple(es, (value)) 313 + LOAD_SEGMENT(ss) 314 + LOAD_SEGMENT(ds) 315 + LOAD_SEGMENT(es) 318 316 319 317 #ifdef CONFIG_X86_32 320 318 ··· 320 322 * On 32-bit systems, the hidden parts of FS and GS are unobservable if 321 323 * the selector is NULL, so there's no funny business here. 322 324 */ 323 - #define __loadsegment_fs(value) __loadsegment_simple(fs, (value)) 324 - #define __loadsegment_gs(value) __loadsegment_simple(gs, (value)) 325 + LOAD_SEGMENT(fs) 326 + LOAD_SEGMENT(gs) 325 327 326 328 #else 327 329 328 - static inline void __loadsegment_fs(unsigned short value) 330 + static inline void __loadsegment_fs(u16 value) 329 331 { 330 - asm volatile(" \n" 331 - "1: movw %0, %%fs \n" 332 - "2: \n" 333 - 332 + asm volatile("1: movw %0, %%fs\n" 333 + "2:\n" 334 334 _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_CLEAR_FS) 335 - 336 - : : "rm" (value) : "memory"); 335 + : : ASM_INPUT_RM (value) : "memory"); 337 336 } 338 337 339 338 /* __loadsegment_gs is intentionally undefined. Use load_gs_index instead. */ 340 339 341 340 #endif 342 341 343 - #define loadsegment(seg, value) __loadsegment_ ## seg (value) 342 + #undef LOAD_SEGMENT 343 + 344 + #define loadsegment(seg, val) __loadsegment_##seg(val) 344 345 345 346 /* 346 347 * Save a segment register away: 347 348 */ 348 - #define savesegment(seg, value) \ 349 - asm("movl %%" #seg ",%k0" : "=r" (value) : : "memory") 349 + #define SAVE_SEGMENT(seg) \ 350 + static inline unsigned long __savesegment_##seg(void) \ 351 + { \ 352 + unsigned long v; \ 353 + asm volatile("movl %%" #seg ",%k0" : "=r" (v)); \ 354 + return v; \ 355 + } 356 + 357 + SAVE_SEGMENT(cs) 358 + SAVE_SEGMENT(ss) 359 + SAVE_SEGMENT(ds) 360 + SAVE_SEGMENT(es) 361 + SAVE_SEGMENT(fs) 362 + SAVE_SEGMENT(gs) 363 + 364 + #undef SAVE_SEGMENT 365 + 366 + #define savesegment(seg, var) ((var) = __savesegment_##seg()) 350 367 351 368 #endif /* !__ASSEMBLER__ */ 352 369 #endif /* __KERNEL__ */
+1 -1
arch/x86/kernel/process_32.c
··· 61 61 { 62 62 unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; 63 63 unsigned long d0, d1, d2, d3, d6, d7; 64 - unsigned short gs; 64 + unsigned int gs; 65 65 66 66 savesegment(gs, gs); 67 67
+4 -4
arch/x86/kernel/process_64.c
··· 104 104 return; 105 105 } 106 106 107 - asm("movl %%ds,%0" : "=r" (ds)); 108 - asm("movl %%es,%0" : "=r" (es)); 109 - asm("movl %%fs,%0" : "=r" (fsindex)); 110 - asm("movl %%gs,%0" : "=r" (gsindex)); 107 + savesegment(ds, ds); 108 + savesegment(es, es); 109 + savesegment(fs, fsindex); 110 + savesegment(gs, gsindex); 111 111 112 112 rdmsrq(MSR_FS_BASE, fs); 113 113 rdmsrq(MSR_GS_BASE, gs);
+3 -1
arch/x86/kernel/tls.c
··· 117 117 int can_allocate) 118 118 { 119 119 struct user_desc info; 120 - unsigned short __maybe_unused sel, modified_sel; 120 + unsigned short modified_sel; 121 121 122 122 if (copy_from_user(&info, u_info, sizeof(info))) 123 123 return -EFAULT; ··· 153 153 modified_sel = (idx << 3) | 3; 154 154 155 155 if (p == current) { 156 + unsigned short sel; 157 + 156 158 #ifdef CONFIG_X86_64 157 159 savesegment(ds, sel); 158 160 if (sel == modified_sel)