git: 1f9635e2c213 - stable/14 - arm64: Enable SVE in userspace

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 21 Oct 2024 15:05:15 UTC
The branch stable/14 has been updated by andrew:

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

commit 1f9635e2c213368cfed3737970f3814fbb55a922
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-09-27 14:06:03 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-10-21 15:03:27 +0000

    arm64: Enable SVE in userspace
    
    Report when SVE is present and allow it to be used by calling
    sve_restore_state on an SVE exception from userspace.
    
    Reviewed by:    kib
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D43310
    
    (cherry picked from commit 205c1007be6d57b2eb8620f79384cb2299dde40e)
---
 sys/arm64/arm64/identcpu.c | 82 ++++++++++++++++++++++++++++++++++++++--------
 sys/arm64/arm64/trap.c     |  6 ++--
 sys/arm64/include/armreg.h |  1 +
 3 files changed, 74 insertions(+), 15 deletions(-)

diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index 84ad2d0eb282..22978af219dc 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -1384,13 +1384,10 @@ static const struct mrs_field_value id_aa64pfr0_sve[] = {
 	MRS_FIELD_VALUE_END,
 };
 
-#if 0
-/* Enable when we add SVE support */
 static const struct mrs_field_hwcap id_aa64pfr0_sve_caps[] = {
 	MRS_HWCAP(1, HWCAP_SVE, ID_AA64PFR0_SVE_IMPL),
 	MRS_HWCAP_END
 };
-#endif
 
 static const struct mrs_field_value id_aa64pfr0_ras[] = {
 	MRS_FIELD_VALUE(ID_AA64PFR0_RAS_NONE, ""),
@@ -1464,7 +1461,8 @@ static const struct mrs_field id_aa64pfr0_fields[] = {
 	MRS_FIELD(ID_AA64PFR0, AMU, false, MRS_EXACT, id_aa64pfr0_amu),
 	MRS_FIELD(ID_AA64PFR0, MPAM, false, MRS_EXACT, id_aa64pfr0_mpam),
 	MRS_FIELD(ID_AA64PFR0, SEL2, false, MRS_EXACT, id_aa64pfr0_sel2),
-	MRS_FIELD(ID_AA64PFR0, SVE, false, MRS_EXACT, id_aa64pfr0_sve),
+	MRS_FIELD_HWCAP_SPLIT(ID_AA64PFR0, SVE, false, MRS_LOWER, MRS_EXACT,
+	    id_aa64pfr0_sve, id_aa64pfr0_sve_caps),
 	MRS_FIELD(ID_AA64PFR0, RAS, false, MRS_EXACT, id_aa64pfr0_ras),
 	MRS_FIELD(ID_AA64PFR0, GIC, false, MRS_EXACT, id_aa64pfr0_gic),
 	MRS_FIELD_HWCAP(ID_AA64PFR0, AdvSIMD, true, MRS_LOWER,
@@ -1581,59 +1579,117 @@ static const struct mrs_field_value id_aa64zfr0_f64mm[] = {
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_f64mm_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEF64MM, ID_AA64ZFR0_F64MM_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_f32mm[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, F32MM, NONE, IMPL),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_f32mm_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEF32MM, ID_AA64ZFR0_F32MM_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_i8mm[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, I8MM, NONE, IMPL),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_i8mm_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEI8MM, ID_AA64ZFR0_I8MM_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_sm4[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, SM4, NONE, IMPL),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_sm4_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVESM4, ID_AA64ZFR0_SM4_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_sha3[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, SHA3, NONE, IMPL),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_sha3_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVESHA3, ID_AA64ZFR0_SHA3_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_bf16[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, BF16, NONE, BASE),
 	MRS_FIELD_VALUE(ID_AA64ZFR0_BF16_EBF, "BF16+EBF"),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_bf16_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEBF16, ID_AA64ZFR0_BF16_BASE),
+	MRS_HWCAP(2, HWCAP2_SVE_EBF16, ID_AA64ZFR0_BF16_EBF),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_bitperm[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, BitPerm, NONE, IMPL),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_bitperm_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEBITPERM, ID_AA64ZFR0_BitPerm_IMPL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_aes[] = {
 	MRS_FIELD_VALUE_NONE_IMPL(ID_AA64ZFR0, AES, NONE, BASE),
 	MRS_FIELD_VALUE(ID_AA64ZFR0_AES_PMULL, "AES+PMULL"),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_aes_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVEAES, ID_AA64ZFR0_AES_BASE),
+	MRS_HWCAP(2, HWCAP2_SVEPMULL, ID_AA64ZFR0_AES_PMULL),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field_value id_aa64zfr0_svever[] = {
 	MRS_FIELD_VALUE(ID_AA64ZFR0_SVEver_SVE1, "SVE1"),
 	MRS_FIELD_VALUE(ID_AA64ZFR0_SVEver_SVE2, "SVE2"),
+	MRS_FIELD_VALUE(ID_AA64ZFR0_SVEver_SVE2P1, "SVE2P1"),
 	MRS_FIELD_VALUE_END,
 };
 
+static const struct mrs_field_hwcap id_aa64zfr0_svever_caps[] = {
+	MRS_HWCAP(2, HWCAP2_SVE2, ID_AA64ZFR0_SVEver_SVE2),
+	MRS_HWCAP(2, HWCAP2_SVE2P1, ID_AA64ZFR0_SVEver_SVE2P1),
+	MRS_HWCAP_END,
+};
+
 static const struct mrs_field id_aa64zfr0_fields[] = {
-	MRS_FIELD(ID_AA64ZFR0, F64MM, false, MRS_EXACT, id_aa64zfr0_f64mm),
-	MRS_FIELD(ID_AA64ZFR0, F32MM, false, MRS_EXACT, id_aa64zfr0_f32mm),
-	MRS_FIELD(ID_AA64ZFR0, I8MM, false, MRS_EXACT, id_aa64zfr0_i8mm),
-	MRS_FIELD(ID_AA64ZFR0, SM4, false, MRS_EXACT, id_aa64zfr0_sm4),
-	MRS_FIELD(ID_AA64ZFR0, SHA3, false, MRS_EXACT, id_aa64zfr0_sha3),
-	MRS_FIELD(ID_AA64ZFR0, BF16, false, MRS_EXACT, id_aa64zfr0_bf16),
-	MRS_FIELD(ID_AA64ZFR0, BitPerm, false, MRS_EXACT, id_aa64zfr0_bitperm),
-	MRS_FIELD(ID_AA64ZFR0, AES, false, MRS_EXACT, id_aa64zfr0_aes),
-	MRS_FIELD(ID_AA64ZFR0, SVEver, false, MRS_EXACT, id_aa64zfr0_svever),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, F64MM, false, MRS_LOWER,
+	    id_aa64zfr0_f64mm, id_aa64zfr0_f64mm_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, F32MM, false, MRS_LOWER,
+	    id_aa64zfr0_f32mm, id_aa64zfr0_f32mm_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, I8MM, false, MRS_LOWER, id_aa64zfr0_i8mm,
+	    id_aa64zfr0_i8mm_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, SM4, false, MRS_LOWER, id_aa64zfr0_sm4,
+	    id_aa64zfr0_sm4_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, SHA3, false, MRS_LOWER, id_aa64zfr0_sha3,
+	    id_aa64zfr0_sha3_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, BF16, false, MRS_LOWER, id_aa64zfr0_bf16,
+	    id_aa64zfr0_bf16_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, BitPerm, false, MRS_LOWER,
+	    id_aa64zfr0_bitperm, id_aa64zfr0_bitperm_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, AES, false, MRS_LOWER, id_aa64zfr0_aes,
+	    id_aa64zfr0_aes_caps),
+	MRS_FIELD_HWCAP(ID_AA64ZFR0, SVEver, false, MRS_LOWER,
+	    id_aa64zfr0_svever, id_aa64zfr0_svever_caps),
 	MRS_FIELD_END,
 };
 
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index 78582f5ac563..64a27b138a9a 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -635,8 +635,10 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
 #endif
 		break;
 	case EXCP_SVE:
-		call_trapsignal(td, SIGILL, ILL_ILLTRP, (void *)frame->tf_elr,
-		    exception);
+		/* Returns true if this thread can use SVE */
+		if (!sve_restore_state(td))
+			call_trapsignal(td, SIGILL, ILL_ILLTRP,
+			    (void *)frame->tf_elr, exception);
 		userret(td, frame);
 		break;
 	case EXCP_SVC32:
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index 2b92c036ef1c..6a3db5adc930 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -1535,6 +1535,7 @@
 #define	ID_AA64ZFR0_SVEver_VAL(x)	((x) & ID_AA64ZFR0_SVEver_MASK
 #define	ID_AA64ZFR0_SVEver_SVE1		(UL(0x0) << ID_AA64ZFR0_SVEver_SHIFT)
 #define	ID_AA64ZFR0_SVEver_SVE2		(UL(0x1) << ID_AA64ZFR0_SVEver_SHIFT)
+#define	ID_AA64ZFR0_SVEver_SVE2P1	(UL(0x2) << ID_AA64ZFR0_SVEver_SHIFT)
 #define	ID_AA64ZFR0_AES_SHIFT		4
 #define	ID_AA64ZFR0_AES_MASK		(UL(0xf) << ID_AA64ZFR0_AES_SHIFT)
 #define	ID_AA64ZFR0_AES_VAL(x)		((x) & ID_AA64ZFR0_AES_MASK