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.

at v5.9 620 lines 16 kB view raw
1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 1994 Linus Torvalds 4 * 5 * Pentium III FXSR, SSE support 6 * General FPU state handling cleanups 7 * Gareth Hughes <gareth@valinux.com>, May 2000 8 * x86-64 work by Andi Kleen 2002 9 */ 10 11#ifndef _ASM_X86_FPU_INTERNAL_H 12#define _ASM_X86_FPU_INTERNAL_H 13 14#include <linux/compat.h> 15#include <linux/sched.h> 16#include <linux/slab.h> 17#include <linux/mm.h> 18 19#include <asm/user.h> 20#include <asm/fpu/api.h> 21#include <asm/fpu/xstate.h> 22#include <asm/cpufeature.h> 23#include <asm/trace/fpu.h> 24 25/* 26 * High level FPU state handling functions: 27 */ 28extern void fpu__prepare_read(struct fpu *fpu); 29extern void fpu__prepare_write(struct fpu *fpu); 30extern void fpu__save(struct fpu *fpu); 31extern int fpu__restore_sig(void __user *buf, int ia32_frame); 32extern void fpu__drop(struct fpu *fpu); 33extern int fpu__copy(struct task_struct *dst, struct task_struct *src); 34extern void fpu__clear_user_states(struct fpu *fpu); 35extern void fpu__clear_all(struct fpu *fpu); 36extern int fpu__exception_code(struct fpu *fpu, int trap_nr); 37 38/* 39 * Boot time FPU initialization functions: 40 */ 41extern void fpu__init_cpu(void); 42extern void fpu__init_system_xstate(void); 43extern void fpu__init_cpu_xstate(void); 44extern void fpu__init_system(struct cpuinfo_x86 *c); 45extern void fpu__init_check_bugs(void); 46extern void fpu__resume_cpu(void); 47extern u64 fpu__get_supported_xfeatures_mask(void); 48 49/* 50 * Debugging facility: 51 */ 52#ifdef CONFIG_X86_DEBUG_FPU 53# define WARN_ON_FPU(x) WARN_ON_ONCE(x) 54#else 55# define WARN_ON_FPU(x) ({ (void)(x); 0; }) 56#endif 57 58/* 59 * FPU related CPU feature flag helper routines: 60 */ 61static __always_inline __pure bool use_xsaveopt(void) 62{ 63 return static_cpu_has(X86_FEATURE_XSAVEOPT); 64} 65 66static __always_inline __pure bool use_xsave(void) 67{ 68 return static_cpu_has(X86_FEATURE_XSAVE); 69} 70 71static __always_inline __pure bool use_fxsr(void) 72{ 73 return static_cpu_has(X86_FEATURE_FXSR); 74} 75 76/* 77 * fpstate handling functions: 78 */ 79 80extern union fpregs_state init_fpstate; 81 82extern void fpstate_init(union fpregs_state *state); 83#ifdef CONFIG_MATH_EMULATION 84extern void fpstate_init_soft(struct swregs_state *soft); 85#else 86static inline void fpstate_init_soft(struct swregs_state *soft) {} 87#endif 88 89static inline void fpstate_init_xstate(struct xregs_state *xsave) 90{ 91 /* 92 * XRSTORS requires these bits set in xcomp_bv, or it will 93 * trigger #GP: 94 */ 95 xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all; 96} 97 98static inline void fpstate_init_fxstate(struct fxregs_state *fx) 99{ 100 fx->cwd = 0x37f; 101 fx->mxcsr = MXCSR_DEFAULT; 102} 103extern void fpstate_sanitize_xstate(struct fpu *fpu); 104 105#define user_insn(insn, output, input...) \ 106({ \ 107 int err; \ 108 \ 109 might_fault(); \ 110 \ 111 asm volatile(ASM_STAC "\n" \ 112 "1:" #insn "\n\t" \ 113 "2: " ASM_CLAC "\n" \ 114 ".section .fixup,\"ax\"\n" \ 115 "3: movl $-1,%[err]\n" \ 116 " jmp 2b\n" \ 117 ".previous\n" \ 118 _ASM_EXTABLE(1b, 3b) \ 119 : [err] "=r" (err), output \ 120 : "0"(0), input); \ 121 err; \ 122}) 123 124#define kernel_insn_err(insn, output, input...) \ 125({ \ 126 int err; \ 127 asm volatile("1:" #insn "\n\t" \ 128 "2:\n" \ 129 ".section .fixup,\"ax\"\n" \ 130 "3: movl $-1,%[err]\n" \ 131 " jmp 2b\n" \ 132 ".previous\n" \ 133 _ASM_EXTABLE(1b, 3b) \ 134 : [err] "=r" (err), output \ 135 : "0"(0), input); \ 136 err; \ 137}) 138 139#define kernel_insn(insn, output, input...) \ 140 asm volatile("1:" #insn "\n\t" \ 141 "2:\n" \ 142 _ASM_EXTABLE_HANDLE(1b, 2b, ex_handler_fprestore) \ 143 : output : input) 144 145static inline int copy_fregs_to_user(struct fregs_state __user *fx) 146{ 147 return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx)); 148} 149 150static inline int copy_fxregs_to_user(struct fxregs_state __user *fx) 151{ 152 if (IS_ENABLED(CONFIG_X86_32)) 153 return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx)); 154 else 155 return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx)); 156 157} 158 159static inline void copy_kernel_to_fxregs(struct fxregs_state *fx) 160{ 161 if (IS_ENABLED(CONFIG_X86_32)) 162 kernel_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 163 else 164 kernel_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); 165} 166 167static inline int copy_kernel_to_fxregs_err(struct fxregs_state *fx) 168{ 169 if (IS_ENABLED(CONFIG_X86_32)) 170 return kernel_insn_err(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 171 else 172 return kernel_insn_err(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); 173} 174 175static inline int copy_user_to_fxregs(struct fxregs_state __user *fx) 176{ 177 if (IS_ENABLED(CONFIG_X86_32)) 178 return user_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 179 else 180 return user_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx)); 181} 182 183static inline void copy_kernel_to_fregs(struct fregs_state *fx) 184{ 185 kernel_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 186} 187 188static inline int copy_kernel_to_fregs_err(struct fregs_state *fx) 189{ 190 return kernel_insn_err(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 191} 192 193static inline int copy_user_to_fregs(struct fregs_state __user *fx) 194{ 195 return user_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx)); 196} 197 198static inline void copy_fxregs_to_kernel(struct fpu *fpu) 199{ 200 if (IS_ENABLED(CONFIG_X86_32)) 201 asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave)); 202 else 203 asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave)); 204} 205 206/* These macros all use (%edi)/(%rdi) as the single memory argument. */ 207#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27" 208#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37" 209#define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f" 210#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f" 211#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f" 212 213#define XSTATE_OP(op, st, lmask, hmask, err) \ 214 asm volatile("1:" op "\n\t" \ 215 "xor %[err], %[err]\n" \ 216 "2:\n\t" \ 217 ".pushsection .fixup,\"ax\"\n\t" \ 218 "3: movl $-2,%[err]\n\t" \ 219 "jmp 2b\n\t" \ 220 ".popsection\n\t" \ 221 _ASM_EXTABLE(1b, 3b) \ 222 : [err] "=r" (err) \ 223 : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ 224 : "memory") 225 226/* 227 * If XSAVES is enabled, it replaces XSAVEOPT because it supports a compact 228 * format and supervisor states in addition to modified optimization in 229 * XSAVEOPT. 230 * 231 * Otherwise, if XSAVEOPT is enabled, XSAVEOPT replaces XSAVE because XSAVEOPT 232 * supports modified optimization which is not supported by XSAVE. 233 * 234 * We use XSAVE as a fallback. 235 * 236 * The 661 label is defined in the ALTERNATIVE* macros as the address of the 237 * original instruction which gets replaced. We need to use it here as the 238 * address of the instruction where we might get an exception at. 239 */ 240#define XSTATE_XSAVE(st, lmask, hmask, err) \ 241 asm volatile(ALTERNATIVE_2(XSAVE, \ 242 XSAVEOPT, X86_FEATURE_XSAVEOPT, \ 243 XSAVES, X86_FEATURE_XSAVES) \ 244 "\n" \ 245 "xor %[err], %[err]\n" \ 246 "3:\n" \ 247 ".pushsection .fixup,\"ax\"\n" \ 248 "4: movl $-2, %[err]\n" \ 249 "jmp 3b\n" \ 250 ".popsection\n" \ 251 _ASM_EXTABLE(661b, 4b) \ 252 : [err] "=r" (err) \ 253 : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ 254 : "memory") 255 256/* 257 * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact 258 * XSAVE area format. 259 */ 260#define XSTATE_XRESTORE(st, lmask, hmask) \ 261 asm volatile(ALTERNATIVE(XRSTOR, \ 262 XRSTORS, X86_FEATURE_XSAVES) \ 263 "\n" \ 264 "3:\n" \ 265 _ASM_EXTABLE_HANDLE(661b, 3b, ex_handler_fprestore)\ 266 : \ 267 : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ 268 : "memory") 269 270/* 271 * This function is called only during boot time when x86 caps are not set 272 * up and alternative can not be used yet. 273 */ 274static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate) 275{ 276 u64 mask = xfeatures_mask_all; 277 u32 lmask = mask; 278 u32 hmask = mask >> 32; 279 int err; 280 281 WARN_ON(system_state != SYSTEM_BOOTING); 282 283 if (boot_cpu_has(X86_FEATURE_XSAVES)) 284 XSTATE_OP(XSAVES, xstate, lmask, hmask, err); 285 else 286 XSTATE_OP(XSAVE, xstate, lmask, hmask, err); 287 288 /* We should never fault when copying to a kernel buffer: */ 289 WARN_ON_FPU(err); 290} 291 292/* 293 * This function is called only during boot time when x86 caps are not set 294 * up and alternative can not be used yet. 295 */ 296static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate) 297{ 298 u64 mask = -1; 299 u32 lmask = mask; 300 u32 hmask = mask >> 32; 301 int err; 302 303 WARN_ON(system_state != SYSTEM_BOOTING); 304 305 if (boot_cpu_has(X86_FEATURE_XSAVES)) 306 XSTATE_OP(XRSTORS, xstate, lmask, hmask, err); 307 else 308 XSTATE_OP(XRSTOR, xstate, lmask, hmask, err); 309 310 /* 311 * We should never fault when copying from a kernel buffer, and the FPU 312 * state we set at boot time should be valid. 313 */ 314 WARN_ON_FPU(err); 315} 316 317/* 318 * Save processor xstate to xsave area. 319 */ 320static inline void copy_xregs_to_kernel(struct xregs_state *xstate) 321{ 322 u64 mask = xfeatures_mask_all; 323 u32 lmask = mask; 324 u32 hmask = mask >> 32; 325 int err; 326 327 WARN_ON_FPU(!alternatives_patched); 328 329 XSTATE_XSAVE(xstate, lmask, hmask, err); 330 331 /* We should never fault when copying to a kernel buffer: */ 332 WARN_ON_FPU(err); 333} 334 335/* 336 * Restore processor xstate from xsave area. 337 */ 338static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask) 339{ 340 u32 lmask = mask; 341 u32 hmask = mask >> 32; 342 343 XSTATE_XRESTORE(xstate, lmask, hmask); 344} 345 346/* 347 * Save xstate to user space xsave area. 348 * 349 * We don't use modified optimization because xrstor/xrstors might track 350 * a different application. 351 * 352 * We don't use compacted format xsave area for 353 * backward compatibility for old applications which don't understand 354 * compacted format of xsave area. 355 */ 356static inline int copy_xregs_to_user(struct xregs_state __user *buf) 357{ 358 u64 mask = xfeatures_mask_user(); 359 u32 lmask = mask; 360 u32 hmask = mask >> 32; 361 int err; 362 363 /* 364 * Clear the xsave header first, so that reserved fields are 365 * initialized to zero. 366 */ 367 err = __clear_user(&buf->header, sizeof(buf->header)); 368 if (unlikely(err)) 369 return -EFAULT; 370 371 stac(); 372 XSTATE_OP(XSAVE, buf, lmask, hmask, err); 373 clac(); 374 375 return err; 376} 377 378/* 379 * Restore xstate from user space xsave area. 380 */ 381static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask) 382{ 383 struct xregs_state *xstate = ((__force struct xregs_state *)buf); 384 u32 lmask = mask; 385 u32 hmask = mask >> 32; 386 int err; 387 388 stac(); 389 XSTATE_OP(XRSTOR, xstate, lmask, hmask, err); 390 clac(); 391 392 return err; 393} 394 395/* 396 * Restore xstate from kernel space xsave area, return an error code instead of 397 * an exception. 398 */ 399static inline int copy_kernel_to_xregs_err(struct xregs_state *xstate, u64 mask) 400{ 401 u32 lmask = mask; 402 u32 hmask = mask >> 32; 403 int err; 404 405 if (static_cpu_has(X86_FEATURE_XSAVES)) 406 XSTATE_OP(XRSTORS, xstate, lmask, hmask, err); 407 else 408 XSTATE_OP(XRSTOR, xstate, lmask, hmask, err); 409 410 return err; 411} 412 413extern int copy_fpregs_to_fpstate(struct fpu *fpu); 414 415static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask) 416{ 417 if (use_xsave()) { 418 copy_kernel_to_xregs(&fpstate->xsave, mask); 419 } else { 420 if (use_fxsr()) 421 copy_kernel_to_fxregs(&fpstate->fxsave); 422 else 423 copy_kernel_to_fregs(&fpstate->fsave); 424 } 425} 426 427static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate) 428{ 429 /* 430 * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is 431 * pending. Clear the x87 state here by setting it to fixed values. 432 * "m" is a random variable that should be in L1. 433 */ 434 if (unlikely(static_cpu_has_bug(X86_BUG_FXSAVE_LEAK))) { 435 asm volatile( 436 "fnclex\n\t" 437 "emms\n\t" 438 "fildl %P[addr]" /* set F?P to defined value */ 439 : : [addr] "m" (fpstate)); 440 } 441 442 __copy_kernel_to_fpregs(fpstate, -1); 443} 444 445extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size); 446 447/* 448 * FPU context switch related helper methods: 449 */ 450 451DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx); 452 453/* 454 * The in-register FPU state for an FPU context on a CPU is assumed to be 455 * valid if the fpu->last_cpu matches the CPU, and the fpu_fpregs_owner_ctx 456 * matches the FPU. 457 * 458 * If the FPU register state is valid, the kernel can skip restoring the 459 * FPU state from memory. 460 * 461 * Any code that clobbers the FPU registers or updates the in-memory 462 * FPU state for a task MUST let the rest of the kernel know that the 463 * FPU registers are no longer valid for this task. 464 * 465 * Either one of these invalidation functions is enough. Invalidate 466 * a resource you control: CPU if using the CPU for something else 467 * (with preemption disabled), FPU for the current task, or a task that 468 * is prevented from running by the current task. 469 */ 470static inline void __cpu_invalidate_fpregs_state(void) 471{ 472 __this_cpu_write(fpu_fpregs_owner_ctx, NULL); 473} 474 475static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu) 476{ 477 fpu->last_cpu = -1; 478} 479 480static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu) 481{ 482 return fpu == this_cpu_read(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu; 483} 484 485/* 486 * These generally need preemption protection to work, 487 * do try to avoid using these on their own: 488 */ 489static inline void fpregs_deactivate(struct fpu *fpu) 490{ 491 this_cpu_write(fpu_fpregs_owner_ctx, NULL); 492 trace_x86_fpu_regs_deactivated(fpu); 493} 494 495static inline void fpregs_activate(struct fpu *fpu) 496{ 497 this_cpu_write(fpu_fpregs_owner_ctx, fpu); 498 trace_x86_fpu_regs_activated(fpu); 499} 500 501/* 502 * Internal helper, do not use directly. Use switch_fpu_return() instead. 503 */ 504static inline void __fpregs_load_activate(void) 505{ 506 struct fpu *fpu = &current->thread.fpu; 507 int cpu = smp_processor_id(); 508 509 if (WARN_ON_ONCE(current->flags & PF_KTHREAD)) 510 return; 511 512 if (!fpregs_state_valid(fpu, cpu)) { 513 copy_kernel_to_fpregs(&fpu->state); 514 fpregs_activate(fpu); 515 fpu->last_cpu = cpu; 516 } 517 clear_thread_flag(TIF_NEED_FPU_LOAD); 518} 519 520/* 521 * FPU state switching for scheduling. 522 * 523 * This is a two-stage process: 524 * 525 * - switch_fpu_prepare() saves the old state. 526 * This is done within the context of the old process. 527 * 528 * - switch_fpu_finish() sets TIF_NEED_FPU_LOAD; the floating point state 529 * will get loaded on return to userspace, or when the kernel needs it. 530 * 531 * If TIF_NEED_FPU_LOAD is cleared then the CPU's FPU registers 532 * are saved in the current thread's FPU register state. 533 * 534 * If TIF_NEED_FPU_LOAD is set then CPU's FPU registers may not 535 * hold current()'s FPU registers. It is required to load the 536 * registers before returning to userland or using the content 537 * otherwise. 538 * 539 * The FPU context is only stored/restored for a user task and 540 * PF_KTHREAD is used to distinguish between kernel and user threads. 541 */ 542static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu) 543{ 544 if (static_cpu_has(X86_FEATURE_FPU) && !(current->flags & PF_KTHREAD)) { 545 if (!copy_fpregs_to_fpstate(old_fpu)) 546 old_fpu->last_cpu = -1; 547 else 548 old_fpu->last_cpu = cpu; 549 550 /* But leave fpu_fpregs_owner_ctx! */ 551 trace_x86_fpu_regs_deactivated(old_fpu); 552 } 553} 554 555/* 556 * Misc helper functions: 557 */ 558 559/* 560 * Load PKRU from the FPU context if available. Delay loading of the 561 * complete FPU state until the return to userland. 562 */ 563static inline void switch_fpu_finish(struct fpu *new_fpu) 564{ 565 u32 pkru_val = init_pkru_value; 566 struct pkru_state *pk; 567 568 if (!static_cpu_has(X86_FEATURE_FPU)) 569 return; 570 571 set_thread_flag(TIF_NEED_FPU_LOAD); 572 573 if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) 574 return; 575 576 /* 577 * PKRU state is switched eagerly because it needs to be valid before we 578 * return to userland e.g. for a copy_to_user() operation. 579 */ 580 if (current->mm) { 581 pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU); 582 if (pk) 583 pkru_val = pk->pkru; 584 } 585 __write_pkru(pkru_val); 586} 587 588/* 589 * MXCSR and XCR definitions: 590 */ 591 592static inline void ldmxcsr(u32 mxcsr) 593{ 594 asm volatile("ldmxcsr %0" :: "m" (mxcsr)); 595} 596 597extern unsigned int mxcsr_feature_mask; 598 599#define XCR_XFEATURE_ENABLED_MASK 0x00000000 600 601static inline u64 xgetbv(u32 index) 602{ 603 u32 eax, edx; 604 605 asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */ 606 : "=a" (eax), "=d" (edx) 607 : "c" (index)); 608 return eax + ((u64)edx << 32); 609} 610 611static inline void xsetbv(u32 index, u64 value) 612{ 613 u32 eax = value; 614 u32 edx = value >> 32; 615 616 asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */ 617 : : "a" (eax), "d" (edx), "c" (index)); 618} 619 620#endif /* _ASM_X86_FPU_INTERNAL_H */