]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
x86/fpu/xstate: Differentiate default features for host and guest FPUs
authorChao Gao <chao.gao@intel.com>
Thu, 22 May 2025 15:10:04 +0000 (08:10 -0700)
committerDave Hansen <dave.hansen@linux.intel.com>
Tue, 24 Jun 2025 20:46:32 +0000 (13:46 -0700)
Currently, guest and host FPUs share the same default features. However,
the CET supervisor xstate is the first feature that needs to be enabled
exclusively for guest FPUs. Enabling it for host FPUs leads to a waste of
24 bytes in the XSAVE buffer.

To support "guest-only" features, add a new structure to hold the
default features and sizes for guest FPUs to clearly differentiate them
from those for host FPUs.

Add two helpers to provide the default feature masks for guest and host
FPUs. Default features are derived by applying the masks to the maximum
supported features.

Note that,
1) for now, guest_default_mask() and host_default_mask() are identical.
This will change in a follow-up patch once guest permissions, default
xfeatures, and fpstate size are all converted to use the guest defaults.

2) only supervisor features will diverge between guest FPUs and host
FPUs, while user features will remain the same [1][2]. So, the new
vcpu_fpu_config struct does not include default user features and size
for the UABI buffer.

An alternative approach is adding a guest_only_xfeatures member to
fpu_kernel_cfg and adding two helper functions to calculate the guest
default xfeatures and size. However, calculating these defaults at runtime
would introduce unnecessary overhead.

Suggested-by: Chang S. Bae <chang.seok.bae@intel.com>
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: John Allen <john.allen@amd.com>
Link: https://lore.kernel.org/kvm/aAwdQ759Y6V7SGhv@google.com/
Link: https://lore.kernel.org/kvm/9ca17e1169805f35168eb722734fbf3579187886.camel@intel.com/
Link: https://lore.kernel.org/all/20250522151031.426788-2-chao.gao%40intel.com
arch/x86/include/asm/fpu/types.h
arch/x86/kernel/fpu/core.c
arch/x86/kernel/fpu/init.c
arch/x86/kernel/fpu/xstate.c

index 1c94121acd3da7bf855c7740ddee0cd7f1793c71..abd193a1a52e9e705aac2b7cf92976b891c88c42 100644 (file)
@@ -551,6 +551,31 @@ struct fpu_guest {
        struct fpstate                  *fpstate;
 };
 
+/*
+ * FPU state configuration data for fpu_guest.
+ * Initialized at boot time. Read only after init.
+ */
+struct vcpu_fpu_config {
+       /*
+        * @size:
+        *
+        * The default size of the register state buffer in guest FPUs.
+        * Includes all supported features except independent managed
+        * features and features which have to be requested by user space
+        * before usage.
+        */
+       unsigned int size;
+
+       /*
+        * @features:
+        *
+        * The default supported features bitmap in guest FPUs. Does not
+        * include independent managed features and features which have to
+        * be requested by user space before usage.
+        */
+       u64 features;
+};
+
 /*
  * FPU state configuration data. Initialized at boot time. Read only after init.
  */
@@ -606,5 +631,6 @@ struct fpu_state_config {
 
 /* FPU state configuration information */
 extern struct fpu_state_config fpu_kernel_cfg, fpu_user_cfg;
+extern struct vcpu_fpu_config guest_default_cfg;
 
 #endif /* _ASM_X86_FPU_TYPES_H */
index ea138583dd92ac72014d95f60be2d5d0442029de..aa7252323cddfcde07ba18cebf39965c96c078a4 100644 (file)
@@ -37,6 +37,7 @@ DEFINE_PER_CPU(u64, xfd_state);
 /* The FPU state configuration data for kernel and user space */
 struct fpu_state_config        fpu_kernel_cfg __ro_after_init;
 struct fpu_state_config fpu_user_cfg __ro_after_init;
+struct vcpu_fpu_config guest_default_cfg __ro_after_init;
 
 /*
  * Represents the initial FPU state. It's mostly (but not completely) zeroes,
index 99db41bf9fa6b11cd92ff0b85f6779ed77f3f889..ff988b9ea39f0daddab94535d2b7d4052cc1ea34 100644 (file)
@@ -205,6 +205,7 @@ static void __init fpu__init_system_xstate_size_legacy(void)
        fpu_kernel_cfg.default_size = size;
        fpu_user_cfg.max_size = size;
        fpu_user_cfg.default_size = size;
+       guest_default_cfg.size = size;
 }
 
 /*
index 9aa9ac8399aee6dfec8a5db384ff62c531327837..7c5f9f1e0700185d174c6496c1cf0b3acaaa9ad4 100644 (file)
@@ -743,6 +743,9 @@ static int __init init_xstate_size(void)
        fpu_user_cfg.default_size =
                xstate_calculate_size(fpu_user_cfg.default_features, false);
 
+       guest_default_cfg.size =
+               xstate_calculate_size(guest_default_cfg.features, compacted);
+
        return 0;
 }
 
@@ -763,6 +766,7 @@ static void __init fpu__init_disable_system_xstate(unsigned int legacy_size)
        fpu_kernel_cfg.default_size = legacy_size;
        fpu_user_cfg.max_size = legacy_size;
        fpu_user_cfg.default_size = legacy_size;
+       guest_default_cfg.size = legacy_size;
 
        /*
         * Prevent enabling the static branch which enables writes to the
@@ -773,6 +777,21 @@ static void __init fpu__init_disable_system_xstate(unsigned int legacy_size)
        fpstate_reset(x86_task_fpu(current));
 }
 
+static u64 __init host_default_mask(void)
+{
+       /* Exclude dynamic features, which require userspace opt-in. */
+       return ~(u64)XFEATURE_MASK_USER_DYNAMIC;
+}
+
+static u64 __init guest_default_mask(void)
+{
+       /*
+        * Exclude dynamic features, which require userspace opt-in even
+        * for KVM guests.
+        */
+       return ~(u64)XFEATURE_MASK_USER_DYNAMIC;
+}
+
 /*
  * Enable and initialize the xsave feature.
  * Called once per system bootup.
@@ -855,12 +874,13 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
        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;
+       /*
+        * Now, given maximum feature set, determine default values by
+        * applying default masks.
+        */
+       fpu_kernel_cfg.default_features = fpu_kernel_cfg.max_features & host_default_mask();
+       fpu_user_cfg.default_features   = fpu_user_cfg.max_features & host_default_mask();
+       guest_default_cfg.features      = fpu_kernel_cfg.max_features & guest_default_mask();
 
        /* Store it for paranoia check at the end */
        xfeatures = fpu_kernel_cfg.max_features;