Re: [PATCH v2 4/6] x86/fpu/xstate: Introduce fpu_guest_cfg for guest FPU configuration

From: Dave Hansen
Date: Tue Mar 04 2025 - 17:50:44 EST


On 11/26/24 02:17, Chao Gao wrote:
> From: Yang Weijiang <weijiang.yang@xxxxxxxxx>
>
> Define new fpu_guest_cfg to hold all guest FPU settings so that it can
> differ from generic kernel FPU settings, e.g., enabling CET supervisor
> xstate by default for guest fpstate while it's remained disabled in
> kernel FPU config.
>
> The kernel dynamic xfeatures are specifically used by guest fpstate now,
> add the mask for guest fpstate so that guest_perm.__state_perm ==
> (fpu_kernel_cfg.default_xfeature | XFEATURE_MASK_KERNEL_DYNAMIC). And
> if guest fpstate is re-allocated to hold user dynamic xfeatures, the
> resulting permissions are consumed before calculate new guest fpstate.

This kinda restates what the code does, but I don't think it matches the
code.

> With new guest FPU config added, there're 3 categories of FPU configs in
> kernel, the usages and key fields are recapped as below.

This changelog is pretty rough. It's got a lot of words but not much
substance.


> kernel FPU config:
> @fpu_kernel_cfg.max_features
> - all known and CPU supported user and supervisor features except
> independent kernel features
>
> @fpu_kernel_cfg.default_features
> - all known and CPU supported user and supervisor features except
> dynamic kernel features, independent kernel features and dynamic
> userspace features.
>
> @fpu_kernel_cfg.max_size
> - size of compacted buffer with 'fpu_kernel_cfg.max_features'
>
> @fpu_kernel_cfg.default_size
> - size of compacted buffer with 'fpu_kernel_cfg.default_features'
>
> user FPU config:
> @fpu_user_cfg.max_features
> - all known and CPU supported user features
>
> @fpu_user_cfg.default_features
> - all known and CPU supported user features except dynamic userspace
> features.
>
> @fpu_user_cfg.max_size
> - size of non-compacted buffer with 'fpu_user_cfg.max_features'
>
> @fpu_user_cfg.default_size
> - size of non-compacted buffer with 'fpu_user_cfg.default_features'
>
> guest FPU config:
> @fpu_guest_cfg.max_features
> - all known and CPU supported user and supervisor features except
> independent kernel features.
>
> @fpu_guest_cfg.default_features
> - all known and CPU supported user and supervisor features except
> independent kernel features and dynamic userspace features.
>
> @fpu_guest_cfg.max_size
> - size of compacted buffer with 'fpu_guest_cfg.max_features'
>
> @fpu_guest_cfg.default_size
> - size of compacted buffer with 'fpu_guest_cfg.default_features'

This looks like kerneldoc, not changelog. Are you sure you want it _here_?


> diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h
> index b49e65120d34..da6583a1c0a2 100644
> --- a/arch/x86/include/asm/fpu/types.h
> +++ b/arch/x86/include/asm/fpu/types.h
> @@ -611,6 +611,6 @@ struct fpu_state_config {
> };
>
> /* FPU state configuration information */
> -extern struct fpu_state_config fpu_kernel_cfg, fpu_user_cfg;
> +extern struct fpu_state_config fpu_kernel_cfg, fpu_user_cfg, fpu_guest_cfg;
>
> #endif /* _ASM_X86_FPU_TYPES_H */
> diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
> index 1209c7aebb21..9e2e5c46cf28 100644
> --- a/arch/x86/kernel/fpu/core.c
> +++ b/arch/x86/kernel/fpu/core.c
> @@ -33,9 +33,10 @@ DEFINE_STATIC_KEY_FALSE(__fpu_state_size_dynamic);
> DEFINE_PER_CPU(u64, xfd_state);
> #endif
>
> -/* The FPU state configuration data for kernel and user space */
> +/* The FPU state configuration data for kernel, user space and guest. */
> struct fpu_state_config fpu_kernel_cfg __ro_after_init;
> struct fpu_state_config fpu_user_cfg __ro_after_init;
> +struct fpu_state_config fpu_guest_cfg __ro_after_init;
>
> /*
> * Represents the initial FPU state. It's mostly (but not completely) zeroes,
> @@ -536,8 +537,15 @@ void fpstate_reset(struct fpu *fpu)
> fpu->perm.__state_perm = fpu_kernel_cfg.default_features;
> fpu->perm.__state_size = fpu_kernel_cfg.default_size;
> fpu->perm.__user_state_size = fpu_user_cfg.default_size;
> - /* Same defaults for guests */
> - fpu->guest_perm = fpu->perm;
> +
> + /* Guest permission settings */
> + fpu->guest_perm.__state_perm = fpu_guest_cfg.default_features;
> + fpu->guest_perm.__state_size = fpu_guest_cfg.default_size;
> + /*
> + * Set guest's __user_state_size to fpu_user_cfg.default_size so that
> + * existing uAPIs can still work.
> + */
> + fpu->guest_perm.__user_state_size = fpu_user_cfg.default_size;
> }
>
> static inline void fpu_inherit_perms(struct fpu *dst_fpu)
> diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
> index c38e477e3e45..17c3255dfa41 100644
> --- a/arch/x86/kernel/fpu/xstate.c
> +++ b/arch/x86/kernel/fpu/xstate.c
> @@ -686,6 +686,7 @@ static int __init init_xstate_size(void)
> {
> /* Recompute the context size for enabled features: */
> unsigned int user_size, kernel_size, kernel_default_size;
> + unsigned int guest_default_size;
> bool compacted = cpu_feature_enabled(X86_FEATURE_XCOMPACTED);
>
> /* Uncompacted user space size */
> @@ -707,13 +708,18 @@ static int __init init_xstate_size(void)
> kernel_default_size =
> xstate_calculate_size(fpu_kernel_cfg.default_features, compacted);
>
> + guest_default_size =
> + xstate_calculate_size(fpu_guest_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_guest_cfg.max_size = kernel_size;
>
> fpu_kernel_cfg.default_size = kernel_default_size;
> + fpu_guest_cfg.default_size = guest_default_size;
> fpu_user_cfg.default_size =
> xstate_calculate_size(fpu_user_cfg.default_features, false);
>
> @@ -829,6 +835,10 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
> fpu_user_cfg.default_features = fpu_user_cfg.max_features;
> fpu_user_cfg.default_features &= ~XFEATURE_MASK_USER_DYNAMIC;
>
> + fpu_guest_cfg.max_features = fpu_kernel_cfg.max_features;
> + fpu_guest_cfg.default_features = fpu_guest_cfg.max_features;
> + fpu_guest_cfg.default_features &= ~XFEATURE_MASK_USER_DYNAMIC;

I thought this was saying above that it was _setting_ dynamic features.

Why _not_ set them by default?