1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
22a58b312SMartin Matuska /*
32a58b312SMartin Matuska * CDDL HEADER START
42a58b312SMartin Matuska *
52a58b312SMartin Matuska * The contents of this file are subject to the terms of the
62a58b312SMartin Matuska * Common Development and Distribution License (the "License").
72a58b312SMartin Matuska * You may not use this file except in compliance with the License.
82a58b312SMartin Matuska *
92a58b312SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
102a58b312SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
112a58b312SMartin Matuska * See the License for the specific language governing permissions
122a58b312SMartin Matuska * and limitations under the License.
132a58b312SMartin Matuska *
142a58b312SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
152a58b312SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
162a58b312SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
172a58b312SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
182a58b312SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
192a58b312SMartin Matuska *
202a58b312SMartin Matuska * CDDL HEADER END
212a58b312SMartin Matuska */
222a58b312SMartin Matuska
232a58b312SMartin Matuska /*
242a58b312SMartin Matuska * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
252a58b312SMartin Matuska */
262a58b312SMartin Matuska
272a58b312SMartin Matuska #include <sys/simd.h>
282a58b312SMartin Matuska #include <sys/zfs_context.h>
292a58b312SMartin Matuska #include <sys/zfs_impl.h>
302a58b312SMartin Matuska #include <sys/sha2.h>
312a58b312SMartin Matuska
322a58b312SMartin Matuska #include <sha2/sha2_impl.h>
332a58b312SMartin Matuska #include <sys/asm_linkage.h>
342a58b312SMartin Matuska
352a58b312SMartin Matuska #define TF(E, N) \
362a58b312SMartin Matuska extern void ASMABI E(uint32_t s[8], const void *, size_t); \
372a58b312SMartin Matuska static inline void N(uint32_t s[8], const void *d, size_t b) { \
382a58b312SMartin Matuska kfpu_begin(); E(s, d, b); kfpu_end(); \
392a58b312SMartin Matuska }
402a58b312SMartin Matuska
412a58b312SMartin Matuska /* some implementation is always okay */
sha2_is_supported(void)422a58b312SMartin Matuska static inline boolean_t sha2_is_supported(void)
432a58b312SMartin Matuska {
442a58b312SMartin Matuska return (B_TRUE);
452a58b312SMartin Matuska }
462a58b312SMartin Matuska
472a58b312SMartin Matuska #if defined(__x86_64)
482a58b312SMartin Matuska
492a58b312SMartin Matuska /* Users of ASMABI requires all calls to be from wrappers */
502a58b312SMartin Matuska extern void ASMABI
512a58b312SMartin Matuska zfs_sha256_transform_x64(uint32_t s[8], const void *, size_t);
522a58b312SMartin Matuska
532a58b312SMartin Matuska static inline void
tf_sha256_transform_x64(uint32_t s[8],const void * d,size_t b)542a58b312SMartin Matuska tf_sha256_transform_x64(uint32_t s[8], const void *d, size_t b)
552a58b312SMartin Matuska {
562a58b312SMartin Matuska zfs_sha256_transform_x64(s, d, b);
572a58b312SMartin Matuska }
582a58b312SMartin Matuska
592a58b312SMartin Matuska const sha256_ops_t sha256_x64_impl = {
602a58b312SMartin Matuska .is_supported = sha2_is_supported,
612a58b312SMartin Matuska .transform = tf_sha256_transform_x64,
622a58b312SMartin Matuska .name = "x64"
632a58b312SMartin Matuska };
642a58b312SMartin Matuska
652a58b312SMartin Matuska #if defined(HAVE_SSSE3)
sha2_have_ssse3(void)662a58b312SMartin Matuska static boolean_t sha2_have_ssse3(void)
672a58b312SMartin Matuska {
682a58b312SMartin Matuska return (kfpu_allowed() && zfs_ssse3_available());
692a58b312SMartin Matuska }
702a58b312SMartin Matuska
712a58b312SMartin Matuska TF(zfs_sha256_transform_ssse3, tf_sha256_ssse3);
722a58b312SMartin Matuska const sha256_ops_t sha256_ssse3_impl = {
732a58b312SMartin Matuska .is_supported = sha2_have_ssse3,
742a58b312SMartin Matuska .transform = tf_sha256_ssse3,
752a58b312SMartin Matuska .name = "ssse3"
762a58b312SMartin Matuska };
772a58b312SMartin Matuska #endif
782a58b312SMartin Matuska
792a58b312SMartin Matuska #if defined(HAVE_AVX)
sha2_have_avx(void)802a58b312SMartin Matuska static boolean_t sha2_have_avx(void)
812a58b312SMartin Matuska {
822a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx_available());
832a58b312SMartin Matuska }
842a58b312SMartin Matuska
852a58b312SMartin Matuska TF(zfs_sha256_transform_avx, tf_sha256_avx);
862a58b312SMartin Matuska const sha256_ops_t sha256_avx_impl = {
872a58b312SMartin Matuska .is_supported = sha2_have_avx,
882a58b312SMartin Matuska .transform = tf_sha256_avx,
892a58b312SMartin Matuska .name = "avx"
902a58b312SMartin Matuska };
912a58b312SMartin Matuska #endif
922a58b312SMartin Matuska
932a58b312SMartin Matuska #if defined(HAVE_AVX2)
sha2_have_avx2(void)942a58b312SMartin Matuska static boolean_t sha2_have_avx2(void)
952a58b312SMartin Matuska {
962a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx2_available());
972a58b312SMartin Matuska }
982a58b312SMartin Matuska
992a58b312SMartin Matuska TF(zfs_sha256_transform_avx2, tf_sha256_avx2);
1002a58b312SMartin Matuska const sha256_ops_t sha256_avx2_impl = {
1012a58b312SMartin Matuska .is_supported = sha2_have_avx2,
1022a58b312SMartin Matuska .transform = tf_sha256_avx2,
1032a58b312SMartin Matuska .name = "avx2"
1042a58b312SMartin Matuska };
1052a58b312SMartin Matuska #endif
1062a58b312SMartin Matuska
1072a58b312SMartin Matuska #if defined(HAVE_SSE4_1)
sha2_have_shani(void)1082a58b312SMartin Matuska static boolean_t sha2_have_shani(void)
1092a58b312SMartin Matuska {
1102a58b312SMartin Matuska return (kfpu_allowed() && zfs_sse4_1_available() && \
1112a58b312SMartin Matuska zfs_shani_available());
1122a58b312SMartin Matuska }
1132a58b312SMartin Matuska
1142a58b312SMartin Matuska TF(zfs_sha256_transform_shani, tf_sha256_shani);
1152a58b312SMartin Matuska const sha256_ops_t sha256_shani_impl = {
1162a58b312SMartin Matuska .is_supported = sha2_have_shani,
1172a58b312SMartin Matuska .transform = tf_sha256_shani,
1182a58b312SMartin Matuska .name = "shani"
1192a58b312SMartin Matuska };
1202a58b312SMartin Matuska #endif
1212a58b312SMartin Matuska
1223494f7c0SMartin Matuska #elif defined(__aarch64__) || defined(__arm__)
1233494f7c0SMartin Matuska extern void zfs_sha256_block_armv7(uint32_t s[8], const void *, size_t);
1243494f7c0SMartin Matuska const sha256_ops_t sha256_armv7_impl = {
1253494f7c0SMartin Matuska .is_supported = sha2_is_supported,
1263494f7c0SMartin Matuska .transform = zfs_sha256_block_armv7,
1273494f7c0SMartin Matuska .name = "armv7"
1283494f7c0SMartin Matuska };
1293494f7c0SMartin Matuska
1303494f7c0SMartin Matuska #if __ARM_ARCH > 6
sha256_have_neon(void)1312a58b312SMartin Matuska static boolean_t sha256_have_neon(void)
1322a58b312SMartin Matuska {
1332a58b312SMartin Matuska return (kfpu_allowed() && zfs_neon_available());
1342a58b312SMartin Matuska }
1352a58b312SMartin Matuska
sha256_have_armv8ce(void)1362a58b312SMartin Matuska static boolean_t sha256_have_armv8ce(void)
1372a58b312SMartin Matuska {
1382a58b312SMartin Matuska return (kfpu_allowed() && zfs_sha256_available());
1392a58b312SMartin Matuska }
1402a58b312SMartin Matuska
1412a58b312SMartin Matuska TF(zfs_sha256_block_neon, tf_sha256_neon);
1422a58b312SMartin Matuska const sha256_ops_t sha256_neon_impl = {
1432a58b312SMartin Matuska .is_supported = sha256_have_neon,
1442a58b312SMartin Matuska .transform = tf_sha256_neon,
1452a58b312SMartin Matuska .name = "neon"
1462a58b312SMartin Matuska };
1472a58b312SMartin Matuska
1482a58b312SMartin Matuska TF(zfs_sha256_block_armv8, tf_sha256_armv8ce);
1492a58b312SMartin Matuska const sha256_ops_t sha256_armv8_impl = {
1502a58b312SMartin Matuska .is_supported = sha256_have_armv8ce,
1512a58b312SMartin Matuska .transform = tf_sha256_armv8ce,
1522a58b312SMartin Matuska .name = "armv8-ce"
1532a58b312SMartin Matuska };
1543494f7c0SMartin Matuska #endif
1552a58b312SMartin Matuska
1562a58b312SMartin Matuska #elif defined(__PPC64__)
sha256_have_isa207(void)1572a58b312SMartin Matuska static boolean_t sha256_have_isa207(void)
1582a58b312SMartin Matuska {
1592a58b312SMartin Matuska return (kfpu_allowed() && zfs_isa207_available());
1602a58b312SMartin Matuska }
1612a58b312SMartin Matuska
1622a58b312SMartin Matuska TF(zfs_sha256_ppc, tf_sha256_ppc);
1632a58b312SMartin Matuska const sha256_ops_t sha256_ppc_impl = {
1642a58b312SMartin Matuska .is_supported = sha2_is_supported,
1652a58b312SMartin Matuska .transform = tf_sha256_ppc,
1662a58b312SMartin Matuska .name = "ppc"
1672a58b312SMartin Matuska };
1682a58b312SMartin Matuska
1692a58b312SMartin Matuska TF(zfs_sha256_power8, tf_sha256_power8);
1702a58b312SMartin Matuska const sha256_ops_t sha256_power8_impl = {
1712a58b312SMartin Matuska .is_supported = sha256_have_isa207,
1722a58b312SMartin Matuska .transform = tf_sha256_power8,
1732a58b312SMartin Matuska .name = "power8"
1742a58b312SMartin Matuska };
1752a58b312SMartin Matuska #endif /* __PPC64__ */
1762a58b312SMartin Matuska
1772a58b312SMartin Matuska /* the two generic ones */
1782a58b312SMartin Matuska extern const sha256_ops_t sha256_generic_impl;
1792a58b312SMartin Matuska
1802a58b312SMartin Matuska /* array with all sha256 implementations */
1812a58b312SMartin Matuska static const sha256_ops_t *const sha256_impls[] = {
1822a58b312SMartin Matuska &sha256_generic_impl,
1832a58b312SMartin Matuska #if defined(__x86_64)
1842a58b312SMartin Matuska &sha256_x64_impl,
1852a58b312SMartin Matuska #endif
1862a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSSE3)
1872a58b312SMartin Matuska &sha256_ssse3_impl,
1882a58b312SMartin Matuska #endif
1892a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX)
1902a58b312SMartin Matuska &sha256_avx_impl,
1912a58b312SMartin Matuska #endif
1922a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX2)
1932a58b312SMartin Matuska &sha256_avx2_impl,
1942a58b312SMartin Matuska #endif
1952a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSE4_1)
1962a58b312SMartin Matuska &sha256_shani_impl,
1972a58b312SMartin Matuska #endif
1983494f7c0SMartin Matuska #if defined(__aarch64__) || defined(__arm__)
1992a58b312SMartin Matuska &sha256_armv7_impl,
2003494f7c0SMartin Matuska #if __ARM_ARCH > 6
2012a58b312SMartin Matuska &sha256_neon_impl,
2022a58b312SMartin Matuska &sha256_armv8_impl,
2032a58b312SMartin Matuska #endif
2043494f7c0SMartin Matuska #endif
2052a58b312SMartin Matuska #if defined(__PPC64__)
2062a58b312SMartin Matuska &sha256_ppc_impl,
2072a58b312SMartin Matuska &sha256_power8_impl,
2082a58b312SMartin Matuska #endif /* __PPC64__ */
2092a58b312SMartin Matuska };
2102a58b312SMartin Matuska
2112a58b312SMartin Matuska /* use the generic implementation functions */
2122a58b312SMartin Matuska #define IMPL_NAME "sha256"
2132a58b312SMartin Matuska #define IMPL_OPS_T sha256_ops_t
2142a58b312SMartin Matuska #define IMPL_ARRAY sha256_impls
2152a58b312SMartin Matuska #define IMPL_GET_OPS sha256_get_ops
2162a58b312SMartin Matuska #define ZFS_IMPL_OPS zfs_sha256_ops
2172a58b312SMartin Matuska #include <generic_impl.c>
2182a58b312SMartin Matuska
2192a58b312SMartin Matuska #ifdef _KERNEL
2202a58b312SMartin Matuska
2212a58b312SMartin Matuska #define IMPL_FMT(impl, i) (((impl) == (i)) ? "[%s] " : "%s ")
2222a58b312SMartin Matuska
2232a58b312SMartin Matuska #if defined(__linux__)
2242a58b312SMartin Matuska
2252a58b312SMartin Matuska static int
sha256_param_get(char * buffer,zfs_kernel_param_t * unused)2262a58b312SMartin Matuska sha256_param_get(char *buffer, zfs_kernel_param_t *unused)
2272a58b312SMartin Matuska {
2282a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
2292a58b312SMartin Matuska char *fmt;
2302a58b312SMartin Matuska int cnt = 0;
2312a58b312SMartin Matuska
2322a58b312SMartin Matuska /* cycling */
2332a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2342a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "cycle");
2352a58b312SMartin Matuska
2362a58b312SMartin Matuska /* list fastest */
2372a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2382a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "fastest");
2392a58b312SMartin Matuska
2402a58b312SMartin Matuska /* list all supported implementations */
2412a58b312SMartin Matuska generic_impl_init();
2422a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2432a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2442a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt,
2452a58b312SMartin Matuska generic_supp_impls[i]->name);
2462a58b312SMartin Matuska }
2472a58b312SMartin Matuska
2482a58b312SMartin Matuska return (cnt);
2492a58b312SMartin Matuska }
2502a58b312SMartin Matuska
2512a58b312SMartin Matuska static int
sha256_param_set(const char * val,zfs_kernel_param_t * unused)2522a58b312SMartin Matuska sha256_param_set(const char *val, zfs_kernel_param_t *unused)
2532a58b312SMartin Matuska {
2542a58b312SMartin Matuska (void) unused;
2552a58b312SMartin Matuska return (generic_impl_setname(val));
2562a58b312SMartin Matuska }
2572a58b312SMartin Matuska
2582a58b312SMartin Matuska #elif defined(__FreeBSD__)
2592a58b312SMartin Matuska
2602a58b312SMartin Matuska #include <sys/sbuf.h>
2612a58b312SMartin Matuska
2622a58b312SMartin Matuska static int
sha256_param(ZFS_MODULE_PARAM_ARGS)2632a58b312SMartin Matuska sha256_param(ZFS_MODULE_PARAM_ARGS)
2642a58b312SMartin Matuska {
2652a58b312SMartin Matuska int err;
2662a58b312SMartin Matuska
2672a58b312SMartin Matuska generic_impl_init();
2682a58b312SMartin Matuska if (req->newptr == NULL) {
2692a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
2702a58b312SMartin Matuska const int init_buflen = 64;
2712a58b312SMartin Matuska const char *fmt;
2722a58b312SMartin Matuska struct sbuf *s;
2732a58b312SMartin Matuska
2742a58b312SMartin Matuska s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
2752a58b312SMartin Matuska
2762a58b312SMartin Matuska /* cycling */
2772a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2782a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "cycle");
2792a58b312SMartin Matuska
2802a58b312SMartin Matuska /* list fastest */
2812a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2822a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "fastest");
2832a58b312SMartin Matuska
2842a58b312SMartin Matuska /* list all supported implementations */
2852a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2862a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2872a58b312SMartin Matuska (void) sbuf_printf(s, fmt, generic_supp_impls[i]->name);
2882a58b312SMartin Matuska }
2892a58b312SMartin Matuska
2902a58b312SMartin Matuska err = sbuf_finish(s);
2912a58b312SMartin Matuska sbuf_delete(s);
2922a58b312SMartin Matuska
2932a58b312SMartin Matuska return (err);
2942a58b312SMartin Matuska }
2952a58b312SMartin Matuska
2962a58b312SMartin Matuska char buf[16];
2972a58b312SMartin Matuska
2982a58b312SMartin Matuska err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
2992a58b312SMartin Matuska if (err) {
3002a58b312SMartin Matuska return (err);
3012a58b312SMartin Matuska }
3022a58b312SMartin Matuska
3032a58b312SMartin Matuska return (-generic_impl_setname(buf));
3042a58b312SMartin Matuska }
3052a58b312SMartin Matuska #endif
3062a58b312SMartin Matuska
3072a58b312SMartin Matuska #undef IMPL_FMT
3082a58b312SMartin Matuska
3092a58b312SMartin Matuska ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, sha256_impl,
3102a58b312SMartin Matuska sha256_param_set, sha256_param_get, ZMOD_RW, \
3112a58b312SMartin Matuska "Select SHA256 implementation.");
3122a58b312SMartin Matuska #endif
3132a58b312SMartin Matuska
3142a58b312SMartin Matuska #undef TF
315