@@ -21,13 +21,13 @@ struct riscv_hwprobe {
21
21
#[ allow( non_upper_case_globals) ]
22
22
const __NR_riscv_hwprobe: libc:: c_long = 258 ;
23
23
24
- const RISCV_HWPROBE_KEY_BASE_BEHAVIOR : i64 = 3 ;
25
- const RISCV_HWPROBE_BASE_BEHAVIOR_IMA : u64 = 1 << 0 ;
24
+ // const RISCV_HWPROBE_KEY_BASE_BEHAVIOR: i64 = 3;
25
+ // const RISCV_HWPROBE_BASE_BEHAVIOR_IMA: u64 = 1 << 0;
26
26
27
27
const RISCV_HWPROBE_KEY_IMA_EXT_0 : i64 = 4 ;
28
- const RISCV_HWPROBE_IMA_FD : u64 = 1 << 0 ;
29
- const RISCV_HWPROBE_IMA_C : u64 = 1 << 1 ;
30
- const RISCV_HWPROBE_IMA_V : u64 = 1 << 2 ;
28
+ // const RISCV_HWPROBE_IMA_FD: u64 = 1 << 0;
29
+ // const RISCV_HWPROBE_IMA_C: u64 = 1 << 1;
30
+ // const RISCV_HWPROBE_IMA_V: u64 = 1 << 2;
31
31
const RISCV_HWPROBE_EXT_ZBA : u64 = 1 << 3 ;
32
32
const RISCV_HWPROBE_EXT_ZBB : u64 = 1 << 4 ;
33
33
const RISCV_HWPROBE_EXT_ZBS : u64 = 1 << 5 ;
@@ -62,11 +62,11 @@ const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33;
62
62
const RISCV_HWPROBE_EXT_ZACAS : u64 = 1 << 34 ;
63
63
// const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35;
64
64
const RISCV_HWPROBE_EXT_ZIHINTPAUSE : u64 = 1 << 36 ;
65
- const RISCV_HWPROBE_EXT_ZVE32X : u64 = 1 << 37 ;
66
- const RISCV_HWPROBE_EXT_ZVE32F : u64 = 1 << 38 ;
67
- const RISCV_HWPROBE_EXT_ZVE64X : u64 = 1 << 39 ;
68
- const RISCV_HWPROBE_EXT_ZVE64F : u64 = 1 << 40 ;
69
- const RISCV_HWPROBE_EXT_ZVE64D : u64 = 1 << 41 ;
65
+ // const RISCV_HWPROBE_EXT_ZVE32X: u64 = 1 << 37;
66
+ // const RISCV_HWPROBE_EXT_ZVE32F: u64 = 1 << 38;
67
+ // const RISCV_HWPROBE_EXT_ZVE64X: u64 = 1 << 39;
68
+ // const RISCV_HWPROBE_EXT_ZVE64F: u64 = 1 << 40;
69
+ // const RISCV_HWPROBE_EXT_ZVE64D: u64 = 1 << 41;
70
70
// const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42;
71
71
// const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43;
72
72
// const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44;
@@ -113,11 +113,79 @@ fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool {
113
113
pub ( crate ) fn detect_features ( ) -> cache:: Initializer {
114
114
let mut value = cache:: Initializer :: default ( ) ;
115
115
116
+ let enable_feature = |value : & mut cache:: Initializer , feature, enable| {
117
+ if enable {
118
+ value. set ( feature as u32 ) ;
119
+ }
120
+ } ;
121
+ let enable_features = |value : & mut cache:: Initializer , feature_slice : & [ Feature ] , enable| {
122
+ if enable {
123
+ for feature in feature_slice {
124
+ value. set ( * feature as u32 ) ;
125
+ }
126
+ }
127
+ } ;
128
+
129
+ // The values are part of the platform-specific [asm/hwcap.h][hwcap]
130
+ //
131
+ // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/hwcap.h
132
+ let auxv = auxvec:: auxv ( ) . expect ( "read auxvec" ) ; // should not fail on RISC-V platform
133
+ #[ allow( clippy:: eq_op) ]
134
+ enable_feature (
135
+ & mut value,
136
+ Feature :: a,
137
+ bit:: test ( auxv. hwcap , ( b'a' - b'a' ) . into ( ) ) ,
138
+ ) ;
139
+ enable_feature (
140
+ & mut value,
141
+ Feature :: c,
142
+ bit:: test ( auxv. hwcap , ( b'c' - b'a' ) . into ( ) ) ,
143
+ ) ;
144
+ enable_features (
145
+ & mut value,
146
+ & [ Feature :: d, Feature :: f, Feature :: zicsr] ,
147
+ bit:: test ( auxv. hwcap , ( b'd' - b'a' ) . into ( ) ) ,
148
+ ) ;
149
+ enable_features (
150
+ & mut value,
151
+ & [ Feature :: f, Feature :: zicsr] ,
152
+ bit:: test ( auxv. hwcap , ( b'f' - b'a' ) . into ( ) ) ,
153
+ ) ;
154
+ let has_i = bit:: test ( auxv. hwcap , ( b'i' - b'a' ) . into ( ) ) ;
155
+ // If future RV128I is supported, implement with `enable_feature` here
156
+ // Checking target_pointer_width instead of target_arch is incorrect since
157
+ // there are RV64ILP32* ABIs.
158
+ #[ cfg( target_arch = "riscv64" ) ]
159
+ enable_feature ( & mut value, Feature :: rv64i, has_i) ;
160
+ #[ cfg( target_arch = "riscv32" ) ]
161
+ enable_feature ( & mut value, Feature :: rv32i, has_i) ;
162
+ // FIXME: e is not exposed in any of asm/hwcap.h, uapi/asm/hwcap.h, uapi/asm/hwprobe.h
163
+ #[ cfg( target_arch = "riscv32" ) ]
164
+ enable_feature (
165
+ & mut value,
166
+ Feature :: rv32e,
167
+ bit:: test ( auxv. hwcap , ( b'e' - b'a' ) . into ( ) ) ,
168
+ ) ;
169
+ enable_feature (
170
+ & mut value,
171
+ Feature :: m,
172
+ bit:: test ( auxv. hwcap , ( b'm' - b'a' ) . into ( ) ) ,
173
+ ) ;
174
+ let has_v = bit:: test ( auxv. hwcap , ( b'v' - b'a' ) . into ( ) ) ;
175
+ enable_features (
176
+ & mut value,
177
+ & [
178
+ Feature :: v,
179
+ Feature :: zve32f,
180
+ Feature :: zve32x,
181
+ Feature :: zve64d,
182
+ Feature :: zve64f,
183
+ Feature :: zve64x,
184
+ ] ,
185
+ has_v,
186
+ ) ;
187
+
116
188
let mut out = [
117
- riscv_hwprobe {
118
- key : RISCV_HWPROBE_KEY_BASE_BEHAVIOR ,
119
- value : 0 ,
120
- } ,
121
189
riscv_hwprobe {
122
190
key : RISCV_HWPROBE_KEY_IMA_EXT_0 ,
123
191
value : 0 ,
@@ -138,23 +206,13 @@ pub(crate) fn detect_features() -> cache::Initializer {
138
206
}
139
207
} ;
140
208
if out[ 0 ] . key != -1 {
141
- let base_behavior = out[ 0 ] . value ;
142
- let ima = base_behavior & RISCV_HWPROBE_BASE_BEHAVIOR_IMA != 0 ;
143
- // If future RV128I is supported, implement with `enable_feature` here
144
- #[ cfg( target_arch = "riscv32" ) ]
145
- enable_feature ( Feature :: rv32i, ima) ;
146
- #[ cfg( target_arch = "riscv64" ) ]
147
- enable_feature ( Feature :: rv64i, ima) ;
148
- enable_feature ( Feature :: m, ima) ;
149
- enable_feature ( Feature :: a, ima) ;
150
- }
151
- if out[ 1 ] . key != -1 {
152
- let ima_ext_0 = out[ 1 ] . value ;
153
- let fd = ima_ext_0 & RISCV_HWPROBE_IMA_FD != 0 ;
154
- enable_feature ( Feature :: f, fd) ;
155
- enable_feature ( Feature :: d, fd) ;
156
- enable_feature ( Feature :: zicsr, fd) ; // implied by f
157
- enable_feature ( Feature :: c, ima_ext_0 & RISCV_HWPROBE_IMA_C != 0 ) ;
209
+ let ima_ext_0 = out[ 0 ] . value ;
210
+ // i, m, a, f, d, zicsr, and c extensions are detected by hwcap.
211
+ // let fd = ima_ext_0 & RISCV_HWPROBE_IMA_FD != 0;
212
+ // enable_feature(Feature::f, fd);
213
+ // enable_feature(Feature::d, fd);
214
+ // enable_feature(Feature::zicsr, fd); // implied by f
215
+ // enable_feature(Feature::c, ima_ext_0 & RISCV_HWPROBE_IMA_C != 0);
158
216
// enable_feature(Feature::zicboz, ima_ext_0 & RISCV_HWPROBE_EXT_ZICBOZ != 0);
159
217
enable_feature ( Feature :: zfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZFH != 0 ) ;
160
218
enable_feature ( Feature :: zfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZFHMIN != 0 ) ;
@@ -203,129 +261,64 @@ pub(crate) fn detect_features() -> cache::Initializer {
203
261
enable_feature ( Feature :: zkn, zkn) ;
204
262
// enable_feature(Feature::zk, zkn & zkr & zkt);
205
263
enable_feature ( Feature :: zks, zbkb & zbkc & zbkx & zksed & zksh) ;
206
- // Standard Vector Extensions
207
- enable_feature ( Feature :: v, ima_ext_0 & RISCV_HWPROBE_IMA_V != 0 ) ;
208
- enable_feature ( Feature :: zvfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH != 0 ) ;
209
- enable_feature ( Feature :: zvfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFHMIN != 0 ) ;
210
- enable_feature ( Feature :: zve32x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32X != 0 ) ;
211
- enable_feature ( Feature :: zve32f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32F != 0 ) ;
212
- enable_feature ( Feature :: zve64x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64X != 0 ) ;
213
- enable_feature ( Feature :: zve64f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64F != 0 ) ;
214
- enable_feature ( Feature :: zve64d, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64D != 0 ) ;
215
- // Vector Cryptography and Bit-manipulation Extensions
216
- let zvbb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBB != 0 ;
217
- enable_feature ( Feature :: zvbb, zvbb) ;
218
- let zvbc = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBC != 0 ;
219
- enable_feature ( Feature :: zvbc, zvbc) ;
220
- let zvkb = zvbb || ima_ext_0 & RISCV_HWPROBE_EXT_ZVKB != 0 ;
221
- enable_feature ( Feature :: zvkb, zvkb) ;
222
- let zvkg = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKG != 0 ;
223
- enable_feature ( Feature :: zvkg, zvkg) ;
224
- let zvkned = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNED != 0 ;
225
- enable_feature ( Feature :: zvkned, zvkned) ;
226
- enable_feature ( Feature :: zvknha, ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHA != 0 ) ;
227
- let zvknhb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHB != 0 ;
228
- enable_feature ( Feature :: zvknhb, zvknhb) ;
229
- let zvksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSED != 0 ;
230
- enable_feature ( Feature :: zvksed, zvksed) ;
231
- let zvksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSH != 0 ;
232
- enable_feature ( Feature :: zvksh, zvksh) ;
233
- let zvkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKT != 0 ;
234
- enable_feature ( Feature :: zvkt, zvkt) ;
235
- let zvkn = zvkned & zvknhb & zvkb & zvkt;
236
- enable_feature ( Feature :: zvkn, zvkn) ;
237
- enable_feature ( Feature :: zvknc, zvkn & zvbc) ;
238
- enable_feature ( Feature :: zvkng, zvkn & zvkg) ;
239
- let zvks = zvksed & zvksh & zvkb & zvkt;
240
- enable_feature ( Feature :: zvks, zvks) ;
241
- enable_feature ( Feature :: zvksc, zvks & zvbc) ;
242
- enable_feature ( Feature :: zvksg, zvks & zvkg) ;
264
+ // Refer result from hwcap because it reflects Vector enablement status, unlike hwprobe.
265
+ // prctl(PR_RISCV_V_GET_CONTROL) is another way to check this but it doesn't work with
266
+ // qemu-user (as of 9.2.1).
267
+ // See https://docs.kernel.org/arch/riscv/vector.html for more.
268
+ if has_v {
269
+ // Standard Vector Extensions
270
+ // v and zve{32,64}* extensions are detected by hwcap.
271
+ // enable_feature(Feature::v, ima_ext_0 & RISCV_HWPROBE_IMA_V != 0);
272
+ enable_feature ( Feature :: zvfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH != 0 ) ;
273
+ enable_feature ( Feature :: zvfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZVFHMIN != 0 ) ;
274
+ // enable_feature(Feature::zve32x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32X != 0);
275
+ // enable_feature(Feature::zve32f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE32F != 0);
276
+ // enable_feature(Feature::zve64x, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64X != 0);
277
+ // enable_feature(Feature::zve64f, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64F != 0);
278
+ // enable_feature(Feature::zve64d, ima_ext_0 & RISCV_HWPROBE_EXT_ZVE64D != 0);
279
+ // Vector Cryptography and Bit-manipulation Extensions
280
+ let zvbb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBB != 0 ;
281
+ enable_feature ( Feature :: zvbb, zvbb) ;
282
+ let zvbc = ima_ext_0 & RISCV_HWPROBE_EXT_ZVBC != 0 ;
283
+ enable_feature ( Feature :: zvbc, zvbc) ;
284
+ let zvkb = zvbb || ima_ext_0 & RISCV_HWPROBE_EXT_ZVKB != 0 ;
285
+ enable_feature ( Feature :: zvkb, zvkb) ;
286
+ let zvkg = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKG != 0 ;
287
+ enable_feature ( Feature :: zvkg, zvkg) ;
288
+ let zvkned = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNED != 0 ;
289
+ enable_feature ( Feature :: zvkned, zvkned) ;
290
+ enable_feature ( Feature :: zvknha, ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHA != 0 ) ;
291
+ let zvknhb = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKNHB != 0 ;
292
+ enable_feature ( Feature :: zvknhb, zvknhb) ;
293
+ let zvksed = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSED != 0 ;
294
+ enable_feature ( Feature :: zvksed, zvksed) ;
295
+ let zvksh = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKSH != 0 ;
296
+ enable_feature ( Feature :: zvksh, zvksh) ;
297
+ let zvkt = ima_ext_0 & RISCV_HWPROBE_EXT_ZVKT != 0 ;
298
+ enable_feature ( Feature :: zvkt, zvkt) ;
299
+ let zvkn = zvkned & zvknhb & zvkb & zvkt;
300
+ enable_feature ( Feature :: zvkn, zvkn) ;
301
+ enable_feature ( Feature :: zvknc, zvkn & zvbc) ;
302
+ enable_feature ( Feature :: zvkng, zvkn & zvkg) ;
303
+ let zvks = zvksed & zvksh & zvkb & zvkt;
304
+ enable_feature ( Feature :: zvks, zvks) ;
305
+ enable_feature ( Feature :: zvksc, zvks & zvbc) ;
306
+ enable_feature ( Feature :: zvksg, zvks & zvkg) ;
307
+ }
243
308
}
244
- if out[ 2 ] . key != -1 {
309
+ if out[ 1 ] . key != -1 {
245
310
enable_feature (
246
311
Feature :: unaligned_scalar_mem,
247
- out[ 2 ] . value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST ,
312
+ out[ 1 ] . value & RISCV_HWPROBE_MISALIGNED_MASK == RISCV_HWPROBE_MISALIGNED_FAST ,
248
313
) ;
249
314
}
250
- if out[ 3 ] . key != -1 {
315
+ if out[ 2 ] . key != -1 {
251
316
enable_feature (
252
317
Feature :: unaligned_vector_mem,
253
- out[ 3 ] . value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST ,
318
+ out[ 2 ] . value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST ,
254
319
) ;
255
320
}
256
- // FIXME: should be enough with hwprobe only, but our code below checks e
257
- // unavailable in neither uapi/asm/hwprobe.h nor uapi/asm/hwcap.h.
258
- // https://github.com/torvalds/linux/blob/master/arch/riscv/include/uapi/asm/hwcap.h
259
- // return value;
260
321
}
261
322
262
- // FIXME: As said in the above FIXME, we currently alway checks auxv too.
263
- // // riscv_hwprobe requires Linux 6.4, so we fallback to auxv-based detection on
264
- // // old Linux kernel.
265
-
266
- let enable_feature = |value : & mut cache:: Initializer , feature, enable| {
267
- if enable {
268
- value. set ( feature as u32 ) ;
269
- }
270
- } ;
271
- let enable_features = |value : & mut cache:: Initializer , feature_slice : & [ Feature ] , enable| {
272
- if enable {
273
- for feature in feature_slice {
274
- value. set ( * feature as u32 ) ;
275
- }
276
- }
277
- } ;
278
-
279
- // The values are part of the platform-specific [asm/hwcap.h][hwcap]
280
- //
281
- // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/riscv/include/asm/hwcap.h
282
- //
283
- // Note that there is no need to check b'v' - b'a' here for the case where riscv_hwprobe is unsupported,
284
- // since both RISCV_HWPROBE_IMA_V and COMPAT_HWCAP_ISA_V are only supported on Linux 6.5+.
285
- // https://github.com/torvalds/linux/commit/162e4df137c1fea6557fda3e4cdf5dc6ca6d5510
286
- // https://github.com/torvalds/linux/commit/dc6667a4e7e36f283bcd0264a0be55adae4d6f86
287
- let auxv = auxvec:: auxv ( ) . expect ( "read auxvec" ) ; // should not fail on RISC-V platform
288
- #[ allow( clippy:: eq_op) ]
289
- enable_feature (
290
- & mut value,
291
- Feature :: a,
292
- bit:: test ( auxv. hwcap , ( b'a' - b'a' ) . into ( ) ) ,
293
- ) ;
294
- enable_feature (
295
- & mut value,
296
- Feature :: c,
297
- bit:: test ( auxv. hwcap , ( b'c' - b'a' ) . into ( ) ) ,
298
- ) ;
299
- enable_features (
300
- & mut value,
301
- & [ Feature :: d, Feature :: f, Feature :: zicsr] ,
302
- bit:: test ( auxv. hwcap , ( b'd' - b'a' ) . into ( ) ) ,
303
- ) ;
304
- enable_features (
305
- & mut value,
306
- & [ Feature :: f, Feature :: zicsr] ,
307
- bit:: test ( auxv. hwcap , ( b'f' - b'a' ) . into ( ) ) ,
308
- ) ;
309
- let has_i = bit:: test ( auxv. hwcap , ( b'i' - b'a' ) . into ( ) ) ;
310
- // If future RV128I is supported, implement with `enable_feature` here
311
- // Checking target_pointer_width instead of target_arch is incorrect since
312
- // there are RV64ILP32* ABIs.
313
- #[ cfg( target_arch = "riscv64" ) ]
314
- enable_feature ( & mut value, Feature :: rv64i, has_i) ;
315
- #[ cfg( target_arch = "riscv32" ) ]
316
- enable_feature ( & mut value, Feature :: rv32i, has_i) ;
317
- // FIXME: e is not exposed in any of asm/hwcap.h, uapi/asm/hwcap.h, uapi/asm/hwprobe.h
318
- #[ cfg( target_arch = "riscv32" ) ]
319
- enable_feature (
320
- & mut value,
321
- Feature :: rv32e,
322
- bit:: test ( auxv. hwcap , ( b'e' - b'a' ) . into ( ) ) ,
323
- ) ;
324
- enable_feature (
325
- & mut value,
326
- Feature :: m,
327
- bit:: test ( auxv. hwcap , ( b'm' - b'a' ) . into ( ) ) ,
328
- ) ;
329
-
330
323
value
331
324
}
0 commit comments