@@ -997,6 +997,141 @@ static int ssve_set(struct task_struct *target,
997
997
ARM64_VEC_SME );
998
998
}
999
999
1000
+ static int za_get (struct task_struct * target ,
1001
+ const struct user_regset * regset ,
1002
+ struct membuf to )
1003
+ {
1004
+ struct user_za_header header ;
1005
+ unsigned int vq ;
1006
+ unsigned long start , end ;
1007
+
1008
+ if (!system_supports_sme ())
1009
+ return - EINVAL ;
1010
+
1011
+ /* Header */
1012
+ memset (& header , 0 , sizeof (header ));
1013
+
1014
+ if (test_tsk_thread_flag (target , TIF_SME_VL_INHERIT ))
1015
+ header .flags |= ZA_PT_VL_INHERIT ;
1016
+
1017
+ header .vl = task_get_sme_vl (target );
1018
+ vq = sve_vq_from_vl (header .vl );
1019
+ header .max_vl = sme_max_vl ();
1020
+ header .max_size = ZA_PT_SIZE (vq );
1021
+
1022
+ /* If ZA is not active there is only the header */
1023
+ if (thread_za_enabled (& target -> thread ))
1024
+ header .size = ZA_PT_SIZE (vq );
1025
+ else
1026
+ header .size = ZA_PT_ZA_OFFSET ;
1027
+
1028
+ membuf_write (& to , & header , sizeof (header ));
1029
+
1030
+ BUILD_BUG_ON (ZA_PT_ZA_OFFSET != sizeof (header ));
1031
+ end = ZA_PT_ZA_OFFSET ;
1032
+
1033
+ if (target == current )
1034
+ fpsimd_preserve_current_state ();
1035
+
1036
+ /* Any register data to include? */
1037
+ if (thread_za_enabled (& target -> thread )) {
1038
+ start = end ;
1039
+ end = ZA_PT_SIZE (vq );
1040
+ membuf_write (& to , target -> thread .za_state , end - start );
1041
+ }
1042
+
1043
+ /* Zero any trailing padding */
1044
+ start = end ;
1045
+ end = ALIGN (header .size , SVE_VQ_BYTES );
1046
+ return membuf_zero (& to , end - start );
1047
+ }
1048
+
1049
+ static int za_set (struct task_struct * target ,
1050
+ const struct user_regset * regset ,
1051
+ unsigned int pos , unsigned int count ,
1052
+ const void * kbuf , const void __user * ubuf )
1053
+ {
1054
+ int ret ;
1055
+ struct user_za_header header ;
1056
+ unsigned int vq ;
1057
+ unsigned long start , end ;
1058
+
1059
+ if (!system_supports_sme ())
1060
+ return - EINVAL ;
1061
+
1062
+ /* Header */
1063
+ if (count < sizeof (header ))
1064
+ return - EINVAL ;
1065
+ ret = user_regset_copyin (& pos , & count , & kbuf , & ubuf , & header ,
1066
+ 0 , sizeof (header ));
1067
+ if (ret )
1068
+ goto out ;
1069
+
1070
+ /*
1071
+ * All current ZA_PT_* flags are consumed by
1072
+ * vec_set_vector_length(), which will also validate them for
1073
+ * us:
1074
+ */
1075
+ ret = vec_set_vector_length (target , ARM64_VEC_SME , header .vl ,
1076
+ ((unsigned long )header .flags ) << 16 );
1077
+ if (ret )
1078
+ goto out ;
1079
+
1080
+ /* Actual VL set may be less than the user asked for: */
1081
+ vq = sve_vq_from_vl (task_get_sme_vl (target ));
1082
+
1083
+ /* Ensure there is some SVE storage for streaming mode */
1084
+ if (!target -> thread .sve_state ) {
1085
+ sve_alloc (target );
1086
+ if (!target -> thread .sve_state ) {
1087
+ clear_thread_flag (TIF_SME );
1088
+ ret = - ENOMEM ;
1089
+ goto out ;
1090
+ }
1091
+ }
1092
+
1093
+ /* Allocate/reinit ZA storage */
1094
+ sme_alloc (target );
1095
+ if (!target -> thread .za_state ) {
1096
+ ret = - ENOMEM ;
1097
+ clear_tsk_thread_flag (target , TIF_SME );
1098
+ goto out ;
1099
+ }
1100
+
1101
+ /* If there is no data then disable ZA */
1102
+ if (!count ) {
1103
+ target -> thread .svcr &= ~SYS_SVCR_EL0_ZA_MASK ;
1104
+ goto out ;
1105
+ }
1106
+
1107
+ /*
1108
+ * If setting a different VL from the requested VL and there is
1109
+ * register data, the data layout will be wrong: don't even
1110
+ * try to set the registers in this case.
1111
+ */
1112
+ if (vq != sve_vq_from_vl (header .vl )) {
1113
+ ret = - EIO ;
1114
+ goto out ;
1115
+ }
1116
+
1117
+ BUILD_BUG_ON (ZA_PT_ZA_OFFSET != sizeof (header ));
1118
+ start = ZA_PT_ZA_OFFSET ;
1119
+ end = ZA_PT_SIZE (vq );
1120
+ ret = user_regset_copyin (& pos , & count , & kbuf , & ubuf ,
1121
+ target -> thread .za_state ,
1122
+ start , end );
1123
+ if (ret )
1124
+ goto out ;
1125
+
1126
+ /* Mark ZA as active and let userspace use it */
1127
+ set_tsk_thread_flag (target , TIF_SME );
1128
+ target -> thread .svcr |= SYS_SVCR_EL0_ZA_MASK ;
1129
+
1130
+ out :
1131
+ fpsimd_flush_task_state (target );
1132
+ return ret ;
1133
+ }
1134
+
1000
1135
#endif /* CONFIG_ARM64_SME */
1001
1136
1002
1137
#ifdef CONFIG_ARM64_PTR_AUTH
@@ -1218,6 +1353,7 @@ enum aarch64_regset {
1218
1353
#endif
1219
1354
#ifdef CONFIG_ARM64_SVE
1220
1355
REGSET_SSVE ,
1356
+ REGSET_ZA ,
1221
1357
#endif
1222
1358
#ifdef CONFIG_ARM64_PTR_AUTH
1223
1359
REGSET_PAC_MASK ,
@@ -1309,6 +1445,14 @@ static const struct user_regset aarch64_regsets[] = {
1309
1445
.regset_get = ssve_get ,
1310
1446
.set = ssve_set ,
1311
1447
},
1448
+ [REGSET_ZA ] = { /* SME ZA */
1449
+ .core_note_type = NT_ARM_ZA ,
1450
+ .n = DIV_ROUND_UP (ZA_PT_ZA_SIZE (SVE_VQ_MAX ), SVE_VQ_BYTES ),
1451
+ .size = SVE_VQ_BYTES ,
1452
+ .align = SVE_VQ_BYTES ,
1453
+ .regset_get = za_get ,
1454
+ .set = za_set ,
1455
+ },
1312
1456
#endif
1313
1457
#ifdef CONFIG_ARM64_PTR_AUTH
1314
1458
[REGSET_PAC_MASK ] = {
0 commit comments