12a58b312SMartin Matuska /*
22a58b312SMartin Matuska * CDDL HEADER START
32a58b312SMartin Matuska *
42a58b312SMartin Matuska * The contents of this file are subject to the terms of the
52a58b312SMartin Matuska * Common Development and Distribution License (the "License").
62a58b312SMartin Matuska * You may not use this file except in compliance with the License.
72a58b312SMartin Matuska *
82a58b312SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92a58b312SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
102a58b312SMartin Matuska * See the License for the specific language governing permissions
112a58b312SMartin Matuska * and limitations under the License.
122a58b312SMartin Matuska *
132a58b312SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
142a58b312SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152a58b312SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
162a58b312SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
172a58b312SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
182a58b312SMartin Matuska *
192a58b312SMartin Matuska * CDDL HEADER END
202a58b312SMartin Matuska */
212a58b312SMartin Matuska
222a58b312SMartin Matuska /*
232a58b312SMartin Matuska * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
242a58b312SMartin Matuska */
252a58b312SMartin Matuska
262a58b312SMartin Matuska #include <sys/simd.h>
272a58b312SMartin Matuska #include <sys/zfs_context.h>
282a58b312SMartin Matuska #include <sys/zfs_impl.h>
292a58b312SMartin Matuska #include <sys/sha2.h>
302a58b312SMartin Matuska
312a58b312SMartin Matuska #include <sha2/sha2_impl.h>
322a58b312SMartin Matuska #include <sys/asm_linkage.h>
332a58b312SMartin Matuska
342a58b312SMartin Matuska #define TF(E, N) \
352a58b312SMartin Matuska extern void ASMABI E(uint64_t s[8], const void *, size_t); \
362a58b312SMartin Matuska static inline void N(uint64_t s[8], const void *d, size_t b) { \
372a58b312SMartin Matuska kfpu_begin(); E(s, d, b); kfpu_end(); \
382a58b312SMartin Matuska }
392a58b312SMartin Matuska
402a58b312SMartin Matuska /* some implementation is always okay */
sha2_is_supported(void)412a58b312SMartin Matuska static inline boolean_t sha2_is_supported(void)
422a58b312SMartin Matuska {
432a58b312SMartin Matuska return (B_TRUE);
442a58b312SMartin Matuska }
452a58b312SMartin Matuska
462a58b312SMartin Matuska #if defined(__x86_64)
472a58b312SMartin Matuska
482a58b312SMartin Matuska /* Users of ASMABI requires all calls to be from wrappers */
492a58b312SMartin Matuska extern void ASMABI
502a58b312SMartin Matuska zfs_sha512_transform_x64(uint64_t s[8], const void *, size_t);
512a58b312SMartin Matuska
522a58b312SMartin Matuska static inline void
tf_sha512_transform_x64(uint64_t s[8],const void * d,size_t b)532a58b312SMartin Matuska tf_sha512_transform_x64(uint64_t s[8], const void *d, size_t b)
542a58b312SMartin Matuska {
552a58b312SMartin Matuska zfs_sha512_transform_x64(s, d, b);
562a58b312SMartin Matuska }
572a58b312SMartin Matuska const sha512_ops_t sha512_x64_impl = {
582a58b312SMartin Matuska .is_supported = sha2_is_supported,
592a58b312SMartin Matuska .transform = tf_sha512_transform_x64,
602a58b312SMartin Matuska .name = "x64"
612a58b312SMartin Matuska };
622a58b312SMartin Matuska
632a58b312SMartin Matuska #if defined(HAVE_AVX)
sha2_have_avx(void)642a58b312SMartin Matuska static boolean_t sha2_have_avx(void)
652a58b312SMartin Matuska {
662a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx_available());
672a58b312SMartin Matuska }
682a58b312SMartin Matuska
692a58b312SMartin Matuska TF(zfs_sha512_transform_avx, tf_sha512_avx);
702a58b312SMartin Matuska const sha512_ops_t sha512_avx_impl = {
712a58b312SMartin Matuska .is_supported = sha2_have_avx,
722a58b312SMartin Matuska .transform = tf_sha512_avx,
732a58b312SMartin Matuska .name = "avx"
742a58b312SMartin Matuska };
752a58b312SMartin Matuska #endif
762a58b312SMartin Matuska
772a58b312SMartin Matuska #if defined(HAVE_AVX2)
sha2_have_avx2(void)782a58b312SMartin Matuska static boolean_t sha2_have_avx2(void)
792a58b312SMartin Matuska {
802a58b312SMartin Matuska return (kfpu_allowed() && zfs_avx2_available());
812a58b312SMartin Matuska }
822a58b312SMartin Matuska
832a58b312SMartin Matuska TF(zfs_sha512_transform_avx2, tf_sha512_avx2);
842a58b312SMartin Matuska const sha512_ops_t sha512_avx2_impl = {
852a58b312SMartin Matuska .is_supported = sha2_have_avx2,
862a58b312SMartin Matuska .transform = tf_sha512_avx2,
872a58b312SMartin Matuska .name = "avx2"
882a58b312SMartin Matuska };
892a58b312SMartin Matuska #endif
902a58b312SMartin Matuska
91*3494f7c0SMartin Matuska #elif defined(__aarch64__) || defined(__arm__)
922a58b312SMartin Matuska extern void zfs_sha512_block_armv7(uint64_t s[8], const void *, size_t);
932a58b312SMartin Matuska const sha512_ops_t sha512_armv7_impl = {
942a58b312SMartin Matuska .is_supported = sha2_is_supported,
952a58b312SMartin Matuska .transform = zfs_sha512_block_armv7,
962a58b312SMartin Matuska .name = "armv7"
972a58b312SMartin Matuska };
982a58b312SMartin Matuska
99*3494f7c0SMartin Matuska #if defined(__aarch64__)
sha512_have_armv8ce(void)1002a58b312SMartin Matuska static boolean_t sha512_have_armv8ce(void)
1012a58b312SMartin Matuska {
1022a58b312SMartin Matuska return (kfpu_allowed() && zfs_sha512_available());
1032a58b312SMartin Matuska }
1042a58b312SMartin Matuska
1052a58b312SMartin Matuska TF(zfs_sha512_block_armv8, tf_sha512_armv8ce);
1062a58b312SMartin Matuska const sha512_ops_t sha512_armv8_impl = {
1072a58b312SMartin Matuska .is_supported = sha512_have_armv8ce,
1082a58b312SMartin Matuska .transform = tf_sha512_armv8ce,
1092a58b312SMartin Matuska .name = "armv8-ce"
1102a58b312SMartin Matuska };
111*3494f7c0SMartin Matuska #endif
1122a58b312SMartin Matuska
113*3494f7c0SMartin Matuska #if defined(__arm__) && __ARM_ARCH > 6
sha512_have_neon(void)1142a58b312SMartin Matuska static boolean_t sha512_have_neon(void)
1152a58b312SMartin Matuska {
1162a58b312SMartin Matuska return (kfpu_allowed() && zfs_neon_available());
1172a58b312SMartin Matuska }
1182a58b312SMartin Matuska
1192a58b312SMartin Matuska TF(zfs_sha512_block_neon, tf_sha512_neon);
1202a58b312SMartin Matuska const sha512_ops_t sha512_neon_impl = {
1212a58b312SMartin Matuska .is_supported = sha512_have_neon,
1222a58b312SMartin Matuska .transform = tf_sha512_neon,
1232a58b312SMartin Matuska .name = "neon"
1242a58b312SMartin Matuska };
125*3494f7c0SMartin Matuska #endif
1262a58b312SMartin Matuska
1272a58b312SMartin Matuska #elif defined(__PPC64__)
1282a58b312SMartin Matuska TF(zfs_sha512_ppc, tf_sha512_ppc);
1292a58b312SMartin Matuska const sha512_ops_t sha512_ppc_impl = {
1302a58b312SMartin Matuska .is_supported = sha2_is_supported,
1312a58b312SMartin Matuska .transform = tf_sha512_ppc,
1322a58b312SMartin Matuska .name = "ppc"
1332a58b312SMartin Matuska };
1342a58b312SMartin Matuska
sha512_have_isa207(void)1352a58b312SMartin Matuska static boolean_t sha512_have_isa207(void)
1362a58b312SMartin Matuska {
1372a58b312SMartin Matuska return (kfpu_allowed() && zfs_isa207_available());
1382a58b312SMartin Matuska }
1392a58b312SMartin Matuska
1402a58b312SMartin Matuska TF(zfs_sha512_power8, tf_sha512_power8);
1412a58b312SMartin Matuska const sha512_ops_t sha512_power8_impl = {
1422a58b312SMartin Matuska .is_supported = sha512_have_isa207,
1432a58b312SMartin Matuska .transform = tf_sha512_power8,
1442a58b312SMartin Matuska .name = "power8"
1452a58b312SMartin Matuska };
1462a58b312SMartin Matuska #endif /* __PPC64__ */
1472a58b312SMartin Matuska
1482a58b312SMartin Matuska /* the two generic ones */
1492a58b312SMartin Matuska extern const sha512_ops_t sha512_generic_impl;
1502a58b312SMartin Matuska
1512a58b312SMartin Matuska /* array with all sha512 implementations */
1522a58b312SMartin Matuska static const sha512_ops_t *const sha512_impls[] = {
1532a58b312SMartin Matuska &sha512_generic_impl,
1542a58b312SMartin Matuska #if defined(__x86_64)
1552a58b312SMartin Matuska &sha512_x64_impl,
1562a58b312SMartin Matuska #endif
1572a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX)
1582a58b312SMartin Matuska &sha512_avx_impl,
1592a58b312SMartin Matuska #endif
1602a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX2)
1612a58b312SMartin Matuska &sha512_avx2_impl,
1622a58b312SMartin Matuska #endif
163*3494f7c0SMartin Matuska #if defined(__aarch64__) || defined(__arm__)
1642a58b312SMartin Matuska &sha512_armv7_impl,
165*3494f7c0SMartin Matuska #if defined(__aarch64__)
1662a58b312SMartin Matuska &sha512_armv8_impl,
1672a58b312SMartin Matuska #endif
1682a58b312SMartin Matuska #if defined(__arm__) && __ARM_ARCH > 6
1692a58b312SMartin Matuska &sha512_neon_impl,
1702a58b312SMartin Matuska #endif
171*3494f7c0SMartin Matuska #endif
1722a58b312SMartin Matuska #if defined(__PPC64__)
1732a58b312SMartin Matuska &sha512_ppc_impl,
1742a58b312SMartin Matuska &sha512_power8_impl,
1752a58b312SMartin Matuska #endif /* __PPC64__ */
1762a58b312SMartin Matuska };
1772a58b312SMartin Matuska
1782a58b312SMartin Matuska /* use the generic implementation functions */
1792a58b312SMartin Matuska #define IMPL_NAME "sha512"
1802a58b312SMartin Matuska #define IMPL_OPS_T sha512_ops_t
1812a58b312SMartin Matuska #define IMPL_ARRAY sha512_impls
1822a58b312SMartin Matuska #define IMPL_GET_OPS sha512_get_ops
1832a58b312SMartin Matuska #define ZFS_IMPL_OPS zfs_sha512_ops
1842a58b312SMartin Matuska #include <generic_impl.c>
1852a58b312SMartin Matuska
1862a58b312SMartin Matuska #ifdef _KERNEL
1872a58b312SMartin Matuska
1882a58b312SMartin Matuska #define IMPL_FMT(impl, i) (((impl) == (i)) ? "[%s] " : "%s ")
1892a58b312SMartin Matuska
1902a58b312SMartin Matuska #if defined(__linux__)
1912a58b312SMartin Matuska
1922a58b312SMartin Matuska static int
sha512_param_get(char * buffer,zfs_kernel_param_t * unused)1932a58b312SMartin Matuska sha512_param_get(char *buffer, zfs_kernel_param_t *unused)
1942a58b312SMartin Matuska {
1952a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
1962a58b312SMartin Matuska char *fmt;
1972a58b312SMartin Matuska int cnt = 0;
1982a58b312SMartin Matuska
1992a58b312SMartin Matuska /* cycling */
2002a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2012a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "cycle");
2022a58b312SMartin Matuska
2032a58b312SMartin Matuska /* list fastest */
2042a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2052a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt, "fastest");
2062a58b312SMartin Matuska
2072a58b312SMartin Matuska /* list all supported implementations */
2082a58b312SMartin Matuska generic_impl_init();
2092a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2102a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2112a58b312SMartin Matuska cnt += sprintf(buffer + cnt, fmt,
2122a58b312SMartin Matuska generic_supp_impls[i]->name);
2132a58b312SMartin Matuska }
2142a58b312SMartin Matuska
2152a58b312SMartin Matuska return (cnt);
2162a58b312SMartin Matuska }
2172a58b312SMartin Matuska
2182a58b312SMartin Matuska static int
sha512_param_set(const char * val,zfs_kernel_param_t * unused)2192a58b312SMartin Matuska sha512_param_set(const char *val, zfs_kernel_param_t *unused)
2202a58b312SMartin Matuska {
2212a58b312SMartin Matuska (void) unused;
2222a58b312SMartin Matuska return (generic_impl_setname(val));
2232a58b312SMartin Matuska }
2242a58b312SMartin Matuska
2252a58b312SMartin Matuska #elif defined(__FreeBSD__)
2262a58b312SMartin Matuska
2272a58b312SMartin Matuska #include <sys/sbuf.h>
2282a58b312SMartin Matuska
2292a58b312SMartin Matuska static int
sha512_param(ZFS_MODULE_PARAM_ARGS)2302a58b312SMartin Matuska sha512_param(ZFS_MODULE_PARAM_ARGS)
2312a58b312SMartin Matuska {
2322a58b312SMartin Matuska int err;
2332a58b312SMartin Matuska
2342a58b312SMartin Matuska generic_impl_init();
2352a58b312SMartin Matuska if (req->newptr == NULL) {
2362a58b312SMartin Matuska const uint32_t impl = IMPL_READ(generic_impl_chosen);
2372a58b312SMartin Matuska const int init_buflen = 64;
2382a58b312SMartin Matuska const char *fmt;
2392a58b312SMartin Matuska struct sbuf *s;
2402a58b312SMartin Matuska
2412a58b312SMartin Matuska s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
2422a58b312SMartin Matuska
2432a58b312SMartin Matuska /* cycling */
2442a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_CYCLE);
2452a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "cycle");
2462a58b312SMartin Matuska
2472a58b312SMartin Matuska /* list fastest */
2482a58b312SMartin Matuska fmt = IMPL_FMT(impl, IMPL_FASTEST);
2492a58b312SMartin Matuska (void) sbuf_printf(s, fmt, "fastest");
2502a58b312SMartin Matuska
2512a58b312SMartin Matuska /* list all supported implementations */
2522a58b312SMartin Matuska for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2532a58b312SMartin Matuska fmt = IMPL_FMT(impl, i);
2542a58b312SMartin Matuska (void) sbuf_printf(s, fmt, generic_supp_impls[i]->name);
2552a58b312SMartin Matuska }
2562a58b312SMartin Matuska
2572a58b312SMartin Matuska err = sbuf_finish(s);
2582a58b312SMartin Matuska sbuf_delete(s);
2592a58b312SMartin Matuska
2602a58b312SMartin Matuska return (err);
2612a58b312SMartin Matuska }
2622a58b312SMartin Matuska
2632a58b312SMartin Matuska /* we got module parameter */
2642a58b312SMartin Matuska char buf[16];
2652a58b312SMartin Matuska
2662a58b312SMartin Matuska err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
2672a58b312SMartin Matuska if (err) {
2682a58b312SMartin Matuska return (err);
2692a58b312SMartin Matuska }
2702a58b312SMartin Matuska
2712a58b312SMartin Matuska return (-generic_impl_setname(buf));
2722a58b312SMartin Matuska }
2732a58b312SMartin Matuska #endif
2742a58b312SMartin Matuska
2752a58b312SMartin Matuska #undef IMPL_FMT
2762a58b312SMartin Matuska
2772a58b312SMartin Matuska ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, sha512_impl,
2782a58b312SMartin Matuska sha512_param_set, sha512_param_get, ZMOD_RW, \
2792a58b312SMartin Matuska "Select SHA512 implementation.");
2802a58b312SMartin Matuska #endif
2812a58b312SMartin Matuska
2822a58b312SMartin Matuska #undef TF
283