70f43ea3a3
- Make LAM enablement safe vs. kernel threads using a process mm temporarily as switching back to the process would not update CR3 and therefore not enable LAM causing faults in user space when using tagged pointers. Cure it by synchronizing LAM enablement via IPIs to all CPUs which use the related mm. - Cure a LAM harmless inconsistency between CR3 and the state during context switch. It's both confusing and prone to lead to real bugs - Handle alt stack handling for threads which run with a non-zero protection key. The non-zero key prevents the kernel to access the alternate stack. Cure it by temporarily enabling all protection keys for the alternate stack setup/restore operations. - Provide a EFI config table identity mapping for kexec kernel to prevent kexec fails because the new kernel cannot access the config table array - Use GB pages only when a full GB is mapped in the identity map as otherwise the CPU can speculate into reserved areas after the end of memory which causes malfunction on UV systems. - Remove the noisy and pointless SRAT table dump during boot - Use is_ioremap_addr() for iounmap() address range checks instead of high_memory. is_ioremap_addr() is more precise. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmbpPpYTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoYddD/9HeH5/rpWS3JU4ZVC+huY28uJuwAFW ER48zniRbmuz8y+dZZ6K8uvqoWB+ro+yNjA9Jhm9nHUzhs7kE5O8+bmkUi6HXViW 6zS6PW95+u80dmSGy1Gna0SU3158OyBf2X61SySJABLLek7WwrR7jakkgrDBVtL5 ILKS/dUwIrUPoVlszCh9uE0Kj6gdFquooE06sif5EIibnhSgSXfr2EbGj0Qq/YYf FYfpggSSVpTXFSkZSB2VCEqK66jaGUfKzZ6v1DkSioChUCsky2OO6zD9pk0dMixO a/0XvRUo3OhiXZbj1tPUtxaEBgJdigpsxke7xQSVxSl+DNNuapiybpgAzFM5Xh+m yFcP66nIpJcHE10vjVR3jSUlTSb2zk+v9d1Ujj10G1h8RHLTfsTCRHgzs7P0/nkE NJleWstYVRV5rFpPLoY0ryQmjW/PzYokkaqWKI12Lhxg4ojijZso3pS8WfOsk1/B 081tOZERWeGnJEOOJwwYE1wt0Qq8th4S9b2/fz3vk2fsEHIf42s4fKQwy1CxKopb PyIrgnZyWx6ueX9QaIGIzGV1GsY4FKMgFJVOyVb0D0stMnr1ty2m3993eNs/nCXy +rHPMwFteLcwiWp/C3hq5IQd7uEvmRt/mYJ5hdvCj5wCIkXI3JtgsXfLSVs3Ln4f R6HvZehYmbJoNQ== =VZcR -----END PGP SIGNATURE----- Merge tag 'x86-mm-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 memory management updates from Thomas Gleixner: - Make LAM enablement safe vs. kernel threads using a process mm temporarily as switching back to the process would not update CR3 and therefore not enable LAM causing faults in user space when using tagged pointers. Cure it by synchronizing LAM enablement via IPIs to all CPUs which use the related mm. - Cure a LAM harmless inconsistency between CR3 and the state during context switch. It's both confusing and prone to lead to real bugs - Handle alt stack handling for threads which run with a non-zero protection key. The non-zero key prevents the kernel to access the alternate stack. Cure it by temporarily enabling all protection keys for the alternate stack setup/restore operations. - Provide a EFI config table identity mapping for kexec kernel to prevent kexec fails because the new kernel cannot access the config table array - Use GB pages only when a full GB is mapped in the identity map as otherwise the CPU can speculate into reserved areas after the end of memory which causes malfunction on UV systems. - Remove the noisy and pointless SRAT table dump during boot - Use is_ioremap_addr() for iounmap() address range checks instead of high_memory. is_ioremap_addr() is more precise. * tag 'x86-mm-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/ioremap: Improve iounmap() address range checks x86/mm: Remove duplicate check from build_cr3() x86/mm: Remove unused NX related declarations x86/mm: Remove unused CR3_HW_ASID_BITS x86/mm: Don't print out SRAT table information x86/mm/ident_map: Use gbpages only where full GB page should be mapped. x86/kexec: Add EFI config table identity mapping for kexec kernel selftests/mm: Add new testcases for pkeys x86/pkeys: Restore altstack access in sigreturn() x86/pkeys: Update PKRU to enable all pkeys before XSAVE x86/pkeys: Add helper functions to update PKRU on the sigframe x86/pkeys: Add PKRU as a parameter in signal handling functions x86/mm: Cleanup prctl_enable_tagged_addr() nr_bits error checking x86/mm: Fix LAM inconsistency during context switch x86/mm: Use IPIs to synchronize LAM enablement
1946 lines
53 KiB
C
1946 lines
53 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* xsave/xrstor support.
|
|
*
|
|
* Author: Suresh Siddha <suresh.b.siddha@intel.com>
|
|
*/
|
|
#include <linux/bitops.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/nospec.h>
|
|
#include <linux/pkeys.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/coredump.h>
|
|
|
|
#include <asm/fpu/api.h>
|
|
#include <asm/fpu/regset.h>
|
|
#include <asm/fpu/signal.h>
|
|
#include <asm/fpu/xcr.h>
|
|
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/prctl.h>
|
|
#include <asm/elf.h>
|
|
|
|
#include <uapi/asm/elf.h>
|
|
|
|
#include "context.h"
|
|
#include "internal.h"
|
|
#include "legacy.h"
|
|
#include "xstate.h"
|
|
|
|
#define for_each_extended_xfeature(bit, mask) \
|
|
(bit) = FIRST_EXTENDED_XFEATURE; \
|
|
for_each_set_bit_from(bit, (unsigned long *)&(mask), 8 * sizeof(mask))
|
|
|
|
/*
|
|
* Although we spell it out in here, the Processor Trace
|
|
* xfeature is completely unused. We use other mechanisms
|
|
* to save/restore PT state in Linux.
|
|
*/
|
|
static const char *xfeature_names[] =
|
|
{
|
|
"x87 floating point registers",
|
|
"SSE registers",
|
|
"AVX registers",
|
|
"MPX bounds registers",
|
|
"MPX CSR",
|
|
"AVX-512 opmask",
|
|
"AVX-512 Hi256",
|
|
"AVX-512 ZMM_Hi256",
|
|
"Processor Trace (unused)",
|
|
"Protection Keys User registers",
|
|
"PASID state",
|
|
"Control-flow User registers",
|
|
"Control-flow Kernel registers (unused)",
|
|
"unknown xstate feature",
|
|
"unknown xstate feature",
|
|
"unknown xstate feature",
|
|
"unknown xstate feature",
|
|
"AMX Tile config",
|
|
"AMX Tile data",
|
|
"unknown xstate feature",
|
|
};
|
|
|
|
static unsigned short xsave_cpuid_features[] __initdata = {
|
|
[XFEATURE_FP] = X86_FEATURE_FPU,
|
|
[XFEATURE_SSE] = X86_FEATURE_XMM,
|
|
[XFEATURE_YMM] = X86_FEATURE_AVX,
|
|
[XFEATURE_BNDREGS] = X86_FEATURE_MPX,
|
|
[XFEATURE_BNDCSR] = X86_FEATURE_MPX,
|
|
[XFEATURE_OPMASK] = X86_FEATURE_AVX512F,
|
|
[XFEATURE_ZMM_Hi256] = X86_FEATURE_AVX512F,
|
|
[XFEATURE_Hi16_ZMM] = X86_FEATURE_AVX512F,
|
|
[XFEATURE_PT_UNIMPLEMENTED_SO_FAR] = X86_FEATURE_INTEL_PT,
|
|
[XFEATURE_PKRU] = X86_FEATURE_OSPKE,
|
|
[XFEATURE_PASID] = X86_FEATURE_ENQCMD,
|
|
[XFEATURE_CET_USER] = X86_FEATURE_SHSTK,
|
|
[XFEATURE_XTILE_CFG] = X86_FEATURE_AMX_TILE,
|
|
[XFEATURE_XTILE_DATA] = X86_FEATURE_AMX_TILE,
|
|
};
|
|
|
|
static unsigned int xstate_offsets[XFEATURE_MAX] __ro_after_init =
|
|
{ [ 0 ... XFEATURE_MAX - 1] = -1};
|
|
static unsigned int xstate_sizes[XFEATURE_MAX] __ro_after_init =
|
|
{ [ 0 ... XFEATURE_MAX - 1] = -1};
|
|
static unsigned int xstate_flags[XFEATURE_MAX] __ro_after_init;
|
|
|
|
#define XSTATE_FLAG_SUPERVISOR BIT(0)
|
|
#define XSTATE_FLAG_ALIGNED64 BIT(1)
|
|
|
|
/*
|
|
* Return whether the system supports a given xfeature.
|
|
*
|
|
* Also return the name of the (most advanced) feature that the caller requested:
|
|
*/
|
|
int cpu_has_xfeatures(u64 xfeatures_needed, const char **feature_name)
|
|
{
|
|
u64 xfeatures_missing = xfeatures_needed & ~fpu_kernel_cfg.max_features;
|
|
|
|
if (unlikely(feature_name)) {
|
|
long xfeature_idx, max_idx;
|
|
u64 xfeatures_print;
|
|
/*
|
|
* So we use FLS here to be able to print the most advanced
|
|
* feature that was requested but is missing. So if a driver
|
|
* asks about "XFEATURE_MASK_SSE | XFEATURE_MASK_YMM" we'll print the
|
|
* missing AVX feature - this is the most informative message
|
|
* to users:
|
|
*/
|
|
if (xfeatures_missing)
|
|
xfeatures_print = xfeatures_missing;
|
|
else
|
|
xfeatures_print = xfeatures_needed;
|
|
|
|
xfeature_idx = fls64(xfeatures_print)-1;
|
|
max_idx = ARRAY_SIZE(xfeature_names)-1;
|
|
xfeature_idx = min(xfeature_idx, max_idx);
|
|
|
|
*feature_name = xfeature_names[xfeature_idx];
|
|
}
|
|
|
|
if (xfeatures_missing)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
EXPORT_SYMBOL_GPL(cpu_has_xfeatures);
|
|
|
|
static bool xfeature_is_aligned64(int xfeature_nr)
|
|
{
|
|
return xstate_flags[xfeature_nr] & XSTATE_FLAG_ALIGNED64;
|
|
}
|
|
|
|
static bool xfeature_is_supervisor(int xfeature_nr)
|
|
{
|
|
return xstate_flags[xfeature_nr] & XSTATE_FLAG_SUPERVISOR;
|
|
}
|
|
|
|
static unsigned int xfeature_get_offset(u64 xcomp_bv, int xfeature)
|
|
{
|
|
unsigned int offs, i;
|
|
|
|
/*
|
|
* Non-compacted format and legacy features use the cached fixed
|
|
* offsets.
|
|
*/
|
|
if (!cpu_feature_enabled(X86_FEATURE_XCOMPACTED) ||
|
|
xfeature <= XFEATURE_SSE)
|
|
return xstate_offsets[xfeature];
|
|
|
|
/*
|
|
* Compacted format offsets depend on the actual content of the
|
|
* compacted xsave area which is determined by the xcomp_bv header
|
|
* field.
|
|
*/
|
|
offs = FXSAVE_SIZE + XSAVE_HDR_SIZE;
|
|
for_each_extended_xfeature(i, xcomp_bv) {
|
|
if (xfeature_is_aligned64(i))
|
|
offs = ALIGN(offs, 64);
|
|
if (i == xfeature)
|
|
break;
|
|
offs += xstate_sizes[i];
|
|
}
|
|
return offs;
|
|
}
|
|
|
|
/*
|
|
* Enable the extended processor state save/restore feature.
|
|
* Called once per CPU onlining.
|
|
*/
|
|
void fpu__init_cpu_xstate(void)
|
|
{
|
|
if (!boot_cpu_has(X86_FEATURE_XSAVE) || !fpu_kernel_cfg.max_features)
|
|
return;
|
|
|
|
cr4_set_bits(X86_CR4_OSXSAVE);
|
|
|
|
/*
|
|
* Must happen after CR4 setup and before xsetbv() to allow KVM
|
|
* lazy passthrough. Write independent of the dynamic state static
|
|
* key as that does not work on the boot CPU. This also ensures
|
|
* that any stale state is wiped out from XFD. Reset the per CPU
|
|
* xfd cache too.
|
|
*/
|
|
if (cpu_feature_enabled(X86_FEATURE_XFD))
|
|
xfd_set_state(init_fpstate.xfd);
|
|
|
|
/*
|
|
* XCR_XFEATURE_ENABLED_MASK (aka. XCR0) sets user features
|
|
* managed by XSAVE{C, OPT, S} and XRSTOR{S}. Only XSAVE user
|
|
* states can be set here.
|
|
*/
|
|
xsetbv(XCR_XFEATURE_ENABLED_MASK, fpu_user_cfg.max_features);
|
|
|
|
/*
|
|
* MSR_IA32_XSS sets supervisor states managed by XSAVES.
|
|
*/
|
|
if (boot_cpu_has(X86_FEATURE_XSAVES)) {
|
|
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() |
|
|
xfeatures_mask_independent());
|
|
}
|
|
}
|
|
|
|
static bool xfeature_enabled(enum xfeature xfeature)
|
|
{
|
|
return fpu_kernel_cfg.max_features & BIT_ULL(xfeature);
|
|
}
|
|
|
|
/*
|
|
* Record the offsets and sizes of various xstates contained
|
|
* in the XSAVE state memory layout.
|
|
*/
|
|
static void __init setup_xstate_cache(void)
|
|
{
|
|
u32 eax, ebx, ecx, edx, i;
|
|
/* start at the beginning of the "extended state" */
|
|
unsigned int last_good_offset = offsetof(struct xregs_state,
|
|
extended_state_area);
|
|
/*
|
|
* The FP xstates and SSE xstates are legacy states. They are always
|
|
* in the fixed offsets in the xsave area in either compacted form
|
|
* or standard form.
|
|
*/
|
|
xstate_offsets[XFEATURE_FP] = 0;
|
|
xstate_sizes[XFEATURE_FP] = offsetof(struct fxregs_state,
|
|
xmm_space);
|
|
|
|
xstate_offsets[XFEATURE_SSE] = xstate_sizes[XFEATURE_FP];
|
|
xstate_sizes[XFEATURE_SSE] = sizeof_field(struct fxregs_state,
|
|
xmm_space);
|
|
|
|
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
|
|
cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
|
|
|
|
xstate_sizes[i] = eax;
|
|
xstate_flags[i] = ecx;
|
|
|
|
/*
|
|
* If an xfeature is supervisor state, the offset in EBX is
|
|
* invalid, leave it to -1.
|
|
*/
|
|
if (xfeature_is_supervisor(i))
|
|
continue;
|
|
|
|
xstate_offsets[i] = ebx;
|
|
|
|
/*
|
|
* In our xstate size checks, we assume that the highest-numbered
|
|
* xstate feature has the highest offset in the buffer. Ensure
|
|
* it does.
|
|
*/
|
|
WARN_ONCE(last_good_offset > xstate_offsets[i],
|
|
"x86/fpu: misordered xstate at %d\n", last_good_offset);
|
|
|
|
last_good_offset = xstate_offsets[i];
|
|
}
|
|
}
|
|
|
|
static void __init print_xstate_feature(u64 xstate_mask)
|
|
{
|
|
const char *feature_name;
|
|
|
|
if (cpu_has_xfeatures(xstate_mask, &feature_name))
|
|
pr_info("x86/fpu: Supporting XSAVE feature 0x%03Lx: '%s'\n", xstate_mask, feature_name);
|
|
}
|
|
|
|
/*
|
|
* Print out all the supported xstate features:
|
|
*/
|
|
static void __init print_xstate_features(void)
|
|
{
|
|
print_xstate_feature(XFEATURE_MASK_FP);
|
|
print_xstate_feature(XFEATURE_MASK_SSE);
|
|
print_xstate_feature(XFEATURE_MASK_YMM);
|
|
print_xstate_feature(XFEATURE_MASK_BNDREGS);
|
|
print_xstate_feature(XFEATURE_MASK_BNDCSR);
|
|
print_xstate_feature(XFEATURE_MASK_OPMASK);
|
|
print_xstate_feature(XFEATURE_MASK_ZMM_Hi256);
|
|
print_xstate_feature(XFEATURE_MASK_Hi16_ZMM);
|
|
print_xstate_feature(XFEATURE_MASK_PKRU);
|
|
print_xstate_feature(XFEATURE_MASK_PASID);
|
|
print_xstate_feature(XFEATURE_MASK_CET_USER);
|
|
print_xstate_feature(XFEATURE_MASK_XTILE_CFG);
|
|
print_xstate_feature(XFEATURE_MASK_XTILE_DATA);
|
|
}
|
|
|
|
/*
|
|
* This check is important because it is easy to get XSTATE_*
|
|
* confused with XSTATE_BIT_*.
|
|
*/
|
|
#define CHECK_XFEATURE(nr) do { \
|
|
WARN_ON(nr < FIRST_EXTENDED_XFEATURE); \
|
|
WARN_ON(nr >= XFEATURE_MAX); \
|
|
} while (0)
|
|
|
|
/*
|
|
* Print out xstate component offsets and sizes
|
|
*/
|
|
static void __init print_xstate_offset_size(void)
|
|
{
|
|
int i;
|
|
|
|
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
|
|
pr_info("x86/fpu: xstate_offset[%d]: %4d, xstate_sizes[%d]: %4d\n",
|
|
i, xfeature_get_offset(fpu_kernel_cfg.max_features, i),
|
|
i, xstate_sizes[i]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function is called only during boot time when x86 caps are not set
|
|
* up and alternative can not be used yet.
|
|
*/
|
|
static __init void os_xrstor_booting(struct xregs_state *xstate)
|
|
{
|
|
u64 mask = fpu_kernel_cfg.max_features & XFEATURE_MASK_FPSTATE;
|
|
u32 lmask = mask;
|
|
u32 hmask = mask >> 32;
|
|
int err;
|
|
|
|
if (cpu_feature_enabled(X86_FEATURE_XSAVES))
|
|
XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
|
|
else
|
|
XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
|
|
|
|
/*
|
|
* We should never fault when copying from a kernel buffer, and the FPU
|
|
* state we set at boot time should be valid.
|
|
*/
|
|
WARN_ON_FPU(err);
|
|
}
|
|
|
|
/*
|
|
* All supported features have either init state all zeros or are
|
|
* handled in setup_init_fpu() individually. This is an explicit
|
|
* feature list and does not use XFEATURE_MASK*SUPPORTED to catch
|
|
* newly added supported features at build time and make people
|
|
* actually look at the init state for the new feature.
|
|
*/
|
|
#define XFEATURES_INIT_FPSTATE_HANDLED \
|
|
(XFEATURE_MASK_FP | \
|
|
XFEATURE_MASK_SSE | \
|
|
XFEATURE_MASK_YMM | \
|
|
XFEATURE_MASK_OPMASK | \
|
|
XFEATURE_MASK_ZMM_Hi256 | \
|
|
XFEATURE_MASK_Hi16_ZMM | \
|
|
XFEATURE_MASK_PKRU | \
|
|
XFEATURE_MASK_BNDREGS | \
|
|
XFEATURE_MASK_BNDCSR | \
|
|
XFEATURE_MASK_PASID | \
|
|
XFEATURE_MASK_CET_USER | \
|
|
XFEATURE_MASK_XTILE)
|
|
|
|
/*
|
|
* setup the xstate image representing the init state
|
|
*/
|
|
static void __init setup_init_fpu_buf(void)
|
|
{
|
|
BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
|
|
XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
|
|
XFEATURES_INIT_FPSTATE_HANDLED);
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_XSAVE))
|
|
return;
|
|
|
|
print_xstate_features();
|
|
|
|
xstate_init_xcomp_bv(&init_fpstate.regs.xsave, init_fpstate.xfeatures);
|
|
|
|
/*
|
|
* Init all the features state with header.xfeatures being 0x0
|
|
*/
|
|
os_xrstor_booting(&init_fpstate.regs.xsave);
|
|
|
|
/*
|
|
* All components are now in init state. Read the state back so
|
|
* that init_fpstate contains all non-zero init state. This only
|
|
* works with XSAVE, but not with XSAVEOPT and XSAVEC/S because
|
|
* those use the init optimization which skips writing data for
|
|
* components in init state.
|
|
*
|
|
* XSAVE could be used, but that would require to reshuffle the
|
|
* data when XSAVEC/S is available because XSAVEC/S uses xstate
|
|
* compaction. But doing so is a pointless exercise because most
|
|
* components have an all zeros init state except for the legacy
|
|
* ones (FP and SSE). Those can be saved with FXSAVE into the
|
|
* legacy area. Adding new features requires to ensure that init
|
|
* state is all zeroes or if not to add the necessary handling
|
|
* here.
|
|
*/
|
|
fxsave(&init_fpstate.regs.fxsave);
|
|
}
|
|
|
|
int xfeature_size(int xfeature_nr)
|
|
{
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
CHECK_XFEATURE(xfeature_nr);
|
|
cpuid_count(XSTATE_CPUID, xfeature_nr, &eax, &ebx, &ecx, &edx);
|
|
return eax;
|
|
}
|
|
|
|
/* Validate an xstate header supplied by userspace (ptrace or sigreturn) */
|
|
static int validate_user_xstate_header(const struct xstate_header *hdr,
|
|
struct fpstate *fpstate)
|
|
{
|
|
/* No unknown or supervisor features may be set */
|
|
if (hdr->xfeatures & ~fpstate->user_xfeatures)
|
|
return -EINVAL;
|
|
|
|
/* Userspace must use the uncompacted format */
|
|
if (hdr->xcomp_bv)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* If 'reserved' is shrunken to add a new field, make sure to validate
|
|
* that new field here!
|
|
*/
|
|
BUILD_BUG_ON(sizeof(hdr->reserved) != 48);
|
|
|
|
/* No reserved bits may be set */
|
|
if (memchr_inv(hdr->reserved, 0, sizeof(hdr->reserved)))
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __init __xstate_dump_leaves(void)
|
|
{
|
|
int i;
|
|
u32 eax, ebx, ecx, edx;
|
|
static int should_dump = 1;
|
|
|
|
if (!should_dump)
|
|
return;
|
|
should_dump = 0;
|
|
/*
|
|
* Dump out a few leaves past the ones that we support
|
|
* just in case there are some goodies up there
|
|
*/
|
|
for (i = 0; i < XFEATURE_MAX + 10; i++) {
|
|
cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx);
|
|
pr_warn("CPUID[%02x, %02x]: eax=%08x ebx=%08x ecx=%08x edx=%08x\n",
|
|
XSTATE_CPUID, i, eax, ebx, ecx, edx);
|
|
}
|
|
}
|
|
|
|
#define XSTATE_WARN_ON(x, fmt, ...) do { \
|
|
if (WARN_ONCE(x, "XSAVE consistency problem: " fmt, ##__VA_ARGS__)) { \
|
|
__xstate_dump_leaves(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define XCHECK_SZ(sz, nr, __struct) ({ \
|
|
if (WARN_ONCE(sz != sizeof(__struct), \
|
|
"[%s]: struct is %zu bytes, cpu state %d bytes\n", \
|
|
xfeature_names[nr], sizeof(__struct), sz)) { \
|
|
__xstate_dump_leaves(); \
|
|
} \
|
|
true; \
|
|
})
|
|
|
|
|
|
/**
|
|
* check_xtile_data_against_struct - Check tile data state size.
|
|
*
|
|
* Calculate the state size by multiplying the single tile size which is
|
|
* recorded in a C struct, and the number of tiles that the CPU informs.
|
|
* Compare the provided size with the calculation.
|
|
*
|
|
* @size: The tile data state size
|
|
*
|
|
* Returns: 0 on success, -EINVAL on mismatch.
|
|
*/
|
|
static int __init check_xtile_data_against_struct(int size)
|
|
{
|
|
u32 max_palid, palid, state_size;
|
|
u32 eax, ebx, ecx, edx;
|
|
u16 max_tile;
|
|
|
|
/*
|
|
* Check the maximum palette id:
|
|
* eax: the highest numbered palette subleaf.
|
|
*/
|
|
cpuid_count(TILE_CPUID, 0, &max_palid, &ebx, &ecx, &edx);
|
|
|
|
/*
|
|
* Cross-check each tile size and find the maximum number of
|
|
* supported tiles.
|
|
*/
|
|
for (palid = 1, max_tile = 0; palid <= max_palid; palid++) {
|
|
u16 tile_size, max;
|
|
|
|
/*
|
|
* Check the tile size info:
|
|
* eax[31:16]: bytes per title
|
|
* ebx[31:16]: the max names (or max number of tiles)
|
|
*/
|
|
cpuid_count(TILE_CPUID, palid, &eax, &ebx, &edx, &edx);
|
|
tile_size = eax >> 16;
|
|
max = ebx >> 16;
|
|
|
|
if (tile_size != sizeof(struct xtile_data)) {
|
|
pr_err("%s: struct is %zu bytes, cpu xtile %d bytes\n",
|
|
__stringify(XFEATURE_XTILE_DATA),
|
|
sizeof(struct xtile_data), tile_size);
|
|
__xstate_dump_leaves();
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (max > max_tile)
|
|
max_tile = max;
|
|
}
|
|
|
|
state_size = sizeof(struct xtile_data) * max_tile;
|
|
if (size != state_size) {
|
|
pr_err("%s: calculated size is %u bytes, cpu state %d bytes\n",
|
|
__stringify(XFEATURE_XTILE_DATA), state_size, size);
|
|
__xstate_dump_leaves();
|
|
return -EINVAL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We have a C struct for each 'xstate'. We need to ensure
|
|
* that our software representation matches what the CPU
|
|
* tells us about the state's size.
|
|
*/
|
|
static bool __init check_xstate_against_struct(int nr)
|
|
{
|
|
/*
|
|
* Ask the CPU for the size of the state.
|
|
*/
|
|
int sz = xfeature_size(nr);
|
|
|
|
/*
|
|
* Match each CPU state with the corresponding software
|
|
* structure.
|
|
*/
|
|
switch (nr) {
|
|
case XFEATURE_YMM: return XCHECK_SZ(sz, nr, struct ymmh_struct);
|
|
case XFEATURE_BNDREGS: return XCHECK_SZ(sz, nr, struct mpx_bndreg_state);
|
|
case XFEATURE_BNDCSR: return XCHECK_SZ(sz, nr, struct mpx_bndcsr_state);
|
|
case XFEATURE_OPMASK: return XCHECK_SZ(sz, nr, struct avx_512_opmask_state);
|
|
case XFEATURE_ZMM_Hi256: return XCHECK_SZ(sz, nr, struct avx_512_zmm_uppers_state);
|
|
case XFEATURE_Hi16_ZMM: return XCHECK_SZ(sz, nr, struct avx_512_hi16_state);
|
|
case XFEATURE_PKRU: return XCHECK_SZ(sz, nr, struct pkru_state);
|
|
case XFEATURE_PASID: return XCHECK_SZ(sz, nr, struct ia32_pasid_state);
|
|
case XFEATURE_XTILE_CFG: return XCHECK_SZ(sz, nr, struct xtile_cfg);
|
|
case XFEATURE_CET_USER: return XCHECK_SZ(sz, nr, struct cet_user_state);
|
|
case XFEATURE_XTILE_DATA: check_xtile_data_against_struct(sz); return true;
|
|
default:
|
|
XSTATE_WARN_ON(1, "No structure for xstate: %d\n", nr);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static unsigned int xstate_calculate_size(u64 xfeatures, bool compacted)
|
|
{
|
|
unsigned int topmost = fls64(xfeatures) - 1;
|
|
unsigned int offset = xstate_offsets[topmost];
|
|
|
|
if (topmost <= XFEATURE_SSE)
|
|
return sizeof(struct xregs_state);
|
|
|
|
if (compacted)
|
|
offset = xfeature_get_offset(xfeatures, topmost);
|
|
return offset + xstate_sizes[topmost];
|
|
}
|
|
|
|
/*
|
|
* This essentially double-checks what the cpu told us about
|
|
* how large the XSAVE buffer needs to be. We are recalculating
|
|
* it to be safe.
|
|
*
|
|
* Independent XSAVE features allocate their own buffers and are not
|
|
* covered by these checks. Only the size of the buffer for task->fpu
|
|
* is checked here.
|
|
*/
|
|
static bool __init paranoid_xstate_size_valid(unsigned int kernel_size)
|
|
{
|
|
bool compacted = cpu_feature_enabled(X86_FEATURE_XCOMPACTED);
|
|
bool xsaves = cpu_feature_enabled(X86_FEATURE_XSAVES);
|
|
unsigned int size = FXSAVE_SIZE + XSAVE_HDR_SIZE;
|
|
int i;
|
|
|
|
for_each_extended_xfeature(i, fpu_kernel_cfg.max_features) {
|
|
if (!check_xstate_against_struct(i))
|
|
return false;
|
|
/*
|
|
* Supervisor state components can be managed only by
|
|
* XSAVES.
|
|
*/
|
|
if (!xsaves && xfeature_is_supervisor(i)) {
|
|
XSTATE_WARN_ON(1, "Got supervisor feature %d, but XSAVES not advertised\n", i);
|
|
return false;
|
|
}
|
|
}
|
|
size = xstate_calculate_size(fpu_kernel_cfg.max_features, compacted);
|
|
XSTATE_WARN_ON(size != kernel_size,
|
|
"size %u != kernel_size %u\n", size, kernel_size);
|
|
return size == kernel_size;
|
|
}
|
|
|
|
/*
|
|
* Get total size of enabled xstates in XCR0 | IA32_XSS.
|
|
*
|
|
* Note the SDM's wording here. "sub-function 0" only enumerates
|
|
* the size of the *user* states. If we use it to size a buffer
|
|
* that we use 'XSAVES' on, we could potentially overflow the
|
|
* buffer because 'XSAVES' saves system states too.
|
|
*
|
|
* This also takes compaction into account. So this works for
|
|
* XSAVEC as well.
|
|
*/
|
|
static unsigned int __init get_compacted_size(void)
|
|
{
|
|
unsigned int eax, ebx, ecx, edx;
|
|
/*
|
|
* - CPUID function 0DH, sub-function 1:
|
|
* EBX enumerates the size (in bytes) required by
|
|
* the XSAVES instruction for an XSAVE area
|
|
* containing all the state components
|
|
* corresponding to bits currently set in
|
|
* XCR0 | IA32_XSS.
|
|
*
|
|
* When XSAVES is not available but XSAVEC is (virt), then there
|
|
* are no supervisor states, but XSAVEC still uses compacted
|
|
* format.
|
|
*/
|
|
cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx);
|
|
return ebx;
|
|
}
|
|
|
|
/*
|
|
* Get the total size of the enabled xstates without the independent supervisor
|
|
* features.
|
|
*/
|
|
static unsigned int __init get_xsave_compacted_size(void)
|
|
{
|
|
u64 mask = xfeatures_mask_independent();
|
|
unsigned int size;
|
|
|
|
if (!mask)
|
|
return get_compacted_size();
|
|
|
|
/* Disable independent features. */
|
|
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor());
|
|
|
|
/*
|
|
* Ask the hardware what size is required of the buffer.
|
|
* This is the size required for the task->fpu buffer.
|
|
*/
|
|
size = get_compacted_size();
|
|
|
|
/* Re-enable independent features so XSAVES will work on them again. */
|
|
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() | mask);
|
|
|
|
return size;
|
|
}
|
|
|
|
static unsigned int __init get_xsave_size_user(void)
|
|
{
|
|
unsigned int eax, ebx, ecx, edx;
|
|
/*
|
|
* - CPUID function 0DH, sub-function 0:
|
|
* EBX enumerates the size (in bytes) required by
|
|
* the XSAVE instruction for an XSAVE area
|
|
* containing all the *user* state components
|
|
* corresponding to bits currently set in XCR0.
|
|
*/
|
|
cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
|
|
return ebx;
|
|
}
|
|
|
|
static int __init init_xstate_size(void)
|
|
{
|
|
/* Recompute the context size for enabled features: */
|
|
unsigned int user_size, kernel_size, kernel_default_size;
|
|
bool compacted = cpu_feature_enabled(X86_FEATURE_XCOMPACTED);
|
|
|
|
/* Uncompacted user space size */
|
|
user_size = get_xsave_size_user();
|
|
|
|
/*
|
|
* XSAVES kernel size includes supervisor states and uses compacted
|
|
* format. XSAVEC uses compacted format, but does not save
|
|
* supervisor states.
|
|
*
|
|
* XSAVE[OPT] do not support supervisor states so kernel and user
|
|
* size is identical.
|
|
*/
|
|
if (compacted)
|
|
kernel_size = get_xsave_compacted_size();
|
|
else
|
|
kernel_size = user_size;
|
|
|
|
kernel_default_size =
|
|
xstate_calculate_size(fpu_kernel_cfg.default_features, compacted);
|
|
|
|
if (!paranoid_xstate_size_valid(kernel_size))
|
|
return -EINVAL;
|
|
|
|
fpu_kernel_cfg.max_size = kernel_size;
|
|
fpu_user_cfg.max_size = user_size;
|
|
|
|
fpu_kernel_cfg.default_size = kernel_default_size;
|
|
fpu_user_cfg.default_size =
|
|
xstate_calculate_size(fpu_user_cfg.default_features, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We enabled the XSAVE hardware, but something went wrong and
|
|
* we can not use it. Disable it.
|
|
*/
|
|
static void __init fpu__init_disable_system_xstate(unsigned int legacy_size)
|
|
{
|
|
fpu_kernel_cfg.max_features = 0;
|
|
cr4_clear_bits(X86_CR4_OSXSAVE);
|
|
setup_clear_cpu_cap(X86_FEATURE_XSAVE);
|
|
|
|
/* Restore the legacy size.*/
|
|
fpu_kernel_cfg.max_size = legacy_size;
|
|
fpu_kernel_cfg.default_size = legacy_size;
|
|
fpu_user_cfg.max_size = legacy_size;
|
|
fpu_user_cfg.default_size = legacy_size;
|
|
|
|
/*
|
|
* Prevent enabling the static branch which enables writes to the
|
|
* XFD MSR.
|
|
*/
|
|
init_fpstate.xfd = 0;
|
|
|
|
fpstate_reset(¤t->thread.fpu);
|
|
}
|
|
|
|
/*
|
|
* Enable and initialize the xsave feature.
|
|
* Called once per system bootup.
|
|
*/
|
|
void __init fpu__init_system_xstate(unsigned int legacy_size)
|
|
{
|
|
unsigned int eax, ebx, ecx, edx;
|
|
u64 xfeatures;
|
|
int err;
|
|
int i;
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_FPU)) {
|
|
pr_info("x86/fpu: No FPU detected\n");
|
|
return;
|
|
}
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
|
|
pr_info("x86/fpu: x87 FPU will use %s\n",
|
|
boot_cpu_has(X86_FEATURE_FXSR) ? "FXSAVE" : "FSAVE");
|
|
return;
|
|
}
|
|
|
|
if (boot_cpu_data.cpuid_level < XSTATE_CPUID) {
|
|
WARN_ON_FPU(1);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Find user xstates supported by the processor.
|
|
*/
|
|
cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx);
|
|
fpu_kernel_cfg.max_features = eax + ((u64)edx << 32);
|
|
|
|
/*
|
|
* Find supervisor xstates supported by the processor.
|
|
*/
|
|
cpuid_count(XSTATE_CPUID, 1, &eax, &ebx, &ecx, &edx);
|
|
fpu_kernel_cfg.max_features |= ecx + ((u64)edx << 32);
|
|
|
|
if ((fpu_kernel_cfg.max_features & XFEATURE_MASK_FPSSE) != XFEATURE_MASK_FPSSE) {
|
|
/*
|
|
* This indicates that something really unexpected happened
|
|
* with the enumeration. Disable XSAVE and try to continue
|
|
* booting without it. This is too early to BUG().
|
|
*/
|
|
pr_err("x86/fpu: FP/SSE not present amongst the CPU's xstate features: 0x%llx.\n",
|
|
fpu_kernel_cfg.max_features);
|
|
goto out_disable;
|
|
}
|
|
|
|
fpu_kernel_cfg.independent_features = fpu_kernel_cfg.max_features &
|
|
XFEATURE_MASK_INDEPENDENT;
|
|
|
|
/*
|
|
* Clear XSAVE features that are disabled in the normal CPUID.
|
|
*/
|
|
for (i = 0; i < ARRAY_SIZE(xsave_cpuid_features); i++) {
|
|
unsigned short cid = xsave_cpuid_features[i];
|
|
|
|
/* Careful: X86_FEATURE_FPU is 0! */
|
|
if ((i != XFEATURE_FP && !cid) || !boot_cpu_has(cid))
|
|
fpu_kernel_cfg.max_features &= ~BIT_ULL(i);
|
|
}
|
|
|
|
if (!cpu_feature_enabled(X86_FEATURE_XFD))
|
|
fpu_kernel_cfg.max_features &= ~XFEATURE_MASK_USER_DYNAMIC;
|
|
|
|
if (!cpu_feature_enabled(X86_FEATURE_XSAVES))
|
|
fpu_kernel_cfg.max_features &= XFEATURE_MASK_USER_SUPPORTED;
|
|
else
|
|
fpu_kernel_cfg.max_features &= XFEATURE_MASK_USER_SUPPORTED |
|
|
XFEATURE_MASK_SUPERVISOR_SUPPORTED;
|
|
|
|
fpu_user_cfg.max_features = fpu_kernel_cfg.max_features;
|
|
fpu_user_cfg.max_features &= XFEATURE_MASK_USER_SUPPORTED;
|
|
|
|
/* Clean out dynamic features from default */
|
|
fpu_kernel_cfg.default_features = fpu_kernel_cfg.max_features;
|
|
fpu_kernel_cfg.default_features &= ~XFEATURE_MASK_USER_DYNAMIC;
|
|
|
|
fpu_user_cfg.default_features = fpu_user_cfg.max_features;
|
|
fpu_user_cfg.default_features &= ~XFEATURE_MASK_USER_DYNAMIC;
|
|
|
|
/* Store it for paranoia check at the end */
|
|
xfeatures = fpu_kernel_cfg.max_features;
|
|
|
|
/*
|
|
* Initialize the default XFD state in initfp_state and enable the
|
|
* dynamic sizing mechanism if dynamic states are available. The
|
|
* static key cannot be enabled here because this runs before
|
|
* jump_label_init(). This is delayed to an initcall.
|
|
*/
|
|
init_fpstate.xfd = fpu_user_cfg.max_features & XFEATURE_MASK_USER_DYNAMIC;
|
|
|
|
/* Set up compaction feature bit */
|
|
if (cpu_feature_enabled(X86_FEATURE_XSAVEC) ||
|
|
cpu_feature_enabled(X86_FEATURE_XSAVES))
|
|
setup_force_cpu_cap(X86_FEATURE_XCOMPACTED);
|
|
|
|
/* Enable xstate instructions to be able to continue with initialization: */
|
|
fpu__init_cpu_xstate();
|
|
|
|
/* Cache size, offset and flags for initialization */
|
|
setup_xstate_cache();
|
|
|
|
err = init_xstate_size();
|
|
if (err)
|
|
goto out_disable;
|
|
|
|
/* Reset the state for the current task */
|
|
fpstate_reset(¤t->thread.fpu);
|
|
|
|
/*
|
|
* Update info used for ptrace frames; use standard-format size and no
|
|
* supervisor xstates:
|
|
*/
|
|
update_regset_xstate_info(fpu_user_cfg.max_size,
|
|
fpu_user_cfg.max_features);
|
|
|
|
/*
|
|
* init_fpstate excludes dynamic states as they are large but init
|
|
* state is zero.
|
|
*/
|
|
init_fpstate.size = fpu_kernel_cfg.default_size;
|
|
init_fpstate.xfeatures = fpu_kernel_cfg.default_features;
|
|
|
|
if (init_fpstate.size > sizeof(init_fpstate.regs)) {
|
|
pr_warn("x86/fpu: init_fpstate buffer too small (%zu < %d), disabling XSAVE\n",
|
|
sizeof(init_fpstate.regs), init_fpstate.size);
|
|
goto out_disable;
|
|
}
|
|
|
|
setup_init_fpu_buf();
|
|
|
|
/*
|
|
* Paranoia check whether something in the setup modified the
|
|
* xfeatures mask.
|
|
*/
|
|
if (xfeatures != fpu_kernel_cfg.max_features) {
|
|
pr_err("x86/fpu: xfeatures modified from 0x%016llx to 0x%016llx during init, disabling XSAVE\n",
|
|
xfeatures, fpu_kernel_cfg.max_features);
|
|
goto out_disable;
|
|
}
|
|
|
|
/*
|
|
* CPU capabilities initialization runs before FPU init. So
|
|
* X86_FEATURE_OSXSAVE is not set. Now that XSAVE is completely
|
|
* functional, set the feature bit so depending code works.
|
|
*/
|
|
setup_force_cpu_cap(X86_FEATURE_OSXSAVE);
|
|
|
|
print_xstate_offset_size();
|
|
pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n",
|
|
fpu_kernel_cfg.max_features,
|
|
fpu_kernel_cfg.max_size,
|
|
boot_cpu_has(X86_FEATURE_XCOMPACTED) ? "compacted" : "standard");
|
|
return;
|
|
|
|
out_disable:
|
|
/* something went wrong, try to boot without any XSAVE support */
|
|
fpu__init_disable_system_xstate(legacy_size);
|
|
}
|
|
|
|
/*
|
|
* Restore minimal FPU state after suspend:
|
|
*/
|
|
void fpu__resume_cpu(void)
|
|
{
|
|
/*
|
|
* Restore XCR0 on xsave capable CPUs:
|
|
*/
|
|
if (cpu_feature_enabled(X86_FEATURE_XSAVE))
|
|
xsetbv(XCR_XFEATURE_ENABLED_MASK, fpu_user_cfg.max_features);
|
|
|
|
/*
|
|
* Restore IA32_XSS. The same CPUID bit enumerates support
|
|
* of XSAVES and MSR_IA32_XSS.
|
|
*/
|
|
if (cpu_feature_enabled(X86_FEATURE_XSAVES)) {
|
|
wrmsrl(MSR_IA32_XSS, xfeatures_mask_supervisor() |
|
|
xfeatures_mask_independent());
|
|
}
|
|
|
|
if (fpu_state_size_dynamic())
|
|
wrmsrl(MSR_IA32_XFD, current->thread.fpu.fpstate->xfd);
|
|
}
|
|
|
|
/*
|
|
* Given an xstate feature nr, calculate where in the xsave
|
|
* buffer the state is. Callers should ensure that the buffer
|
|
* is valid.
|
|
*/
|
|
static void *__raw_xsave_addr(struct xregs_state *xsave, int xfeature_nr)
|
|
{
|
|
u64 xcomp_bv = xsave->header.xcomp_bv;
|
|
|
|
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
|
|
return NULL;
|
|
|
|
if (cpu_feature_enabled(X86_FEATURE_XCOMPACTED)) {
|
|
if (WARN_ON_ONCE(!(xcomp_bv & BIT_ULL(xfeature_nr))))
|
|
return NULL;
|
|
}
|
|
|
|
return (void *)xsave + xfeature_get_offset(xcomp_bv, xfeature_nr);
|
|
}
|
|
|
|
/*
|
|
* Given the xsave area and a state inside, this function returns the
|
|
* address of the state.
|
|
*
|
|
* This is the API that is called to get xstate address in either
|
|
* standard format or compacted format of xsave area.
|
|
*
|
|
* Note that if there is no data for the field in the xsave buffer
|
|
* this will return NULL.
|
|
*
|
|
* Inputs:
|
|
* xstate: the thread's storage area for all FPU data
|
|
* xfeature_nr: state which is defined in xsave.h (e.g. XFEATURE_FP,
|
|
* XFEATURE_SSE, etc...)
|
|
* Output:
|
|
* address of the state in the xsave area, or NULL if the
|
|
* field is not present in the xsave buffer.
|
|
*/
|
|
void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr)
|
|
{
|
|
/*
|
|
* Do we even *have* xsave state?
|
|
*/
|
|
if (!boot_cpu_has(X86_FEATURE_XSAVE))
|
|
return NULL;
|
|
|
|
/*
|
|
* We should not ever be requesting features that we
|
|
* have not enabled.
|
|
*/
|
|
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
|
|
return NULL;
|
|
|
|
/*
|
|
* This assumes the last 'xsave*' instruction to
|
|
* have requested that 'xfeature_nr' be saved.
|
|
* If it did not, we might be seeing and old value
|
|
* of the field in the buffer.
|
|
*
|
|
* This can happen because the last 'xsave' did not
|
|
* request that this feature be saved (unlikely)
|
|
* or because the "init optimization" caused it
|
|
* to not be saved.
|
|
*/
|
|
if (!(xsave->header.xfeatures & BIT_ULL(xfeature_nr)))
|
|
return NULL;
|
|
|
|
return __raw_xsave_addr(xsave, xfeature_nr);
|
|
}
|
|
EXPORT_SYMBOL_GPL(get_xsave_addr);
|
|
|
|
/*
|
|
* Given an xstate feature nr, calculate where in the xsave buffer the state is.
|
|
* The xsave buffer should be in standard format, not compacted (e.g. user mode
|
|
* signal frames).
|
|
*/
|
|
void __user *get_xsave_addr_user(struct xregs_state __user *xsave, int xfeature_nr)
|
|
{
|
|
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
|
|
return NULL;
|
|
|
|
return (void __user *)xsave + xstate_offsets[xfeature_nr];
|
|
}
|
|
|
|
#ifdef CONFIG_ARCH_HAS_PKEYS
|
|
|
|
/*
|
|
* This will go out and modify PKRU register to set the access
|
|
* rights for @pkey to @init_val.
|
|
*/
|
|
int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
|
|
unsigned long init_val)
|
|
{
|
|
u32 old_pkru, new_pkru_bits = 0;
|
|
int pkey_shift;
|
|
|
|
/*
|
|
* This check implies XSAVE support. OSPKE only gets
|
|
* set if we enable XSAVE and we enable PKU in XCR0.
|
|
*/
|
|
if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* This code should only be called with valid 'pkey'
|
|
* values originating from in-kernel users. Complain
|
|
* if a bad value is observed.
|
|
*/
|
|
if (WARN_ON_ONCE(pkey >= arch_max_pkey()))
|
|
return -EINVAL;
|
|
|
|
/* Set the bits we need in PKRU: */
|
|
if (init_val & PKEY_DISABLE_ACCESS)
|
|
new_pkru_bits |= PKRU_AD_BIT;
|
|
if (init_val & PKEY_DISABLE_WRITE)
|
|
new_pkru_bits |= PKRU_WD_BIT;
|
|
|
|
/* Shift the bits in to the correct place in PKRU for pkey: */
|
|
pkey_shift = pkey * PKRU_BITS_PER_PKEY;
|
|
new_pkru_bits <<= pkey_shift;
|
|
|
|
/* Get old PKRU and mask off any old bits in place: */
|
|
old_pkru = read_pkru();
|
|
old_pkru &= ~((PKRU_AD_BIT|PKRU_WD_BIT) << pkey_shift);
|
|
|
|
/* Write old part along with new part: */
|
|
write_pkru(old_pkru | new_pkru_bits);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* ! CONFIG_ARCH_HAS_PKEYS */
|
|
|
|
static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
|
|
void *init_xstate, unsigned int size)
|
|
{
|
|
membuf_write(to, from_xstate ? xstate : init_xstate, size);
|
|
}
|
|
|
|
/**
|
|
* __copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer
|
|
* @to: membuf descriptor
|
|
* @fpstate: The fpstate buffer from which to copy
|
|
* @xfeatures: The mask of xfeatures to save (XSAVE mode only)
|
|
* @pkru_val: The PKRU value to store in the PKRU component
|
|
* @copy_mode: The requested copy mode
|
|
*
|
|
* Converts from kernel XSAVE or XSAVES compacted format to UABI conforming
|
|
* format, i.e. from the kernel internal hardware dependent storage format
|
|
* to the requested @mode. UABI XSTATE is always uncompacted!
|
|
*
|
|
* It supports partial copy but @to.pos always starts from zero.
|
|
*/
|
|
void __copy_xstate_to_uabi_buf(struct membuf to, struct fpstate *fpstate,
|
|
u64 xfeatures, u32 pkru_val,
|
|
enum xstate_copy_mode copy_mode)
|
|
{
|
|
const unsigned int off_mxcsr = offsetof(struct fxregs_state, mxcsr);
|
|
struct xregs_state *xinit = &init_fpstate.regs.xsave;
|
|
struct xregs_state *xsave = &fpstate->regs.xsave;
|
|
struct xstate_header header;
|
|
unsigned int zerofrom;
|
|
u64 mask;
|
|
int i;
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
header.xfeatures = xsave->header.xfeatures;
|
|
|
|
/* Mask out the feature bits depending on copy mode */
|
|
switch (copy_mode) {
|
|
case XSTATE_COPY_FP:
|
|
header.xfeatures &= XFEATURE_MASK_FP;
|
|
break;
|
|
|
|
case XSTATE_COPY_FX:
|
|
header.xfeatures &= XFEATURE_MASK_FP | XFEATURE_MASK_SSE;
|
|
break;
|
|
|
|
case XSTATE_COPY_XSAVE:
|
|
header.xfeatures &= fpstate->user_xfeatures & xfeatures;
|
|
break;
|
|
}
|
|
|
|
/* Copy FP state up to MXCSR */
|
|
copy_feature(header.xfeatures & XFEATURE_MASK_FP, &to, &xsave->i387,
|
|
&xinit->i387, off_mxcsr);
|
|
|
|
/* Copy MXCSR when SSE or YMM are set in the feature mask */
|
|
copy_feature(header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM),
|
|
&to, &xsave->i387.mxcsr, &xinit->i387.mxcsr,
|
|
MXCSR_AND_FLAGS_SIZE);
|
|
|
|
/* Copy the remaining FP state */
|
|
copy_feature(header.xfeatures & XFEATURE_MASK_FP,
|
|
&to, &xsave->i387.st_space, &xinit->i387.st_space,
|
|
sizeof(xsave->i387.st_space));
|
|
|
|
/* Copy the SSE state - shared with YMM, but independently managed */
|
|
copy_feature(header.xfeatures & XFEATURE_MASK_SSE,
|
|
&to, &xsave->i387.xmm_space, &xinit->i387.xmm_space,
|
|
sizeof(xsave->i387.xmm_space));
|
|
|
|
if (copy_mode != XSTATE_COPY_XSAVE)
|
|
goto out;
|
|
|
|
/* Zero the padding area */
|
|
membuf_zero(&to, sizeof(xsave->i387.padding));
|
|
|
|
/* Copy xsave->i387.sw_reserved */
|
|
membuf_write(&to, xstate_fx_sw_bytes, sizeof(xsave->i387.sw_reserved));
|
|
|
|
/* Copy the user space relevant state of @xsave->header */
|
|
membuf_write(&to, &header, sizeof(header));
|
|
|
|
zerofrom = offsetof(struct xregs_state, extended_state_area);
|
|
|
|
/*
|
|
* This 'mask' indicates which states to copy from fpstate.
|
|
* Those extended states that are not present in fpstate are
|
|
* either disabled or initialized:
|
|
*
|
|
* In non-compacted format, disabled features still occupy
|
|
* state space but there is no state to copy from in the
|
|
* compacted init_fpstate. The gap tracking will zero these
|
|
* states.
|
|
*
|
|
* The extended features have an all zeroes init state. Thus,
|
|
* remove them from 'mask' to zero those features in the user
|
|
* buffer instead of retrieving them from init_fpstate.
|
|
*/
|
|
mask = header.xfeatures;
|
|
|
|
for_each_extended_xfeature(i, mask) {
|
|
/*
|
|
* If there was a feature or alignment gap, zero the space
|
|
* in the destination buffer.
|
|
*/
|
|
if (zerofrom < xstate_offsets[i])
|
|
membuf_zero(&to, xstate_offsets[i] - zerofrom);
|
|
|
|
if (i == XFEATURE_PKRU) {
|
|
struct pkru_state pkru = {0};
|
|
/*
|
|
* PKRU is not necessarily up to date in the
|
|
* XSAVE buffer. Use the provided value.
|
|
*/
|
|
pkru.pkru = pkru_val;
|
|
membuf_write(&to, &pkru, sizeof(pkru));
|
|
} else {
|
|
membuf_write(&to,
|
|
__raw_xsave_addr(xsave, i),
|
|
xstate_sizes[i]);
|
|
}
|
|
/*
|
|
* Keep track of the last copied state in the non-compacted
|
|
* target buffer for gap zeroing.
|
|
*/
|
|
zerofrom = xstate_offsets[i] + xstate_sizes[i];
|
|
}
|
|
|
|
out:
|
|
if (to.left)
|
|
membuf_zero(&to, to.left);
|
|
}
|
|
|
|
/**
|
|
* copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer
|
|
* @to: membuf descriptor
|
|
* @tsk: The task from which to copy the saved xstate
|
|
* @copy_mode: The requested copy mode
|
|
*
|
|
* Converts from kernel XSAVE or XSAVES compacted format to UABI conforming
|
|
* format, i.e. from the kernel internal hardware dependent storage format
|
|
* to the requested @mode. UABI XSTATE is always uncompacted!
|
|
*
|
|
* It supports partial copy but @to.pos always starts from zero.
|
|
*/
|
|
void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
|
|
enum xstate_copy_mode copy_mode)
|
|
{
|
|
__copy_xstate_to_uabi_buf(to, tsk->thread.fpu.fpstate,
|
|
tsk->thread.fpu.fpstate->user_xfeatures,
|
|
tsk->thread.pkru, copy_mode);
|
|
}
|
|
|
|
static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
|
|
const void *kbuf, const void __user *ubuf)
|
|
{
|
|
if (kbuf) {
|
|
memcpy(dst, kbuf + offset, size);
|
|
} else {
|
|
if (copy_from_user(dst, ubuf + offset, size))
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* copy_uabi_to_xstate - Copy a UABI format buffer to the kernel xstate
|
|
* @fpstate: The fpstate buffer to copy to
|
|
* @kbuf: The UABI format buffer, if it comes from the kernel
|
|
* @ubuf: The UABI format buffer, if it comes from userspace
|
|
* @pkru: The location to write the PKRU value to
|
|
*
|
|
* Converts from the UABI format into the kernel internal hardware
|
|
* dependent format.
|
|
*
|
|
* This function ultimately has three different callers with distinct PKRU
|
|
* behavior.
|
|
* 1. When called from sigreturn the PKRU register will be restored from
|
|
* @fpstate via an XRSTOR. Correctly copying the UABI format buffer to
|
|
* @fpstate is sufficient to cover this case, but the caller will also
|
|
* pass a pointer to the thread_struct's pkru field in @pkru and updating
|
|
* it is harmless.
|
|
* 2. When called from ptrace the PKRU register will be restored from the
|
|
* thread_struct's pkru field. A pointer to that is passed in @pkru.
|
|
* The kernel will restore it manually, so the XRSTOR behavior that resets
|
|
* the PKRU register to the hardware init value (0) if the corresponding
|
|
* xfeatures bit is not set is emulated here.
|
|
* 3. When called from KVM the PKRU register will be restored from the vcpu's
|
|
* pkru field. A pointer to that is passed in @pkru. KVM hasn't used
|
|
* XRSTOR and hasn't had the PKRU resetting behavior described above. To
|
|
* preserve that KVM behavior, it passes NULL for @pkru if the xfeatures
|
|
* bit is not set.
|
|
*/
|
|
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
|
|
const void __user *ubuf, u32 *pkru)
|
|
{
|
|
struct xregs_state *xsave = &fpstate->regs.xsave;
|
|
unsigned int offset, size;
|
|
struct xstate_header hdr;
|
|
u64 mask;
|
|
int i;
|
|
|
|
offset = offsetof(struct xregs_state, header);
|
|
if (copy_from_buffer(&hdr, offset, sizeof(hdr), kbuf, ubuf))
|
|
return -EFAULT;
|
|
|
|
if (validate_user_xstate_header(&hdr, fpstate))
|
|
return -EINVAL;
|
|
|
|
/* Validate MXCSR when any of the related features is in use */
|
|
mask = XFEATURE_MASK_FP | XFEATURE_MASK_SSE | XFEATURE_MASK_YMM;
|
|
if (hdr.xfeatures & mask) {
|
|
u32 mxcsr[2];
|
|
|
|
offset = offsetof(struct fxregs_state, mxcsr);
|
|
if (copy_from_buffer(mxcsr, offset, sizeof(mxcsr), kbuf, ubuf))
|
|
return -EFAULT;
|
|
|
|
/* Reserved bits in MXCSR must be zero. */
|
|
if (mxcsr[0] & ~mxcsr_feature_mask)
|
|
return -EINVAL;
|
|
|
|
/* SSE and YMM require MXCSR even when FP is not in use. */
|
|
if (!(hdr.xfeatures & XFEATURE_MASK_FP)) {
|
|
xsave->i387.mxcsr = mxcsr[0];
|
|
xsave->i387.mxcsr_mask = mxcsr[1];
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < XFEATURE_MAX; i++) {
|
|
mask = BIT_ULL(i);
|
|
|
|
if (hdr.xfeatures & mask) {
|
|
void *dst = __raw_xsave_addr(xsave, i);
|
|
|
|
offset = xstate_offsets[i];
|
|
size = xstate_sizes[i];
|
|
|
|
if (copy_from_buffer(dst, offset, size, kbuf, ubuf))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
|
|
struct pkru_state *xpkru;
|
|
|
|
xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
|
|
*pkru = xpkru->pkru;
|
|
} else {
|
|
/*
|
|
* KVM may pass NULL here to indicate that it does not need
|
|
* PKRU updated.
|
|
*/
|
|
if (pkru)
|
|
*pkru = 0;
|
|
}
|
|
|
|
/*
|
|
* The state that came in from userspace was user-state only.
|
|
* Mask all the user states out of 'xfeatures':
|
|
*/
|
|
xsave->header.xfeatures &= XFEATURE_MASK_SUPERVISOR_ALL;
|
|
|
|
/*
|
|
* Add back in the features that came in from userspace:
|
|
*/
|
|
xsave->header.xfeatures |= hdr.xfeatures;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Convert from a ptrace standard-format kernel buffer to kernel XSAVE[S]
|
|
* format and copy to the target thread. Used by ptrace and KVM.
|
|
*/
|
|
int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru)
|
|
{
|
|
return copy_uabi_to_xstate(fpstate, kbuf, NULL, pkru);
|
|
}
|
|
|
|
/*
|
|
* Convert from a sigreturn standard-format user-space buffer to kernel
|
|
* XSAVE[S] format and copy to the target thread. This is called from the
|
|
* sigreturn() and rt_sigreturn() system calls.
|
|
*/
|
|
int copy_sigframe_from_user_to_xstate(struct task_struct *tsk,
|
|
const void __user *ubuf)
|
|
{
|
|
return copy_uabi_to_xstate(tsk->thread.fpu.fpstate, NULL, ubuf, &tsk->thread.pkru);
|
|
}
|
|
|
|
static bool validate_independent_components(u64 mask)
|
|
{
|
|
u64 xchk;
|
|
|
|
if (WARN_ON_FPU(!cpu_feature_enabled(X86_FEATURE_XSAVES)))
|
|
return false;
|
|
|
|
xchk = ~xfeatures_mask_independent();
|
|
|
|
if (WARN_ON_ONCE(!mask || mask & xchk))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* xsaves - Save selected components to a kernel xstate buffer
|
|
* @xstate: Pointer to the buffer
|
|
* @mask: Feature mask to select the components to save
|
|
*
|
|
* The @xstate buffer must be 64 byte aligned and correctly initialized as
|
|
* XSAVES does not write the full xstate header. Before first use the
|
|
* buffer should be zeroed otherwise a consecutive XRSTORS from that buffer
|
|
* can #GP.
|
|
*
|
|
* The feature mask must be a subset of the independent features.
|
|
*/
|
|
void xsaves(struct xregs_state *xstate, u64 mask)
|
|
{
|
|
int err;
|
|
|
|
if (!validate_independent_components(mask))
|
|
return;
|
|
|
|
XSTATE_OP(XSAVES, xstate, (u32)mask, (u32)(mask >> 32), err);
|
|
WARN_ON_ONCE(err);
|
|
}
|
|
|
|
/**
|
|
* xrstors - Restore selected components from a kernel xstate buffer
|
|
* @xstate: Pointer to the buffer
|
|
* @mask: Feature mask to select the components to restore
|
|
*
|
|
* The @xstate buffer must be 64 byte aligned and correctly initialized
|
|
* otherwise XRSTORS from that buffer can #GP.
|
|
*
|
|
* Proper usage is to restore the state which was saved with
|
|
* xsaves() into @xstate.
|
|
*
|
|
* The feature mask must be a subset of the independent features.
|
|
*/
|
|
void xrstors(struct xregs_state *xstate, u64 mask)
|
|
{
|
|
int err;
|
|
|
|
if (!validate_independent_components(mask))
|
|
return;
|
|
|
|
XSTATE_OP(XRSTORS, xstate, (u32)mask, (u32)(mask >> 32), err);
|
|
WARN_ON_ONCE(err);
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_KVM)
|
|
void fpstate_clear_xstate_component(struct fpstate *fps, unsigned int xfeature)
|
|
{
|
|
void *addr = get_xsave_addr(&fps->regs.xsave, xfeature);
|
|
|
|
if (addr)
|
|
memset(addr, 0, xstate_sizes[xfeature]);
|
|
}
|
|
EXPORT_SYMBOL_GPL(fpstate_clear_xstate_component);
|
|
#endif
|
|
|
|
#ifdef CONFIG_X86_64
|
|
|
|
#ifdef CONFIG_X86_DEBUG_FPU
|
|
/*
|
|
* Ensure that a subsequent XSAVE* or XRSTOR* instruction with RFBM=@mask
|
|
* can safely operate on the @fpstate buffer.
|
|
*/
|
|
static bool xstate_op_valid(struct fpstate *fpstate, u64 mask, bool rstor)
|
|
{
|
|
u64 xfd = __this_cpu_read(xfd_state);
|
|
|
|
if (fpstate->xfd == xfd)
|
|
return true;
|
|
|
|
/*
|
|
* The XFD MSR does not match fpstate->xfd. That's invalid when
|
|
* the passed in fpstate is current's fpstate.
|
|
*/
|
|
if (fpstate->xfd == current->thread.fpu.fpstate->xfd)
|
|
return false;
|
|
|
|
/*
|
|
* XRSTOR(S) from init_fpstate are always correct as it will just
|
|
* bring all components into init state and not read from the
|
|
* buffer. XSAVE(S) raises #PF after init.
|
|
*/
|
|
if (fpstate == &init_fpstate)
|
|
return rstor;
|
|
|
|
/*
|
|
* XSAVE(S): clone(), fpu_swap_kvm_fpstate()
|
|
* XRSTORS(S): fpu_swap_kvm_fpstate()
|
|
*/
|
|
|
|
/*
|
|
* No XSAVE/XRSTOR instructions (except XSAVE itself) touch
|
|
* the buffer area for XFD-disabled state components.
|
|
*/
|
|
mask &= ~xfd;
|
|
|
|
/*
|
|
* Remove features which are valid in fpstate. They
|
|
* have space allocated in fpstate.
|
|
*/
|
|
mask &= ~fpstate->xfeatures;
|
|
|
|
/*
|
|
* Any remaining state components in 'mask' might be written
|
|
* by XSAVE/XRSTOR. Fail validation it found.
|
|
*/
|
|
return !mask;
|
|
}
|
|
|
|
void xfd_validate_state(struct fpstate *fpstate, u64 mask, bool rstor)
|
|
{
|
|
WARN_ON_ONCE(!xstate_op_valid(fpstate, mask, rstor));
|
|
}
|
|
#endif /* CONFIG_X86_DEBUG_FPU */
|
|
|
|
static int __init xfd_update_static_branch(void)
|
|
{
|
|
/*
|
|
* If init_fpstate.xfd has bits set then dynamic features are
|
|
* available and the dynamic sizing must be enabled.
|
|
*/
|
|
if (init_fpstate.xfd)
|
|
static_branch_enable(&__fpu_state_size_dynamic);
|
|
return 0;
|
|
}
|
|
arch_initcall(xfd_update_static_branch)
|
|
|
|
void fpstate_free(struct fpu *fpu)
|
|
{
|
|
if (fpu->fpstate && fpu->fpstate != &fpu->__fpstate)
|
|
vfree(fpu->fpstate);
|
|
}
|
|
|
|
/**
|
|
* fpstate_realloc - Reallocate struct fpstate for the requested new features
|
|
*
|
|
* @xfeatures: A bitmap of xstate features which extend the enabled features
|
|
* of that task
|
|
* @ksize: The required size for the kernel buffer
|
|
* @usize: The required size for user space buffers
|
|
* @guest_fpu: Pointer to a guest FPU container. NULL for host allocations
|
|
*
|
|
* Note vs. vmalloc(): If the task with a vzalloc()-allocated buffer
|
|
* terminates quickly, vfree()-induced IPIs may be a concern, but tasks
|
|
* with large states are likely to live longer.
|
|
*
|
|
* Returns: 0 on success, -ENOMEM on allocation error.
|
|
*/
|
|
static int fpstate_realloc(u64 xfeatures, unsigned int ksize,
|
|
unsigned int usize, struct fpu_guest *guest_fpu)
|
|
{
|
|
struct fpu *fpu = ¤t->thread.fpu;
|
|
struct fpstate *curfps, *newfps = NULL;
|
|
unsigned int fpsize;
|
|
bool in_use;
|
|
|
|
fpsize = ksize + ALIGN(offsetof(struct fpstate, regs), 64);
|
|
|
|
newfps = vzalloc(fpsize);
|
|
if (!newfps)
|
|
return -ENOMEM;
|
|
newfps->size = ksize;
|
|
newfps->user_size = usize;
|
|
newfps->is_valloc = true;
|
|
|
|
/*
|
|
* When a guest FPU is supplied, use @guest_fpu->fpstate
|
|
* as reference independent whether it is in use or not.
|
|
*/
|
|
curfps = guest_fpu ? guest_fpu->fpstate : fpu->fpstate;
|
|
|
|
/* Determine whether @curfps is the active fpstate */
|
|
in_use = fpu->fpstate == curfps;
|
|
|
|
if (guest_fpu) {
|
|
newfps->is_guest = true;
|
|
newfps->is_confidential = curfps->is_confidential;
|
|
newfps->in_use = curfps->in_use;
|
|
guest_fpu->xfeatures |= xfeatures;
|
|
guest_fpu->uabi_size = usize;
|
|
}
|
|
|
|
fpregs_lock();
|
|
/*
|
|
* If @curfps is in use, ensure that the current state is in the
|
|
* registers before swapping fpstate as that might invalidate it
|
|
* due to layout changes.
|
|
*/
|
|
if (in_use && test_thread_flag(TIF_NEED_FPU_LOAD))
|
|
fpregs_restore_userregs();
|
|
|
|
newfps->xfeatures = curfps->xfeatures | xfeatures;
|
|
newfps->user_xfeatures = curfps->user_xfeatures | xfeatures;
|
|
newfps->xfd = curfps->xfd & ~xfeatures;
|
|
|
|
/* Do the final updates within the locked region */
|
|
xstate_init_xcomp_bv(&newfps->regs.xsave, newfps->xfeatures);
|
|
|
|
if (guest_fpu) {
|
|
guest_fpu->fpstate = newfps;
|
|
/* If curfps is active, update the FPU fpstate pointer */
|
|
if (in_use)
|
|
fpu->fpstate = newfps;
|
|
} else {
|
|
fpu->fpstate = newfps;
|
|
}
|
|
|
|
if (in_use)
|
|
xfd_update_state(fpu->fpstate);
|
|
fpregs_unlock();
|
|
|
|
/* Only free valloc'ed state */
|
|
if (curfps && curfps->is_valloc)
|
|
vfree(curfps);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int validate_sigaltstack(unsigned int usize)
|
|
{
|
|
struct task_struct *thread, *leader = current->group_leader;
|
|
unsigned long framesize = get_sigframe_size();
|
|
|
|
lockdep_assert_held(¤t->sighand->siglock);
|
|
|
|
/* get_sigframe_size() is based on fpu_user_cfg.max_size */
|
|
framesize -= fpu_user_cfg.max_size;
|
|
framesize += usize;
|
|
for_each_thread(leader, thread) {
|
|
if (thread->sas_ss_size && thread->sas_ss_size < framesize)
|
|
return -ENOSPC;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __xstate_request_perm(u64 permitted, u64 requested, bool guest)
|
|
{
|
|
/*
|
|
* This deliberately does not exclude !XSAVES as we still might
|
|
* decide to optionally context switch XCR0 or talk the silicon
|
|
* vendors into extending XFD for the pre AMX states, especially
|
|
* AVX512.
|
|
*/
|
|
bool compacted = cpu_feature_enabled(X86_FEATURE_XCOMPACTED);
|
|
struct fpu *fpu = ¤t->group_leader->thread.fpu;
|
|
struct fpu_state_perm *perm;
|
|
unsigned int ksize, usize;
|
|
u64 mask;
|
|
int ret = 0;
|
|
|
|
/* Check whether fully enabled */
|
|
if ((permitted & requested) == requested)
|
|
return 0;
|
|
|
|
/* Calculate the resulting kernel state size */
|
|
mask = permitted | requested;
|
|
/* Take supervisor states into account on the host */
|
|
if (!guest)
|
|
mask |= xfeatures_mask_supervisor();
|
|
ksize = xstate_calculate_size(mask, compacted);
|
|
|
|
/* Calculate the resulting user state size */
|
|
mask &= XFEATURE_MASK_USER_SUPPORTED;
|
|
usize = xstate_calculate_size(mask, false);
|
|
|
|
if (!guest) {
|
|
ret = validate_sigaltstack(usize);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
perm = guest ? &fpu->guest_perm : &fpu->perm;
|
|
/* Pairs with the READ_ONCE() in xstate_get_group_perm() */
|
|
WRITE_ONCE(perm->__state_perm, mask);
|
|
/* Protected by sighand lock */
|
|
perm->__state_size = ksize;
|
|
perm->__user_state_size = usize;
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Permissions array to map facilities with more than one component
|
|
*/
|
|
static const u64 xstate_prctl_req[XFEATURE_MAX] = {
|
|
[XFEATURE_XTILE_DATA] = XFEATURE_MASK_XTILE_DATA,
|
|
};
|
|
|
|
static int xstate_request_perm(unsigned long idx, bool guest)
|
|
{
|
|
u64 permitted, requested;
|
|
int ret;
|
|
|
|
if (idx >= XFEATURE_MAX)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* Look up the facility mask which can require more than
|
|
* one xstate component.
|
|
*/
|
|
idx = array_index_nospec(idx, ARRAY_SIZE(xstate_prctl_req));
|
|
requested = xstate_prctl_req[idx];
|
|
if (!requested)
|
|
return -EOPNOTSUPP;
|
|
|
|
if ((fpu_user_cfg.max_features & requested) != requested)
|
|
return -EOPNOTSUPP;
|
|
|
|
/* Lockless quick check */
|
|
permitted = xstate_get_group_perm(guest);
|
|
if ((permitted & requested) == requested)
|
|
return 0;
|
|
|
|
/* Protect against concurrent modifications */
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
permitted = xstate_get_group_perm(guest);
|
|
|
|
/* First vCPU allocation locks the permissions. */
|
|
if (guest && (permitted & FPU_GUEST_PERM_LOCKED))
|
|
ret = -EBUSY;
|
|
else
|
|
ret = __xstate_request_perm(permitted, requested, guest);
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
return ret;
|
|
}
|
|
|
|
int __xfd_enable_feature(u64 xfd_err, struct fpu_guest *guest_fpu)
|
|
{
|
|
u64 xfd_event = xfd_err & XFEATURE_MASK_USER_DYNAMIC;
|
|
struct fpu_state_perm *perm;
|
|
unsigned int ksize, usize;
|
|
struct fpu *fpu;
|
|
|
|
if (!xfd_event) {
|
|
if (!guest_fpu)
|
|
pr_err_once("XFD: Invalid xfd error: %016llx\n", xfd_err);
|
|
return 0;
|
|
}
|
|
|
|
/* Protect against concurrent modifications */
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
|
/* If not permitted let it die */
|
|
if ((xstate_get_group_perm(!!guest_fpu) & xfd_event) != xfd_event) {
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
return -EPERM;
|
|
}
|
|
|
|
fpu = ¤t->group_leader->thread.fpu;
|
|
perm = guest_fpu ? &fpu->guest_perm : &fpu->perm;
|
|
ksize = perm->__state_size;
|
|
usize = perm->__user_state_size;
|
|
|
|
/*
|
|
* The feature is permitted. State size is sufficient. Dropping
|
|
* the lock is safe here even if more features are added from
|
|
* another task, the retrieved buffer sizes are valid for the
|
|
* currently requested feature(s).
|
|
*/
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
/*
|
|
* Try to allocate a new fpstate. If that fails there is no way
|
|
* out.
|
|
*/
|
|
if (fpstate_realloc(xfd_event, ksize, usize, guest_fpu))
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
int xfd_enable_feature(u64 xfd_err)
|
|
{
|
|
return __xfd_enable_feature(xfd_err, NULL);
|
|
}
|
|
|
|
#else /* CONFIG_X86_64 */
|
|
static inline int xstate_request_perm(unsigned long idx, bool guest)
|
|
{
|
|
return -EPERM;
|
|
}
|
|
#endif /* !CONFIG_X86_64 */
|
|
|
|
u64 xstate_get_guest_group_perm(void)
|
|
{
|
|
return xstate_get_group_perm(true);
|
|
}
|
|
EXPORT_SYMBOL_GPL(xstate_get_guest_group_perm);
|
|
|
|
/**
|
|
* fpu_xstate_prctl - xstate permission operations
|
|
* @option: A subfunction of arch_prctl()
|
|
* @arg2: option argument
|
|
* Return: 0 if successful; otherwise, an error code
|
|
*
|
|
* Option arguments:
|
|
*
|
|
* ARCH_GET_XCOMP_SUPP: Pointer to user space u64 to store the info
|
|
* ARCH_GET_XCOMP_PERM: Pointer to user space u64 to store the info
|
|
* ARCH_REQ_XCOMP_PERM: Facility number requested
|
|
*
|
|
* For facilities which require more than one XSTATE component, the request
|
|
* must be the highest state component number related to that facility,
|
|
* e.g. for AMX which requires XFEATURE_XTILE_CFG(17) and
|
|
* XFEATURE_XTILE_DATA(18) this would be XFEATURE_XTILE_DATA(18).
|
|
*/
|
|
long fpu_xstate_prctl(int option, unsigned long arg2)
|
|
{
|
|
u64 __user *uptr = (u64 __user *)arg2;
|
|
u64 permitted, supported;
|
|
unsigned long idx = arg2;
|
|
bool guest = false;
|
|
|
|
switch (option) {
|
|
case ARCH_GET_XCOMP_SUPP:
|
|
supported = fpu_user_cfg.max_features | fpu_user_cfg.legacy_features;
|
|
return put_user(supported, uptr);
|
|
|
|
case ARCH_GET_XCOMP_PERM:
|
|
/*
|
|
* Lockless snapshot as it can also change right after the
|
|
* dropping the lock.
|
|
*/
|
|
permitted = xstate_get_host_group_perm();
|
|
permitted &= XFEATURE_MASK_USER_SUPPORTED;
|
|
return put_user(permitted, uptr);
|
|
|
|
case ARCH_GET_XCOMP_GUEST_PERM:
|
|
permitted = xstate_get_guest_group_perm();
|
|
permitted &= XFEATURE_MASK_USER_SUPPORTED;
|
|
return put_user(permitted, uptr);
|
|
|
|
case ARCH_REQ_XCOMP_GUEST_PERM:
|
|
guest = true;
|
|
fallthrough;
|
|
|
|
case ARCH_REQ_XCOMP_PERM:
|
|
if (!IS_ENABLED(CONFIG_X86_64))
|
|
return -EOPNOTSUPP;
|
|
|
|
return xstate_request_perm(idx, guest);
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_PROC_PID_ARCH_STATUS
|
|
/*
|
|
* Report the amount of time elapsed in millisecond since last AVX512
|
|
* use in the task.
|
|
*/
|
|
static void avx512_status(struct seq_file *m, struct task_struct *task)
|
|
{
|
|
unsigned long timestamp = READ_ONCE(task->thread.fpu.avx512_timestamp);
|
|
long delta;
|
|
|
|
if (!timestamp) {
|
|
/*
|
|
* Report -1 if no AVX512 usage
|
|
*/
|
|
delta = -1;
|
|
} else {
|
|
delta = (long)(jiffies - timestamp);
|
|
/*
|
|
* Cap to LONG_MAX if time difference > LONG_MAX
|
|
*/
|
|
if (delta < 0)
|
|
delta = LONG_MAX;
|
|
delta = jiffies_to_msecs(delta);
|
|
}
|
|
|
|
seq_put_decimal_ll(m, "AVX512_elapsed_ms:\t", delta);
|
|
seq_putc(m, '\n');
|
|
}
|
|
|
|
/*
|
|
* Report architecture specific information
|
|
*/
|
|
int proc_pid_arch_status(struct seq_file *m, struct pid_namespace *ns,
|
|
struct pid *pid, struct task_struct *task)
|
|
{
|
|
/*
|
|
* Report AVX512 state if the processor and build option supported.
|
|
*/
|
|
if (cpu_feature_enabled(X86_FEATURE_AVX512F))
|
|
avx512_status(m, task);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_PROC_PID_ARCH_STATUS */
|
|
|
|
#ifdef CONFIG_COREDUMP
|
|
static const char owner_name[] = "LINUX";
|
|
|
|
/*
|
|
* Dump type, size, offset and flag values for every xfeature that is present.
|
|
*/
|
|
static int dump_xsave_layout_desc(struct coredump_params *cprm)
|
|
{
|
|
int num_records = 0;
|
|
int i;
|
|
|
|
for_each_extended_xfeature(i, fpu_user_cfg.max_features) {
|
|
struct x86_xfeat_component xc = {
|
|
.type = i,
|
|
.size = xstate_sizes[i],
|
|
.offset = xstate_offsets[i],
|
|
/* reserved for future use */
|
|
.flags = 0,
|
|
};
|
|
|
|
if (!dump_emit(cprm, &xc, sizeof(xc)))
|
|
return 0;
|
|
|
|
num_records++;
|
|
}
|
|
return num_records;
|
|
}
|
|
|
|
static u32 get_xsave_desc_size(void)
|
|
{
|
|
u32 cnt = 0;
|
|
u32 i;
|
|
|
|
for_each_extended_xfeature(i, fpu_user_cfg.max_features)
|
|
cnt++;
|
|
|
|
return cnt * (sizeof(struct x86_xfeat_component));
|
|
}
|
|
|
|
int elf_coredump_extra_notes_write(struct coredump_params *cprm)
|
|
{
|
|
int num_records = 0;
|
|
struct elf_note en;
|
|
|
|
if (!fpu_user_cfg.max_features)
|
|
return 0;
|
|
|
|
en.n_namesz = sizeof(owner_name);
|
|
en.n_descsz = get_xsave_desc_size();
|
|
en.n_type = NT_X86_XSAVE_LAYOUT;
|
|
|
|
if (!dump_emit(cprm, &en, sizeof(en)))
|
|
return 1;
|
|
if (!dump_emit(cprm, owner_name, en.n_namesz))
|
|
return 1;
|
|
if (!dump_align(cprm, 4))
|
|
return 1;
|
|
|
|
num_records = dump_xsave_layout_desc(cprm);
|
|
if (!num_records)
|
|
return 1;
|
|
|
|
/* Total size should be equal to the number of records */
|
|
if ((sizeof(struct x86_xfeat_component) * num_records) != en.n_descsz)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int elf_coredump_extra_notes_size(void)
|
|
{
|
|
int size;
|
|
|
|
if (!fpu_user_cfg.max_features)
|
|
return 0;
|
|
|
|
/* .note header */
|
|
size = sizeof(struct elf_note);
|
|
/* Name plus alignment to 4 bytes */
|
|
size += roundup(sizeof(owner_name), 4);
|
|
size += get_xsave_desc_size();
|
|
|
|
return size;
|
|
}
|
|
#endif /* CONFIG_COREDUMP */
|