git: b9951017bab3 - main - amd64/fpu: Track supervisor state XSAVE components

From: Bojan Novković <bnovkov_at_FreeBSD.org>
Date: Wed, 22 Jan 2025 12:59:12 UTC
The branch main has been updated by bnovkov:

URL: https://cgit.FreeBSD.org/src/commit/?id=b9951017bab396e24042e85632e2cc34ee0329ff

commit b9951017bab396e24042e85632e2cc34ee0329ff
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2025-01-15 16:41:24 +0000
Commit:     Bojan Novković <bnovkov@FreeBSD.org>
CommitDate: 2025-01-22 12:58:34 +0000

    amd64/fpu: Track supervisor state XSAVE components
    
    The amd64/fpu.c xsave_* routines track supported XSAVE components and
    features. However, they only track supported user state components, and
    there is currently no way for a consumer to check whether the CPU
    supports a supervisor state component. Fix this by saving the supported
    supervisor state components, enumerated by CPUID function 0DH,
    sub-function 1, in a separate mask.
    
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D48466
---
 sys/amd64/amd64/fpu.c | 38 ++++++++++++++++++++++++--------------
 sys/x86/include/fpu.h |  5 +++--
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index 591bd196ca7d..79d1722268b7 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -164,6 +164,7 @@ SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
 
 int use_xsave;			/* non-static for cpu_switch.S */
 uint64_t xsave_mask;		/* the same */
+static	uint64_t xsave_mask_supervisor;
 static	uint64_t xsave_extensions;
 static	uma_zone_t fpu_save_area_zone;
 static	struct savefpu *fpu_initialstate;
@@ -324,6 +325,7 @@ fpuinit_bsp1(void)
 		ctx_switch_xsave[3] |= 0x10;
 		restore_wp(old_wp);
 	}
+	xsave_mask_supervisor = ((uint64_t)cp[3] << 32) | cp[2];
 }
 
 /*
@@ -421,7 +423,7 @@ fpuinitstate(void *arg __unused)
 	    XSAVE_AREA_ALIGN - 1, 0);
 	fpu_initialstate = uma_zalloc(fpu_save_area_zone, M_WAITOK | M_ZERO);
 	if (use_xsave) {
-		max_ext_n = flsl(xsave_mask);
+		max_ext_n = flsl(xsave_mask | xsave_mask_supervisor);
 		xsave_area_desc = malloc(max_ext_n * sizeof(struct
 		    xsave_area_elm_descr), M_DEVBUF, M_WAITOK | M_ZERO);
 	}
@@ -1293,19 +1295,25 @@ fpu_save_area_reset(struct savefpu *fsa)
 }
 
 static __inline void
-xsave_extfeature_check(uint64_t feature)
+xsave_extfeature_check(uint64_t feature, bool supervisor)
 {
+	uint64_t mask;
 
+	mask = supervisor ? xsave_mask_supervisor : xsave_mask;
 	KASSERT((feature & (feature - 1)) == 0,
 	    ("%s: invalid XFEATURE 0x%lx", __func__, feature));
-	KASSERT(feature < flsl(xsave_mask),
-	    ("%s: unsupported XFEATURE 0x%lx", __func__, feature));
+	KASSERT(ilog2(feature) <= ilog2(mask),
+	    ("%s: unsupported %s XFEATURE 0x%lx", __func__,
+	    supervisor ? "supervisor" : "user", feature));
 }
 
 static __inline void
-xsave_extstate_bv_check(uint64_t xstate_bv)
+xsave_extstate_bv_check(uint64_t xstate_bv, bool supervisor)
 {
-	KASSERT(xstate_bv != 0 && ilog2(xstate_bv) < flsl(xsave_mask),
+	uint64_t mask;
+
+	mask = supervisor ? xsave_mask_supervisor : xsave_mask;
+	KASSERT(xstate_bv != 0 && ilog2(xstate_bv) <= ilog2(mask),
 	    ("%s: invalid XSTATE_BV 0x%lx", __func__, xstate_bv));
 }
 
@@ -1317,11 +1325,13 @@ bool
 xsave_extfeature_supported(uint64_t feature, bool supervisor)
 {
 	int idx;
+	uint64_t mask;
 
 	KASSERT(use_xsave, ("%s: XSAVE not supported", __func__));
-	xsave_extfeature_check(feature);
+	xsave_extfeature_check(feature, supervisor);
 
-	if ((xsave_mask & feature) == 0)
+	mask = supervisor ? xsave_mask_supervisor : xsave_mask;
+	if ((mask & feature) == 0)
 		return (false);
 	idx = ilog2(feature);
 	return (((xsave_area_desc[idx].flags & CPUID_EXTSTATE_SUPERVISOR) != 0) ==
@@ -1345,15 +1355,15 @@ xsave_extension_supported(uint64_t extension)
  */
 size_t
 xsave_area_offset(uint64_t xstate_bv, uint64_t feature,
-    bool compact)
+    bool compact, bool supervisor)
 {
 	int i, idx;
 	size_t offs;
 	struct xsave_area_elm_descr *xep;
 
 	KASSERT(use_xsave, ("%s: XSAVE not supported", __func__));
-	xsave_extstate_bv_check(xstate_bv);
-	xsave_extfeature_check(feature);
+	xsave_extstate_bv_check(xstate_bv, supervisor);
+	xsave_extfeature_check(feature, supervisor);
 
 	idx = ilog2(feature);
 	if (!compact)
@@ -1376,16 +1386,16 @@ xsave_area_offset(uint64_t xstate_bv, uint64_t feature,
  * 'xstate_bv' and extended region format ('compact').
  */
 size_t
-xsave_area_size(uint64_t xstate_bv, bool compact)
+xsave_area_size(uint64_t xstate_bv, bool compact, bool supervisor)
 {
 	int last_idx;
 
 	KASSERT(use_xsave, ("%s: XSAVE not supported", __func__));
-	xsave_extstate_bv_check(xstate_bv);
+	xsave_extstate_bv_check(xstate_bv, supervisor);
 
 	last_idx = ilog2(xstate_bv);
 
-	return (xsave_area_offset(xstate_bv, (uint64_t)1 << last_idx, compact) +
+	return (xsave_area_offset(xstate_bv, (uint64_t)1 << last_idx, compact, supervisor) +
 	    xsave_area_desc[last_idx].size);
 }
 
diff --git a/sys/x86/include/fpu.h b/sys/x86/include/fpu.h
index 9d2e43f6386e..c94e058498f6 100644
--- a/sys/x86/include/fpu.h
+++ b/sys/x86/include/fpu.h
@@ -222,8 +222,9 @@ struct savefpu_ymm {
 bool	xsave_extfeature_supported(uint64_t feature, bool supervisor);
 bool	xsave_extension_supported(uint64_t extension);
 size_t	xsave_area_hdr_offset(void);
-size_t	xsave_area_offset(uint64_t xstate_bv, uint64_t feature, bool compact);
-size_t	xsave_area_size(uint64_t xstate_bv, bool compact);
+size_t	xsave_area_offset(uint64_t xstate_bv, uint64_t feature, bool compact,
+    bool supervisor);
+size_t	xsave_area_size(uint64_t xstate_bv, bool compact, bool supervisor);
 #endif
 
 #endif /* !_X86_FPU_H_ */