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(uint64_t s[8], const void *, size_t); \
372a58b312SMartin Matuska static inline void N(uint64_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_sha512_transform_x64(uint64_t s[8], const void *, size_t);
522a58b312SMartin Matuska
532a58b312SMartin Matuska static inline void
tf_sha512_transform_x64(uint64_t s[8],const void * d,size_t b)542a58b312SMartin Matuska tf_sha512_transform_x64(uint64_t s[8], const void *d, size_t b)
552a58b312SMartin Matuska {
562a58b312SMartin Matuska zfs_sha512_transform_x64(s, d, b);
572a58b312SMartin Matuska }
582a58b312SMartin Matuska const sha512_ops_t sha512_x64_impl = {
592a58b312SMartin Matuska .is_supported = sha2_is_supported,
602a58b312SMartin Matuska .transform = tf_sha512_transform_x64,
612a58b312SMartin Matuska .name = "x64"
622a58b312SMartin Matuska };
632a58b312SMartin Matuska
642a58b312SMartin Matuska #if defined(HAVE_AVX)
sha2_have_avx(void)652a58b312SMartin Matuska static boolean_t sha2_have_avx(void)
662a58b312SMartin Matuska {
672a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx_available());
682a58b312SMartin Matuska }
692a58b312SMartin Matuska
702a58b312SMartin Matuska TF(zfs_sha512_transform_avx, tf_sha512_avx);
712a58b312SMartin Matuska const sha512_ops_t sha512_avx_impl = {
722a58b312SMartin Matuska .is_supported = sha2_have_avx,
732a58b312SMartin Matuska .transform = tf_sha512_avx,
742a58b312SMartin Matuska .name = "avx"
752a58b312SMartin Matuska };
762a58b312SMartin Matuska #endif
772a58b312SMartin Matuska
782a58b312SMartin Matuska #if defined(HAVE_AVX2)
sha2_have_avx2(void)792a58b312SMartin Matuska static boolean_t sha2_have_avx2(void)
802a58b312SMartin Matuska {
812a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx2_available());
822a58b312SMartin Matuska }
832a58b312SMartin Matuska
842a58b312SMartin Matuska TF(zfs_sha512_transform_avx2, tf_sha512_avx2);
852a58b312SMartin Matuska const sha512_ops_t sha512_avx2_impl = {
862a58b312SMartin Matuska .is_supported = sha2_have_avx2,
872a58b312SMartin Matuska .transform = tf_sha512_avx2,
882a58b312SMartin Matuska .name = "avx2"
892a58b312SMartin Matuska };
902a58b312SMartin Matuska #endif
912a58b312SMartin Matuska
923494f7c0SMartin Matuska #elif defined(__aarch64__) || defined(__arm__)
932a58b312SMartin Matuska extern void zfs_sha512_block_armv7(uint64_t s[8], const void *, size_t);
942a58b312SMartin Matuska const sha512_ops_t sha512_armv7_impl = {
952a58b312SMartin Matuska .is_supported = sha2_is_supported,
962a58b312SMartin Matuska .transform = zfs_sha512_block_armv7,
972a58b312SMartin Matuska .name = "armv7"
982a58b312SMartin Matuska };
992a58b312SMartin Matuska
1003494f7c0SMartin Matuska #if defined(__aarch64__)
sha512_have_armv8ce(void)1012a58b312SMartin Matuska static boolean_t sha512_have_armv8ce(void)
1022a58b312SMartin Matuska {
1032a58b312SMartin Matuska return (kfpu_allowed() && zfs_sha512_available());
1042a58b312SMartin Matuska }
1052a58b312SMartin Matuska
1062a58b312SMartin Matuska TF(zfs_sha512_block_armv8, tf_sha512_armv8ce);
1072a58b312SMartin Matuska const sha512_ops_t sha512_armv8_impl = {
1082a58b312SMartin Matuska .is_supported = sha512_have_armv8ce,
1092a58b312SMartin Matuska .transform = tf_sha512_armv8ce,
1102a58b312SMartin Matuska .name = "armv8-ce"
1112a58b312SMartin Matuska };
1123494f7c0SMartin Matuska #endif
1132a58b312SMartin Matuska
1143494f7c0SMartin Matuska #if defined(__arm__) && __ARM_ARCH > 6
sha512_have_neon(void)1152a58b312SMartin Matuska static boolean_t sha512_have_neon(void)
1162a58b312SMartin Matuska {
1172a58b312SMartin Matuska return (kfpu_allowed() && zfs_neon_available());
1182a58b312SMartin Matuska }
1192a58b312SMartin Matuska
1202a58b312SMartin Matuska TF(zfs_sha512_block_neon, tf_sha512_neon);
1212a58b312SMartin Matuska const sha512_ops_t sha512_neon_impl = {
1222a58b312SMartin Matuska .is_supported = sha512_have_neon,
1232a58b312SMartin Matuska .transform = tf_sha512_neon,
1242a58b312SMartin Matuska .name = "neon"
1252a58b312SMartin Matuska };
1263494f7c0SMartin Matuska #endif
1272a58b312SMartin Matuska
1282a58b312SMartin Matuska #elif defined(__PPC64__)
1292a58b312SMartin Matuska TF(zfs_sha512_ppc, tf_sha512_ppc);
1302a58b312SMartin Matuska const sha512_ops_t sha512_ppc_impl = {
1312a58b312SMartin Matuska .is_supported = sha2_is_supported,
1322a58b312SMartin Matuska .transform = tf_sha512_ppc,
1332a58b312SMartin Matuska .name = "ppc"
1342a58b312SMartin Matuska };
1352a58b312SMartin Matuska
sha512_have_isa207(void)1362a58b312SMartin Matuska static boolean_t sha512_have_isa207(void)
1372a58b312SMartin Matuska {
1382a58b312SMartin Matuska return (kfpu_allowed() && zfs_isa207_available());
1392a58b312SMartin Matuska }
1402a58b312SMartin Matuska
1412a58b312SMartin Matuska TF(zfs_sha512_power8, tf_sha512_power8);
1422a58b312SMartin Matuska const sha512_ops_t sha512_power8_impl = {
1432a58b312SMartin Matuska .is_supported = sha512_have_isa207,
1442a58b312SMartin Matuska .transform = tf_sha512_power8,
1452a58b312SMartin Matuska .name = "power8"
1462a58b312SMartin Matuska };
1472a58b312SMartin Matuska #endif /* __PPC64__ */
1482a58b312SMartin Matuska
1492a58b312SMartin Matuska /* the two generic ones */
1502a58b312SMartin Matuska extern const sha512_ops_t sha512_generic_impl;
1512a58b312SMartin Matuska
1522a58b312SMartin Matuska /* array with all sha512 implementations */
1532a58b312SMartin Matuska static const sha512_ops_t *const sha512_impls[] = {
1542a58b312SMartin Matuska &sha512_generic_impl,
1552a58b312SMartin Matuska #if defined(__x86_64)
1562a58b312SMartin Matuska &sha512_x64_impl,
1572a58b312SMartin Matuska #endif
1582a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX)
1592a58b312SMartin Matuska &sha512_avx_impl,
1602a58b312SMartin Matuska #endif
1612a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX2)
1622a58b312SMartin Matuska &sha512_avx2_impl,
1632a58b312SMartin Matuska #endif
1643494f7c0SMartin Matuska #if defined(__aarch64__) || defined(__arm__)
1652a58b312SMartin Matuska &sha512_armv7_impl,
1663494f7c0SMartin Matuska #if defined(__aarch64__)
1672a58b312SMartin Matuska &sha512_armv8_impl,
1682a58b312SMartin Matuska #endif
1692a58b312SMartin Matuska #if defined(__arm__) && __ARM_ARCH > 6
1702a58b312SMartin Matuska &sha512_neon_impl,
1712a58b312SMartin Matuska #endif
1723494f7c0SMartin Matuska #endif
1732a58b312SMartin Matuska #if defined(__PPC64__)
1742a58b312SMartin Matuska &sha512_ppc_impl,
1752a58b312SMartin Matuska &sha512_power8_impl,
1762a58b312SMartin Matuska #endif /* __PPC64__ */
1772a58b312SMartin Matuska };
1782a58b312SMartin Matuska
1792a58b312SMartin Matuska /* use the generic implementation functions */
1802a58b312SMartin Matuska #define IMPL_NAME "sha512"
1812a58b312SMartin Matuska #define IMPL_OPS_T sha512_ops_t
1822a58b312SMartin Matuska #define IMPL_ARRAY sha512_impls
1832a58b312SMartin Matuska #define IMPL_GET_OPS sha512_get_ops
1842a58b312SMartin Matuska #define ZFS_IMPL_OPS zfs_sha512_ops
1852a58b312SMartin Matuska #include <generic_impl.c>
1862a58b312SMartin Matuska
1872a58b312SMartin Matuska #ifdef _KERNEL
1882a58b312SMartin Matuska
1892a58b312SMartin Matuska #define IMPL_FMT(impl, i) (((impl) == (i)) ? "[%s] " : "%s ")
1902a58b312SMartin Matuska
1912a58b312SMartin Matuska #if defined(__linux__)
1922a58b312SMartin Matuska
1932a58b312SMartin Matuska static int
sha512_param_get(char * buffer,zfs_kernel_param_t * unused)1942a58b312SMartin Matuska sha512_param_get(char *buffer, zfs_kernel_param_t *unused)
1952a58b312SMartin Matuska {
1962a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
1972a58b312SMartin Matuska char *fmt;
1982a58b312SMartin Matuska int cnt = 0;
1992a58b312SMartin Matuska
2002a58b312SMartin Matuska /* cycling */
2012a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2022a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "cycle");
2032a58b312SMartin Matuska
2042a58b312SMartin Matuska /* list fastest */
2052a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2062a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "fastest");
2072a58b312SMartin Matuska
2082a58b312SMartin Matuska /* list all supported implementations */
2092a58b312SMartin Matuska generic_impl_init();
2102a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2112a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2122a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt,
2132a58b312SMartin Matuska generic_supp_impls[i]->name);
2142a58b312SMartin Matuska }
2152a58b312SMartin Matuska
2162a58b312SMartin Matuska return (cnt);
2172a58b312SMartin Matuska }
2182a58b312SMartin Matuska
2192a58b312SMartin Matuska static int
sha512_param_set(const char * val,zfs_kernel_param_t * unused)2202a58b312SMartin Matuska sha512_param_set(const char *val, zfs_kernel_param_t *unused)
2212a58b312SMartin Matuska {
2222a58b312SMartin Matuska (void) unused;
2232a58b312SMartin Matuska return (generic_impl_setname(val));
2242a58b312SMartin Matuska }
2252a58b312SMartin Matuska
2262a58b312SMartin Matuska #elif defined(__FreeBSD__)
2272a58b312SMartin Matuska
2282a58b312SMartin Matuska #include <sys/sbuf.h>
2292a58b312SMartin Matuska
2302a58b312SMartin Matuska static int
sha512_param(ZFS_MODULE_PARAM_ARGS)2312a58b312SMartin Matuska sha512_param(ZFS_MODULE_PARAM_ARGS)
2322a58b312SMartin Matuska {
2332a58b312SMartin Matuska int err;
2342a58b312SMartin Matuska
2352a58b312SMartin Matuska generic_impl_init();
2362a58b312SMartin Matuska if (req->newptr == NULL) {
2372a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
2382a58b312SMartin Matuska const int init_buflen = 64;
2392a58b312SMartin Matuska const char *fmt;
2402a58b312SMartin Matuska struct sbuf *s;
2412a58b312SMartin Matuska
2422a58b312SMartin Matuska s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
2432a58b312SMartin Matuska
2442a58b312SMartin Matuska /* cycling */
2452a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2462a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "cycle");
2472a58b312SMartin Matuska
2482a58b312SMartin Matuska /* list fastest */
2492a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2502a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "fastest");
2512a58b312SMartin Matuska
2522a58b312SMartin Matuska /* list all supported implementations */
2532a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2542a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2552a58b312SMartin Matuska (void) sbuf_printf(s, fmt, generic_supp_impls[i]->name);
2562a58b312SMartin Matuska }
2572a58b312SMartin Matuska
2582a58b312SMartin Matuska err = sbuf_finish(s);
2592a58b312SMartin Matuska sbuf_delete(s);
2602a58b312SMartin Matuska
2612a58b312SMartin Matuska return (err);
2622a58b312SMartin Matuska }
2632a58b312SMartin Matuska
2642a58b312SMartin Matuska /* we got module parameter */
2652a58b312SMartin Matuska char buf[16];
2662a58b312SMartin Matuska
2672a58b312SMartin Matuska err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
2682a58b312SMartin Matuska if (err) {
2692a58b312SMartin Matuska return (err);
2702a58b312SMartin Matuska }
2712a58b312SMartin Matuska
2722a58b312SMartin Matuska return (-generic_impl_setname(buf));
2732a58b312SMartin Matuska }
2742a58b312SMartin Matuska #endif
2752a58b312SMartin Matuska
2762a58b312SMartin Matuska #undef IMPL_FMT
2772a58b312SMartin Matuska
2782a58b312SMartin Matuska ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, sha512_impl,
2792a58b312SMartin Matuska sha512_param_set, sha512_param_get, ZMOD_RW, \
2802a58b312SMartin Matuska "Select SHA512 implementation.");
2812a58b312SMartin Matuska #endif
2822a58b312SMartin Matuska
2832a58b312SMartin Matuska #undef TF
284