1 /* Initialize cpu feature data. s390x version.
2 Copyright (C) 2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <cpu-features.h>
22 # include <elf/dl-tunables.h>
23 # include <ifunc-memcmp.h>
25 extern __typeof (memcmp
) MEMCMP_DEFAULT
;
29 # define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR) \
30 (DEST_PTR)->hwcap = (SRC_PTR)->hwcap; \
31 (DEST_PTR)->stfle_bits[0] = (SRC_PTR)->stfle_bits[0];
34 TUNABLE_CALLBACK (set_hwcaps
) (tunable_val_t
*valp
)
36 /* The current IFUNC selection is always using the most recent
37 features which are available via AT_HWCAP or STFLE-bits. But in
38 some scenarios it is useful to adjust this selection.
40 The environment variable:
42 GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,zzz,....
44 can be used to enable HWCAP/STFLE feature yyy, disable HWCAP/STFLE feature
45 xxx, where the feature name is case-sensitive and has to match the ones
46 used below. Furthermore, the ARCH-level zzz can be used to set various
47 HWCAP/STFLE features at once. */
49 /* Copy the features from dl_s390_cpu_features, which contains the features
50 provided by AT_HWCAP and stfle-instruction. */
51 struct cpu_features
*cpu_features
= &GLRO(dl_s390_cpu_features
);
52 struct cpu_features cpu_features_orig
;
53 S390_COPY_CPU_FEATURES (cpu_features
, &cpu_features_orig
);
54 struct cpu_features cpu_features_curr
;
55 S390_COPY_CPU_FEATURES (cpu_features
, &cpu_features_curr
);
57 const char *token
= valp
->strval
;
60 const char *token_end
, *feature
;
65 /* Find token separator or end of string. */
66 for (token_end
= token
; *token_end
!= ','; token_end
++)
67 if (*token_end
== '\0')
70 /* Determine feature. */
71 token_len
= token_end
- token
;
76 feature_len
= token_len
- 1;
82 feature_len
= token_len
;
85 /* Handle only the features here which are really used in the
86 IFUNC-resolvers. All others are ignored as the values are only used
88 bool reset_features
= false;
89 unsigned long int hwcap_mask
= 0UL;
90 unsigned long long stfle_bits0_mask
= 0ULL;
92 if ((*feature
== 'z' || *feature
== 'a'))
94 if ((feature_len
== 5 && *feature
== 'z'
95 && MEMCMP_DEFAULT (feature
, "zEC12", 5) == 0)
96 || (feature_len
== 6 && *feature
== 'a'
97 && MEMCMP_DEFAULT (feature
, "arch10", 6) == 0))
99 reset_features
= true;
101 hwcap_mask
= HWCAP_S390_VXRS
| HWCAP_S390_VXRS_EXT
102 | HWCAP_S390_VXRS_EXT2
;
103 stfle_bits0_mask
= S390_STFLE_MASK_ARCH13_MIE3
;
105 else if ((feature_len
== 3 && *feature
== 'z'
106 && MEMCMP_DEFAULT (feature
, "z13", 3) == 0)
107 || (feature_len
== 6 && *feature
== 'a'
108 && MEMCMP_DEFAULT (feature
, "arch11", 6) == 0))
110 reset_features
= true;
112 hwcap_mask
= HWCAP_S390_VXRS_EXT
| HWCAP_S390_VXRS_EXT2
;
113 stfle_bits0_mask
= S390_STFLE_MASK_ARCH13_MIE3
;
115 else if ((feature_len
== 3 && *feature
== 'z'
116 && MEMCMP_DEFAULT (feature
, "z14", 3) == 0)
117 || (feature_len
== 6 && *feature
== 'a'
118 && MEMCMP_DEFAULT (feature
, "arch12", 6) == 0))
120 reset_features
= true;
122 hwcap_mask
= HWCAP_S390_VXRS_EXT2
;
123 stfle_bits0_mask
= S390_STFLE_MASK_ARCH13_MIE3
;
125 else if ((feature_len
== 3 && *feature
== 'z'
126 && (MEMCMP_DEFAULT (feature
, "z15", 3) == 0
127 || MEMCMP_DEFAULT (feature
, "z16", 3) == 0))
129 && (MEMCMP_DEFAULT (feature
, "arch13", 6) == 0
130 || MEMCMP_DEFAULT (feature
, "arch14", 6) == 0)))
132 /* For z15 or newer we don't have to disable something,
133 but we have to reset to the original values. */
134 reset_features
= true;
137 else if (*feature
== 'H')
139 if (feature_len
== 15
140 && MEMCMP_DEFAULT (feature
, "HWCAP_S390_VXRS", 15) == 0)
142 hwcap_mask
= HWCAP_S390_VXRS
;
144 hwcap_mask
|= HWCAP_S390_VXRS_EXT
| HWCAP_S390_VXRS_EXT2
;
146 else if (feature_len
== 19
147 && MEMCMP_DEFAULT (feature
, "HWCAP_S390_VXRS_EXT", 19) == 0)
149 hwcap_mask
= HWCAP_S390_VXRS_EXT
;
151 hwcap_mask
|= HWCAP_S390_VXRS_EXT2
;
153 hwcap_mask
|= HWCAP_S390_VXRS
;
155 else if (feature_len
== 20
156 && MEMCMP_DEFAULT (feature
, "HWCAP_S390_VXRS_EXT2", 20) == 0)
158 hwcap_mask
= HWCAP_S390_VXRS_EXT2
;
160 hwcap_mask
|= HWCAP_S390_VXRS
| HWCAP_S390_VXRS_EXT
;
163 else if (*feature
== 'S')
165 if (feature_len
== 10
166 && MEMCMP_DEFAULT (feature
, "STFLE_MIE3", 10) == 0)
168 stfle_bits0_mask
= S390_STFLE_MASK_ARCH13_MIE3
;
172 /* Perform the actions determined above. */
175 S390_COPY_CPU_FEATURES (&cpu_features_orig
, &cpu_features_curr
);
178 if (hwcap_mask
!= 0UL)
181 cpu_features_curr
.hwcap
&= ~hwcap_mask
;
183 cpu_features_curr
.hwcap
|= hwcap_mask
;
186 if (stfle_bits0_mask
!= 0ULL)
189 cpu_features_curr
.stfle_bits
[0] &= ~stfle_bits0_mask
;
191 cpu_features_curr
.stfle_bits
[0] |= stfle_bits0_mask
;
194 /* Jump over current token ... */
197 /* ... and skip token separator for next round. */
198 if (*token
== ',') token
++;
200 while (*token
!= '\0');
202 /* Copy back the features after checking that no unsupported features were
204 cpu_features
->hwcap
= cpu_features_curr
.hwcap
& cpu_features_orig
.hwcap
;
205 cpu_features
->stfle_bits
[0] = cpu_features_curr
.stfle_bits
[0]
206 & cpu_features_orig
.stfle_bits
[0];
211 init_cpu_features (struct cpu_features
*cpu_features
)
213 /* Fill cpu_features as passed by kernel and machine. */
214 cpu_features
->hwcap
= GLRO(dl_hwcap
);
216 /* We want just 1 double word to be returned. */
217 if (__glibc_likely ((cpu_features
->hwcap
& HWCAP_S390_STFLE
)
218 && (cpu_features
->hwcap
& HWCAP_S390_ZARCH
)
219 && (cpu_features
->hwcap
& HWCAP_S390_HIGH_GPRS
)))
221 register unsigned long reg0
__asm__("0") = 0;
222 __asm__
__volatile__(".machine push" "\n\t"
223 ".machine \"z9-109\"" "\n\t"
224 ".machinemode \"zarch_nohighgprs\"\n\t"
227 : "=QS" (cpu_features
->stfle_bits
[0]),
233 cpu_features
->stfle_bits
[0] = 0ULL;
237 TUNABLE_GET (glibc
, cpu
, hwcaps
, tunable_val_t
*, TUNABLE_CALLBACK (set_hwcaps
));