riscv: use hwprobe syscall for capability detection
authorHongren Zheng <i@zenithal.me>
Wed, 17 Apr 2024 09:21:53 +0000 (17:21 +0800)
committerTomas Mraz <tomas@openssl.org>
Thu, 9 May 2024 08:50:42 +0000 (10:50 +0200)
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24172)

crypto/riscvcap.c
include/crypto/riscv_arch.def
include/crypto/riscv_arch.h

index db75c21b2895c34cd98166535ef484bd5d87b616..7683bf0fb86c013e660afb1a9ed9cd0dd2c480dc 100644 (file)
 #define OPENSSL_RISCVCAP_IMPL
 #include "crypto/riscv_arch.h"
 
+#ifdef OSSL_RISCV_HWPROBE
+# include <unistd.h>
+# include <sys/syscall.h>
+# include <asm/hwprobe.h>
+#endif
+
 extern size_t riscv_vlen_asm(void);
 
 static void parse_env(const char *envstr);
@@ -71,6 +77,38 @@ static void parse_env(const char *envstr)
     }
 }
 
+#ifdef OSSL_RISCV_HWPROBE
+static long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
+                          size_t cpu_count, unsigned long *cpus,
+                          unsigned int flags)
+{
+    return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags);
+}
+
+static void hwprobe_to_cap()
+{
+    long ret;
+    struct riscv_hwprobe pairs[OSSL_RISCV_HWPROBE_PAIR_COUNT] = {
+        OSSL_RISCV_HWPROBE_PAIR_CONTENT
+    };
+
+    ret = riscv_hwprobe(pairs, OSSL_RISCV_HWPROBE_PAIR_COUNT, 0, NULL, 0);
+    /* if hwprobe syscall does not exist, ret would be -ENOSYS */
+    if (ret == 0) {
+        for (size_t i = 0; i < kRISCVNumCaps; ++i) {
+            for (size_t j = 0; j != OSSL_RISCV_HWPROBE_PAIR_COUNT; ++j) {
+                if (pairs[j].key == RISCV_capabilities[i].hwprobe_key
+                        && (pairs[j].value & RISCV_capabilities[i].hwprobe_value)
+                           != 0)
+                    /* Match, set relevant bit in OPENSSL_riscvcap_P[] */
+                    OPENSSL_riscvcap_P[RISCV_capabilities[i].index] |=
+                        (1 << RISCV_capabilities[i].bit_offset);
+            }
+        }
+    }
+}
+#endif /* OSSL_RISCV_HWPROBE */
+
 size_t riscv_vlen(void)
 {
     return vlen;
@@ -91,6 +129,11 @@ void OPENSSL_cpuid_setup(void)
     if ((e = getenv("OPENSSL_riscvcap"))) {
         parse_env(e);
     }
+#ifdef OSSL_RISCV_HWPROBE
+    else {
+        hwprobe_to_cap();
+    }
+#endif
 
     if (RISCV_HAS_V()) {
         vlen = riscv_vlen_asm();
index 70b0647ae2aed98822a19eff5419c16a0eea103b..23d46b4a8b1fa9512af3f5380135b32c9e0faff8 100644 (file)
  * second argument as the index in the array where the capability will be stored
  * and third argument as the index of the bit to be used to encode the
  * capability.
- * RISCV_DEFINE_CAP(EXTENSION NAME, array index, bit index) */
+ *
+ * The fourth and the fifth arguments are copied from linux header asm/hwprobe.h.
+ * Directly coping values instead of macro names comes from the fact
+ * that an old version may lack definition of some macro.
+ * When there is no hwprobe key/value pair for a capability, the key is set to -1
+ * and the value is set to 0, as when the hwprobe syscall returns a key of -1,
+ * the value is set to 0 and the corresponding capability would not be enabled.
+ *
+ * RISCV_DEFINE_CAP(EXTENSION NAME, array index, bit index, hwprobe key, hwprobe value) */
 
-RISCV_DEFINE_CAP(ZBA, 0, 0)
-RISCV_DEFINE_CAP(ZBB, 0, 1)
-RISCV_DEFINE_CAP(ZBC, 0, 2)
-RISCV_DEFINE_CAP(ZBS, 0, 3)
-RISCV_DEFINE_CAP(ZBKB, 0, 4)
-RISCV_DEFINE_CAP(ZBKC, 0, 5)
-RISCV_DEFINE_CAP(ZBKX, 0, 6)
-RISCV_DEFINE_CAP(ZKND, 0, 7)
-RISCV_DEFINE_CAP(ZKNE, 0, 8)
-RISCV_DEFINE_CAP(ZKNH, 0, 9)
-RISCV_DEFINE_CAP(ZKSED, 0, 10)
-RISCV_DEFINE_CAP(ZKSH, 0, 11)
-RISCV_DEFINE_CAP(ZKR, 0, 12)
-RISCV_DEFINE_CAP(ZKT, 0, 13)
-RISCV_DEFINE_CAP(V, 0, 14)
-RISCV_DEFINE_CAP(ZVBB, 0, 15)
-RISCV_DEFINE_CAP(ZVBC, 0, 16)
-RISCV_DEFINE_CAP(ZVKB, 0, 17)
-RISCV_DEFINE_CAP(ZVKG, 0, 18)
-RISCV_DEFINE_CAP(ZVKNED, 0, 19)
-RISCV_DEFINE_CAP(ZVKNHA, 0, 20)
-RISCV_DEFINE_CAP(ZVKNHB, 0, 21)
-RISCV_DEFINE_CAP(ZVKSED, 0, 22)
-RISCV_DEFINE_CAP(ZVKSH, 0, 23)
+RISCV_DEFINE_CAP(ZBA, 0, 0, 4, (1 << 3))
+RISCV_DEFINE_CAP(ZBB, 0, 1, 4, (1 << 4))
+RISCV_DEFINE_CAP(ZBC, 0, 2, 4, (1 << 7))
+RISCV_DEFINE_CAP(ZBS, 0, 3, 4, (1 << 5))
+RISCV_DEFINE_CAP(ZBKB, 0, 4, 4, (1 << 8))
+RISCV_DEFINE_CAP(ZBKC, 0, 5, 4, (1 << 9))
+RISCV_DEFINE_CAP(ZBKX, 0, 6, 4, (1 << 10))
+RISCV_DEFINE_CAP(ZKND, 0, 7, 4, (1 << 11))
+RISCV_DEFINE_CAP(ZKNE, 0, 8, 4, (1 << 12))
+RISCV_DEFINE_CAP(ZKNH, 0, 9, 4, (1 << 13))
+RISCV_DEFINE_CAP(ZKSED, 0, 10, 4, (1 << 14))
+RISCV_DEFINE_CAP(ZKSH, 0, 11, 4, (1 << 15))
+RISCV_DEFINE_CAP(ZKR, 0, 12, -1, 0)
+RISCV_DEFINE_CAP(ZKT, 0, 13, 4, (1 << 16))
+RISCV_DEFINE_CAP(V, 0, 14, 4, (1 << 2))
+RISCV_DEFINE_CAP(ZVBB, 0, 15, 4, (1 << 17))
+RISCV_DEFINE_CAP(ZVBC, 0, 16, 4, (1 << 18))
+RISCV_DEFINE_CAP(ZVKB, 0, 17, 4, (1 << 19))
+RISCV_DEFINE_CAP(ZVKG, 0, 18, 4, (1 << 20))
+RISCV_DEFINE_CAP(ZVKNED, 0, 19, 4, (1 << 21))
+RISCV_DEFINE_CAP(ZVKNHA, 0, 20, 4, (1 << 22))
+RISCV_DEFINE_CAP(ZVKNHB, 0, 21, 4, (1 << 23))
+RISCV_DEFINE_CAP(ZVKSED, 0, 22, 4, (1 << 24))
+RISCV_DEFINE_CAP(ZVKSH, 0, 23, 4, (1 << 25))
 
 /*
  * In the future ...
- * RISCV_DEFINE_CAP(ZFOO, 0, 31)
- * RISCV_DEFINE_CAP(ZBAR, 1, 0)
+ * RISCV_DEFINE_CAP(ZFOO, 0, 31, ..., ...)
+ * RISCV_DEFINE_CAP(ZBAR, 1, 0, ..., ...)
  * ... and so on.
  */
 
index 6950137f451800cdec9825c8e24024c13d72f7e7..6712cdc6598c03b288d1f40c99f7ed0c6336bdb2 100644 (file)
 # include <ctype.h>
 # include <stdint.h>
 
-# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1
+# if defined(OPENSSL_SYS_LINUX) && !defined(FIPS_MODULE)
+#  if __has_include(<asm/hwprobe.h>)
+#   define OSSL_RISCV_HWPROBE
+#  endif
+# endif
+
+# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX, \
+                          HWPROBE_KEY, HWPROBE_VALUE) +1
 extern uint32_t OPENSSL_riscvcap_P[ ((
 # include "riscv_arch.def"
 ) + sizeof(uint32_t) - 1) / sizeof(uint32_t) ];
 
 # ifdef OPENSSL_RISCVCAP_IMPL
-#  define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1
+#  define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX, \
+                           HWPROBE_KEY, HWPROBE_VALUE) +1
 uint32_t OPENSSL_riscvcap_P[ ((
 #  include "riscv_arch.def"
 ) + sizeof(uint32_t) - 1) / sizeof(uint32_t) ];
 # endif
 
-# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX)                   \
+# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX,                   \
+                          HWPROBE_KEY, HWPROBE_VALUE)               \
     static inline int RISCV_HAS_##NAME(void)                        \
     {                                                               \
         return (OPENSSL_riscvcap_P[INDEX] & (1 << BIT_INDEX)) != 0; \
@@ -36,26 +45,50 @@ struct RISCV_capability_s {
     const char *name;
     size_t index;
     size_t bit_offset;
+# ifdef OSSL_RISCV_HWPROBE
+    int32_t hwprobe_key;
+    uint64_t hwprobe_value;
+# endif
 };
 
-# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1
+# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX, \
+                          OSSL_RISCV_HWPROBE_KEY, OSSL_RISCV_HWPROBE_VALUE) +1
 extern const struct RISCV_capability_s RISCV_capabilities[
 # include "riscv_arch.def"
 ];
 
 # ifdef OPENSSL_RISCVCAP_IMPL
-#  define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) \
+#  ifdef OSSL_RISCV_HWPROBE
+#  define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX,     \
+                           HWPROBE_KEY, HWPROBE_VALUE) \
+    { #NAME, INDEX, BIT_INDEX, HWPROBE_KEY, HWPROBE_VALUE },
+#  else
+#  define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX,     \
+                           HWPROBE_KEY, HWPROBE_VALUE) \
     { #NAME, INDEX, BIT_INDEX },
+#  endif
 const struct RISCV_capability_s RISCV_capabilities[] = {
 #  include "riscv_arch.def"
 };
 # endif
 
-# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX) +1
+# define RISCV_DEFINE_CAP(NAME, INDEX, BIT_INDEX, \
+                          HWPROBE_KEY, HWPROBE_VALUE) +1
 static const size_t kRISCVNumCaps =
 # include "riscv_arch.def"
 ;
 
+# ifdef OSSL_RISCV_HWPROBE
+/*
+ * Content is an array of { hwprobe_key, 0 } where
+ * hwprobe_key is copied from asm/hwprobe.h.
+ * It should be updated along with riscv_arch.def.
+ */
+#  define OSSL_RISCV_HWPROBE_PAIR_COUNT 1
+#  define OSSL_RISCV_HWPROBE_PAIR_CONTENT \
+   { 4, 0 },
+# endif
+
 /* Extension combination tests. */
 #define RISCV_HAS_ZBB_AND_ZBC() (RISCV_HAS_ZBB() && RISCV_HAS_ZBC())
 #define RISCV_HAS_ZBKB_AND_ZKND_AND_ZKNE() (RISCV_HAS_ZBKB() && RISCV_HAS_ZKND() && RISCV_HAS_ZKNE())