Commit 0c23929f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86-fpu-2025-07-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 FPU updates from Ingo Molnar:

 - Most of the changes are related to the implementation of CET
   supervisor state support for guests, and its preparatory changes
   (Chao Gao)

 - Improve/fix the debug output for unexpected FPU exceptions (Dave
   Hansen)

* tag 'x86-fpu-2025-07-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/fpu: Delay instruction pointer fixup until after warning
  x86/fpu/xstate: Add CET supervisor xfeature support as a guest-only feature
  x86/fpu/xstate: Introduce "guest-only" supervisor xfeature set
  x86/fpu: Remove xfd argument from __fpstate_reset()
  x86/fpu: Initialize guest fpstate and FPU pseudo container from guest defaults
  x86/fpu: Initialize guest FPU permissions from guest defaults
  x86/fpu/xstate: Differentiate default features for host and guest FPUs
parents 4dd39dde 1cec9ac2
Loading
Loading
Loading
Loading
+43 −6
Original line number Diff line number Diff line
@@ -118,7 +118,7 @@ enum xfeature {
	XFEATURE_PKRU,
	XFEATURE_PASID,
	XFEATURE_CET_USER,
	XFEATURE_CET_KERNEL_UNUSED,
	XFEATURE_CET_KERNEL,
	XFEATURE_RSRVD_COMP_13,
	XFEATURE_RSRVD_COMP_14,
	XFEATURE_LBR,
@@ -142,7 +142,7 @@ enum xfeature {
#define XFEATURE_MASK_PKRU		(1 << XFEATURE_PKRU)
#define XFEATURE_MASK_PASID		(1 << XFEATURE_PASID)
#define XFEATURE_MASK_CET_USER		(1 << XFEATURE_CET_USER)
#define XFEATURE_MASK_CET_KERNEL	(1 << XFEATURE_CET_KERNEL_UNUSED)
#define XFEATURE_MASK_CET_KERNEL	(1 << XFEATURE_CET_KERNEL)
#define XFEATURE_MASK_LBR		(1 << XFEATURE_LBR)
#define XFEATURE_MASK_XTILE_CFG		(1 << XFEATURE_XTILE_CFG)
#define XFEATURE_MASK_XTILE_DATA	(1 << XFEATURE_XTILE_DATA)
@@ -268,6 +268,16 @@ struct cet_user_state {
	u64 user_ssp;
};

/*
 * State component 12 is Control-flow Enforcement supervisor states.
 * This state includes SSP pointers for privilege levels 0 through 2.
 */
struct cet_supervisor_state {
	u64 pl0_ssp;
	u64 pl1_ssp;
	u64 pl2_ssp;
} __packed;

/*
 * State component 15: Architectural LBR configuration state.
 * The size of Arch LBR state depends on the number of LBRs (lbr_depth).
@@ -551,6 +561,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.
 */
@@ -567,8 +602,9 @@ struct fpu_state_config {
	 * @default_size:
	 *
	 * The default size of the register state buffer. Includes all
	 * supported features except independent managed features and
	 * features which have to be requested by user space before usage.
	 * supported features except independent managed features,
	 * guest-only features and features which have to be requested by
	 * user space before usage.
	 */
	unsigned int		default_size;

@@ -584,8 +620,8 @@ struct fpu_state_config {
	 * @default_features:
	 *
	 * The default supported features bitmap. Does not include
	 * independent managed features and features which have to
	 * be requested by user space before usage.
	 * independent managed features, guest-only features and features
	 * which have to be requested by user space before usage.
	 */
	u64 default_features;
	/*
@@ -606,5 +642,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 */
+6 −3
Original line number Diff line number Diff line
@@ -46,9 +46,13 @@
/* Features which are dynamically enabled for a process on request */
#define XFEATURE_MASK_USER_DYNAMIC	XFEATURE_MASK_XTILE_DATA

/* Supervisor features which are enabled only in guest FPUs */
#define XFEATURE_MASK_GUEST_SUPERVISOR	XFEATURE_MASK_CET_KERNEL

/* All currently supported supervisor features */
#define XFEATURE_MASK_SUPERVISOR_SUPPORTED (XFEATURE_MASK_PASID | \
					    XFEATURE_MASK_CET_USER)
					    XFEATURE_MASK_CET_USER | \
					    XFEATURE_MASK_GUEST_SUPERVISOR)

/*
 * A supervisor state component may not always contain valuable information,
@@ -75,8 +79,7 @@
 * Unsupported supervisor features. When a supervisor feature in this mask is
 * supported in the future, move it to the supported supervisor feature mask.
 */
#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT | \
					      XFEATURE_MASK_CET_KERNEL)
#define XFEATURE_MASK_SUPERVISOR_UNSUPPORTED (XFEATURE_MASK_PT)

/* All supervisor states including supported and unsupported states. */
#define XFEATURE_MASK_SUPERVISOR_ALL (XFEATURE_MASK_SUPERVISOR_SUPPORTED | \
+39 −14
Original line number Diff line number Diff line
@@ -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,
@@ -217,7 +218,7 @@ void fpu_reset_from_exception_fixup(void)
}

#if IS_ENABLED(CONFIG_KVM)
static void __fpstate_reset(struct fpstate *fpstate, u64 xfd);
static void __fpstate_reset(struct fpstate *fpstate);

static void fpu_lock_guest_permissions(void)
{
@@ -242,19 +243,21 @@ bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
	struct fpstate *fpstate;
	unsigned int size;

	size = fpu_kernel_cfg.default_size + ALIGN(offsetof(struct fpstate, regs), 64);
	size = guest_default_cfg.size + ALIGN(offsetof(struct fpstate, regs), 64);

	fpstate = vzalloc(size);
	if (!fpstate)
		return false;

	/* Leave xfd to 0 (the reset value defined by spec) */
	__fpstate_reset(fpstate, 0);
	fpstate_init_user(fpstate);
	/* Initialize indicators to reflect properties of the fpstate */
	fpstate->is_valloc	= true;
	fpstate->is_guest	= true;

	__fpstate_reset(fpstate);
	fpstate_init_user(fpstate);

	gfpu->fpstate		= fpstate;
	gfpu->xfeatures		= fpu_kernel_cfg.default_features;
	gfpu->xfeatures		= guest_default_cfg.features;

	/*
	 * KVM sets the FP+SSE bits in the XSAVE header when copying FPU state
@@ -541,28 +544,50 @@ void fpstate_init_user(struct fpstate *fpstate)
		fpstate_init_fstate(fpstate);
}

static void __fpstate_reset(struct fpstate *fpstate, u64 xfd)
static void __fpstate_reset(struct fpstate *fpstate)
{
	/* Initialize sizes and feature masks */
	/*
	 * Supervisor features (and thus sizes) may diverge between guest
	 * FPUs and host FPUs, as some supervisor features are supported
	 * for guests despite not being utilized by the host. User
	 * features and sizes are always identical, which allows for
	 * common guest and userspace ABI.
	 *
	 * For the host, set XFD to the kernel's desired initialization
	 * value. For guests, set XFD to its architectural RESET value.
	 */
	if (fpstate->is_guest) {
		fpstate->size		= guest_default_cfg.size;
		fpstate->xfeatures	= guest_default_cfg.features;
		fpstate->xfd		= 0;
	} else {
		fpstate->size		= fpu_kernel_cfg.default_size;
	fpstate->user_size	= fpu_user_cfg.default_size;
		fpstate->xfeatures	= fpu_kernel_cfg.default_features;
		fpstate->xfd		= init_fpstate.xfd;
	}

	fpstate->user_size	= fpu_user_cfg.default_size;
	fpstate->user_xfeatures	= fpu_user_cfg.default_features;
	fpstate->xfd		= xfd;
}

void fpstate_reset(struct fpu *fpu)
{
	/* Set the fpstate pointer to the default fpstate */
	fpu->fpstate = &fpu->__fpstate;
	__fpstate_reset(fpu->fpstate, init_fpstate.xfd);
	__fpstate_reset(fpu->fpstate);

	/* Initialize the permission related info in 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;

	fpu->guest_perm.__state_perm	= guest_default_cfg.features;
	fpu->guest_perm.__state_size	= guest_default_cfg.size;
	/*
	 * User features and sizes are always identical between host and
	 * guest FPUs, which allows for common guest and userspace ABI.
	 */
	fpu->guest_perm.__user_state_size = fpu_user_cfg.default_size;
}

static inline void fpu_inherit_perms(struct fpu *dst_fpu)
+1 −0
Original line number Diff line number Diff line
@@ -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;
}

/*
+33 −7
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ static const char *xfeature_names[] =
	"Protection Keys User registers",
	"PASID state",
	"Control-flow User registers",
	"Control-flow Kernel registers (unused)",
	"Control-flow Kernel registers (KVM only)",
	"unknown xstate feature",
	"unknown xstate feature",
	"unknown xstate feature",
@@ -81,6 +81,7 @@ static unsigned short xsave_cpuid_features[] __initdata = {
	[XFEATURE_PKRU]				= X86_FEATURE_OSPKE,
	[XFEATURE_PASID]			= X86_FEATURE_ENQCMD,
	[XFEATURE_CET_USER]			= X86_FEATURE_SHSTK,
	[XFEATURE_CET_KERNEL]			= X86_FEATURE_SHSTK,
	[XFEATURE_XTILE_CFG]			= X86_FEATURE_AMX_TILE,
	[XFEATURE_XTILE_DATA]			= X86_FEATURE_AMX_TILE,
	[XFEATURE_APX]				= X86_FEATURE_APX,
@@ -372,6 +373,7 @@ static __init void os_xrstor_booting(struct xregs_state *xstate)
	 XFEATURE_MASK_BNDCSR |			\
	 XFEATURE_MASK_PASID |			\
	 XFEATURE_MASK_CET_USER |		\
	 XFEATURE_MASK_CET_KERNEL |		\
	 XFEATURE_MASK_XTILE |			\
	 XFEATURE_MASK_APX)

@@ -573,6 +575,7 @@ static bool __init check_xstate_against_struct(int nr)
	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_CET_KERNEL: return XCHECK_SZ(sz, nr, struct cet_supervisor_state);
	case XFEATURE_APX:        return XCHECK_SZ(sz, nr, struct apx_state);
	case XFEATURE_XTILE_DATA: check_xtile_data_against_struct(sz); return true;
	default:
@@ -743,6 +746,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 +769,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 +780,24 @@ 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 (require userspace opt-in) and features
	 * that are supported only for KVM guests.
	 */
	return ~((u64)XFEATURE_MASK_USER_DYNAMIC | XFEATURE_MASK_GUEST_SUPERVISOR);
}

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 +880,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;
Loading