31
31
32
32
#include "fp-ptrace.h"
33
33
34
+ #include <linux/bits.h>
35
+
36
+ #define FPMR_LSCALE2_MASK GENMASK(37, 32)
37
+ #define FPMR_NSCALE_MASK GENMASK(31, 24)
38
+ #define FPMR_LSCALE_MASK GENMASK(22, 16)
39
+ #define FPMR_OSC_MASK GENMASK(15, 15)
40
+ #define FPMR_OSM_MASK GENMASK(14, 14)
41
+
34
42
/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
35
43
#ifndef NT_ARM_SVE
36
44
#define NT_ARM_SVE 0x405
48
56
#define NT_ARM_ZT 0x40d
49
57
#endif
50
58
59
+ #ifndef NT_ARM_FPMR
60
+ #define NT_ARM_FPMR 0x40e
61
+ #endif
62
+
51
63
#define ARCH_VQ_MAX 256
52
64
53
65
/* VL 128..2048 in powers of 2 */
54
66
#define MAX_NUM_VLS 5
55
67
68
+ /*
69
+ * FPMR bits we can set without doing feature checks to see if values
70
+ * are valid.
71
+ */
72
+ #define FPMR_SAFE_BITS (FPMR_LSCALE2_MASK | FPMR_NSCALE_MASK | \
73
+ FPMR_LSCALE_MASK | FPMR_OSC_MASK | FPMR_OSM_MASK)
74
+
56
75
#define NUM_FPR 32
57
76
__uint128_t v_in [NUM_FPR ];
58
77
__uint128_t v_expected [NUM_FPR ];
@@ -78,6 +97,8 @@ char zt_in[ZT_SIG_REG_BYTES];
78
97
char zt_expected [ZT_SIG_REG_BYTES ];
79
98
char zt_out [ZT_SIG_REG_BYTES ];
80
99
100
+ uint64_t fpmr_in , fpmr_expected , fpmr_out ;
101
+
81
102
uint64_t sve_vl_out ;
82
103
uint64_t sme_vl_out ;
83
104
uint64_t svcr_in , svcr_expected , svcr_out ;
@@ -128,6 +149,11 @@ static bool fa64_supported(void)
128
149
return getauxval (AT_HWCAP2 ) & HWCAP2_SME_FA64 ;
129
150
}
130
151
152
+ static bool fpmr_supported (void )
153
+ {
154
+ return getauxval (AT_HWCAP2 ) & HWCAP2_FPMR ;
155
+ }
156
+
131
157
static bool compare_buffer (const char * name , void * out ,
132
158
void * expected , size_t size )
133
159
{
@@ -233,6 +259,8 @@ static void run_child(struct test_config *config)
233
259
flags |= HAVE_SME2 ;
234
260
if (fa64_supported ())
235
261
flags |= HAVE_FA64 ;
262
+ if (fpmr_supported ())
263
+ flags |= HAVE_FPMR ;
236
264
237
265
load_and_save (flags );
238
266
@@ -321,6 +349,14 @@ static void read_child_regs(pid_t child)
321
349
iov_child .iov_len = sizeof (zt_out );
322
350
read_one_child_regs (child , "ZT" , & iov_parent , & iov_child );
323
351
}
352
+
353
+ if (fpmr_supported ()) {
354
+ iov_parent .iov_base = & fpmr_out ;
355
+ iov_parent .iov_len = sizeof (fpmr_out );
356
+ iov_child .iov_base = & fpmr_out ;
357
+ iov_child .iov_len = sizeof (fpmr_out );
358
+ read_one_child_regs (child , "FPMR" , & iov_parent , & iov_child );
359
+ }
324
360
}
325
361
326
362
static bool continue_breakpoint (pid_t child ,
@@ -595,6 +631,26 @@ static bool check_ptrace_values_zt(pid_t child, struct test_config *config)
595
631
return compare_buffer ("initial ZT" , buf , zt_in , ZT_SIG_REG_BYTES );
596
632
}
597
633
634
+ static bool check_ptrace_values_fpmr (pid_t child , struct test_config * config )
635
+ {
636
+ uint64_t val ;
637
+ struct iovec iov ;
638
+ int ret ;
639
+
640
+ if (!fpmr_supported ())
641
+ return true;
642
+
643
+ iov .iov_base = & val ;
644
+ iov .iov_len = sizeof (val );
645
+ ret = ptrace (PTRACE_GETREGSET , child , NT_ARM_FPMR , & iov );
646
+ if (ret != 0 ) {
647
+ ksft_print_msg ("Failed to read initial FPMR: %s (%d)\n" ,
648
+ strerror (errno ), errno );
649
+ return false;
650
+ }
651
+
652
+ return compare_buffer ("initial FPMR" , & val , & fpmr_in , sizeof (val ));
653
+ }
598
654
599
655
static bool check_ptrace_values (pid_t child , struct test_config * config )
600
656
{
@@ -629,6 +685,9 @@ static bool check_ptrace_values(pid_t child, struct test_config *config)
629
685
if (!check_ptrace_values_zt (child , config ))
630
686
pass = false;
631
687
688
+ if (!check_ptrace_values_fpmr (child , config ))
689
+ pass = false;
690
+
632
691
return pass ;
633
692
}
634
693
@@ -832,11 +891,18 @@ static void set_initial_values(struct test_config *config)
832
891
{
833
892
int vq = __sve_vq_from_vl (vl_in (config ));
834
893
int sme_vq = __sve_vq_from_vl (config -> sme_vl_in );
894
+ bool sm_change ;
835
895
836
896
svcr_in = config -> svcr_in ;
837
897
svcr_expected = config -> svcr_expected ;
838
898
svcr_out = 0 ;
839
899
900
+ if (sme_supported () &&
901
+ (svcr_in & SVCR_SM ) != (svcr_expected & SVCR_SM ))
902
+ sm_change = true;
903
+ else
904
+ sm_change = false;
905
+
840
906
fill_random (& v_in , sizeof (v_in ));
841
907
memcpy (v_expected , v_in , sizeof (v_in ));
842
908
memset (v_out , 0 , sizeof (v_out ));
@@ -883,6 +949,21 @@ static void set_initial_values(struct test_config *config)
883
949
memset (zt_expected , 0 , ZT_SIG_REG_BYTES );
884
950
memset (zt_out , 0 , sizeof (zt_out ));
885
951
}
952
+
953
+ if (fpmr_supported ()) {
954
+ fill_random (& fpmr_in , sizeof (fpmr_in ));
955
+ fpmr_in &= FPMR_SAFE_BITS ;
956
+
957
+ /* Entering or exiting streaming mode clears FPMR */
958
+ if (sm_change )
959
+ fpmr_expected = 0 ;
960
+ else
961
+ fpmr_expected = fpmr_in ;
962
+ } else {
963
+ fpmr_in = 0 ;
964
+ fpmr_expected = 0 ;
965
+ fpmr_out = 0 ;
966
+ }
886
967
}
887
968
888
969
static bool check_memory_values (struct test_config * config )
@@ -933,6 +1014,12 @@ static bool check_memory_values(struct test_config *config)
933
1014
if (!compare_buffer ("saved ZT" , zt_out , zt_expected , ZT_SIG_REG_BYTES ))
934
1015
pass = false;
935
1016
1017
+ if (fpmr_out != fpmr_expected ) {
1018
+ ksft_print_msg ("Mismatch in saved FPMR: %lx != %lx\n" ,
1019
+ fpmr_out , fpmr_expected );
1020
+ pass = false;
1021
+ }
1022
+
936
1023
return pass ;
937
1024
}
938
1025
@@ -1010,6 +1097,36 @@ static void fpsimd_write(pid_t child, struct test_config *test_config)
1010
1097
strerror (errno ), errno );
1011
1098
}
1012
1099
1100
+ static bool fpmr_write_supported (struct test_config * config )
1101
+ {
1102
+ if (!fpmr_supported ())
1103
+ return false;
1104
+
1105
+ if (!sve_sme_same (config ))
1106
+ return false;
1107
+
1108
+ return true;
1109
+ }
1110
+
1111
+ static void fpmr_write_expected (struct test_config * config )
1112
+ {
1113
+ fill_random (& fpmr_expected , sizeof (fpmr_expected ));
1114
+ fpmr_expected &= FPMR_SAFE_BITS ;
1115
+ }
1116
+
1117
+ static void fpmr_write (pid_t child , struct test_config * config )
1118
+ {
1119
+ struct iovec iov ;
1120
+ int ret ;
1121
+
1122
+ iov .iov_len = sizeof (fpmr_expected );
1123
+ iov .iov_base = & fpmr_expected ;
1124
+ ret = ptrace (PTRACE_SETREGSET , child , NT_ARM_FPMR , & iov );
1125
+ if (ret != 0 )
1126
+ ksft_print_msg ("Failed to write FPMR: %s (%d)\n" ,
1127
+ strerror (errno ), errno );
1128
+ }
1129
+
1013
1130
static void sve_write_expected (struct test_config * config )
1014
1131
{
1015
1132
int vl = vl_expected (config );
@@ -1266,6 +1383,12 @@ static struct test_definition base_test_defs[] = {
1266
1383
.set_expected_values = fpsimd_write_expected ,
1267
1384
.modify_values = fpsimd_write ,
1268
1385
},
1386
+ {
1387
+ .name = "FPMR write" ,
1388
+ .supported = fpmr_write_supported ,
1389
+ .set_expected_values = fpmr_write_expected ,
1390
+ .modify_values = fpmr_write ,
1391
+ },
1269
1392
};
1270
1393
1271
1394
static struct test_definition sve_test_defs [] = {
@@ -1475,6 +1598,9 @@ int main(void)
1475
1598
if (fa64_supported ())
1476
1599
ksft_print_msg ("FA64 supported\n" );
1477
1600
1601
+ if (fpmr_supported ())
1602
+ ksft_print_msg ("FPMR supported\n" );
1603
+
1478
1604
ksft_set_plan (tests );
1479
1605
1480
1606
/* Get signal handers ready before we start any children */
0 commit comments