@@ -21,13 +21,13 @@ struct riscv_hwprobe {
2121#[ allow( non_upper_case_globals) ]
2222const __NR_riscv_hwprobe: libc:: c_long = 258 ;
2323
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;
2626
2727const 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;
3131const RISCV_HWPROBE_EXT_ZBA : u64 = 1 << 3 ;
3232const RISCV_HWPROBE_EXT_ZBB : u64 = 1 << 4 ;
3333const RISCV_HWPROBE_EXT_ZBS : u64 = 1 << 5 ;
@@ -62,11 +62,11 @@ const RISCV_HWPROBE_EXT_ZTSO: u64 = 1 << 33;
6262const RISCV_HWPROBE_EXT_ZACAS : u64 = 1 << 34 ;
6363// const RISCV_HWPROBE_EXT_ZICOND: u64 = 1 << 35;
6464const 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;
7070// const RISCV_HWPROBE_EXT_ZIMOP: u64 = 1 << 42;
7171// const RISCV_HWPROBE_EXT_ZCA: u64 = 1 << 43;
7272// const RISCV_HWPROBE_EXT_ZCB: u64 = 1 << 44;
@@ -113,11 +113,79 @@ fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool {
113113pub ( crate ) fn detect_features ( ) -> cache:: Initializer {
114114 let mut value = cache:: Initializer :: default ( ) ;
115115
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+
116188 let mut out = [
117- riscv_hwprobe {
118- key : RISCV_HWPROBE_KEY_BASE_BEHAVIOR ,
119- value : 0 ,
120- } ,
121189 riscv_hwprobe {
122190 key : RISCV_HWPROBE_KEY_IMA_EXT_0 ,
123191 value : 0 ,
@@ -138,23 +206,13 @@ pub(crate) fn detect_features() -> cache::Initializer {
138206 }
139207 } ;
140208 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);
158216 // enable_feature(Feature::zicboz, ima_ext_0 & RISCV_HWPROBE_EXT_ZICBOZ != 0);
159217 enable_feature ( Feature :: zfh, ima_ext_0 & RISCV_HWPROBE_EXT_ZFH != 0 ) ;
160218 enable_feature ( Feature :: zfhmin, ima_ext_0 & RISCV_HWPROBE_EXT_ZFHMIN != 0 ) ;
@@ -203,129 +261,64 @@ pub(crate) fn detect_features() -> cache::Initializer {
203261 enable_feature ( Feature :: zkn, zkn) ;
204262 // enable_feature(Feature::zk, zkn & zkr & zkt);
205263 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+ }
243308 }
244- if out[ 2 ] . key != -1 {
309+ if out[ 1 ] . key != -1 {
245310 enable_feature (
246311 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 ,
248313 ) ;
249314 }
250- if out[ 3 ] . key != -1 {
315+ if out[ 2 ] . key != -1 {
251316 enable_feature (
252317 Feature :: unaligned_vector_mem,
253- out[ 3 ] . value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST ,
318+ out[ 2 ] . value == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST ,
254319 ) ;
255320 }
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;
260321 }
261322
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-
330323 value
331324}
0 commit comments