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(uint32_t s[8], const void *, size_t); \
362a58b312SMartin Matuska 	static inline void N(uint32_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_sha256_transform_x64(uint32_t s[8], const void *, size_t);
512a58b312SMartin Matuska 
522a58b312SMartin Matuska static inline void
tf_sha256_transform_x64(uint32_t s[8],const void * d,size_t b)532a58b312SMartin Matuska tf_sha256_transform_x64(uint32_t s[8], const void *d, size_t b)
542a58b312SMartin Matuska {
552a58b312SMartin Matuska 	zfs_sha256_transform_x64(s, d, b);
562a58b312SMartin Matuska }
572a58b312SMartin Matuska 
582a58b312SMartin Matuska const sha256_ops_t sha256_x64_impl = {
592a58b312SMartin Matuska 	.is_supported = sha2_is_supported,
602a58b312SMartin Matuska 	.transform = tf_sha256_transform_x64,
612a58b312SMartin Matuska 	.name = "x64"
622a58b312SMartin Matuska };
632a58b312SMartin Matuska 
642a58b312SMartin Matuska #if defined(HAVE_SSSE3)
sha2_have_ssse3(void)652a58b312SMartin Matuska static boolean_t sha2_have_ssse3(void)
662a58b312SMartin Matuska {
672a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_ssse3_available());
682a58b312SMartin Matuska }
692a58b312SMartin Matuska 
702a58b312SMartin Matuska TF(zfs_sha256_transform_ssse3, tf_sha256_ssse3);
712a58b312SMartin Matuska const sha256_ops_t sha256_ssse3_impl = {
722a58b312SMartin Matuska 	.is_supported = sha2_have_ssse3,
732a58b312SMartin Matuska 	.transform = tf_sha256_ssse3,
742a58b312SMartin Matuska 	.name = "ssse3"
752a58b312SMartin Matuska };
762a58b312SMartin Matuska #endif
772a58b312SMartin Matuska 
782a58b312SMartin Matuska #if defined(HAVE_AVX)
sha2_have_avx(void)792a58b312SMartin Matuska static boolean_t sha2_have_avx(void)
802a58b312SMartin Matuska {
812a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_avx_available());
822a58b312SMartin Matuska }
832a58b312SMartin Matuska 
842a58b312SMartin Matuska TF(zfs_sha256_transform_avx, tf_sha256_avx);
852a58b312SMartin Matuska const sha256_ops_t sha256_avx_impl = {
862a58b312SMartin Matuska 	.is_supported = sha2_have_avx,
872a58b312SMartin Matuska 	.transform = tf_sha256_avx,
882a58b312SMartin Matuska 	.name = "avx"
892a58b312SMartin Matuska };
902a58b312SMartin Matuska #endif
912a58b312SMartin Matuska 
922a58b312SMartin Matuska #if defined(HAVE_AVX2)
sha2_have_avx2(void)932a58b312SMartin Matuska static boolean_t sha2_have_avx2(void)
942a58b312SMartin Matuska {
952a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_avx2_available());
962a58b312SMartin Matuska }
972a58b312SMartin Matuska 
982a58b312SMartin Matuska TF(zfs_sha256_transform_avx2, tf_sha256_avx2);
992a58b312SMartin Matuska const sha256_ops_t sha256_avx2_impl = {
1002a58b312SMartin Matuska 	.is_supported = sha2_have_avx2,
1012a58b312SMartin Matuska 	.transform = tf_sha256_avx2,
1022a58b312SMartin Matuska 	.name = "avx2"
1032a58b312SMartin Matuska };
1042a58b312SMartin Matuska #endif
1052a58b312SMartin Matuska 
1062a58b312SMartin Matuska #if defined(HAVE_SSE4_1)
sha2_have_shani(void)1072a58b312SMartin Matuska static boolean_t sha2_have_shani(void)
1082a58b312SMartin Matuska {
1092a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_sse4_1_available() && \
1102a58b312SMartin Matuska 	    zfs_shani_available());
1112a58b312SMartin Matuska }
1122a58b312SMartin Matuska 
1132a58b312SMartin Matuska TF(zfs_sha256_transform_shani, tf_sha256_shani);
1142a58b312SMartin Matuska const sha256_ops_t sha256_shani_impl = {
1152a58b312SMartin Matuska 	.is_supported = sha2_have_shani,
1162a58b312SMartin Matuska 	.transform = tf_sha256_shani,
1172a58b312SMartin Matuska 	.name = "shani"
1182a58b312SMartin Matuska };
1192a58b312SMartin Matuska #endif
1202a58b312SMartin Matuska 
121*3494f7c0SMartin Matuska #elif defined(__aarch64__) || defined(__arm__)
122*3494f7c0SMartin Matuska extern void zfs_sha256_block_armv7(uint32_t s[8], const void *, size_t);
123*3494f7c0SMartin Matuska const sha256_ops_t sha256_armv7_impl = {
124*3494f7c0SMartin Matuska 	.is_supported = sha2_is_supported,
125*3494f7c0SMartin Matuska 	.transform = zfs_sha256_block_armv7,
126*3494f7c0SMartin Matuska 	.name = "armv7"
127*3494f7c0SMartin Matuska };
128*3494f7c0SMartin Matuska 
129*3494f7c0SMartin Matuska #if __ARM_ARCH > 6
sha256_have_neon(void)1302a58b312SMartin Matuska static boolean_t sha256_have_neon(void)
1312a58b312SMartin Matuska {
1322a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_neon_available());
1332a58b312SMartin Matuska }
1342a58b312SMartin Matuska 
sha256_have_armv8ce(void)1352a58b312SMartin Matuska static boolean_t sha256_have_armv8ce(void)
1362a58b312SMartin Matuska {
1372a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_sha256_available());
1382a58b312SMartin Matuska }
1392a58b312SMartin Matuska 
1402a58b312SMartin Matuska TF(zfs_sha256_block_neon, tf_sha256_neon);
1412a58b312SMartin Matuska const sha256_ops_t sha256_neon_impl = {
1422a58b312SMartin Matuska 	.is_supported = sha256_have_neon,
1432a58b312SMartin Matuska 	.transform = tf_sha256_neon,
1442a58b312SMartin Matuska 	.name = "neon"
1452a58b312SMartin Matuska };
1462a58b312SMartin Matuska 
1472a58b312SMartin Matuska TF(zfs_sha256_block_armv8, tf_sha256_armv8ce);
1482a58b312SMartin Matuska const sha256_ops_t sha256_armv8_impl = {
1492a58b312SMartin Matuska 	.is_supported = sha256_have_armv8ce,
1502a58b312SMartin Matuska 	.transform = tf_sha256_armv8ce,
1512a58b312SMartin Matuska 	.name = "armv8-ce"
1522a58b312SMartin Matuska };
153*3494f7c0SMartin Matuska #endif
1542a58b312SMartin Matuska 
1552a58b312SMartin Matuska #elif defined(__PPC64__)
sha256_have_isa207(void)1562a58b312SMartin Matuska static boolean_t sha256_have_isa207(void)
1572a58b312SMartin Matuska {
1582a58b312SMartin Matuska 	return (kfpu_allowed() && zfs_isa207_available());
1592a58b312SMartin Matuska }
1602a58b312SMartin Matuska 
1612a58b312SMartin Matuska TF(zfs_sha256_ppc, tf_sha256_ppc);
1622a58b312SMartin Matuska const sha256_ops_t sha256_ppc_impl = {
1632a58b312SMartin Matuska 	.is_supported = sha2_is_supported,
1642a58b312SMartin Matuska 	.transform = tf_sha256_ppc,
1652a58b312SMartin Matuska 	.name = "ppc"
1662a58b312SMartin Matuska };
1672a58b312SMartin Matuska 
1682a58b312SMartin Matuska TF(zfs_sha256_power8, tf_sha256_power8);
1692a58b312SMartin Matuska const sha256_ops_t sha256_power8_impl = {
1702a58b312SMartin Matuska 	.is_supported = sha256_have_isa207,
1712a58b312SMartin Matuska 	.transform = tf_sha256_power8,
1722a58b312SMartin Matuska 	.name = "power8"
1732a58b312SMartin Matuska };
1742a58b312SMartin Matuska #endif /* __PPC64__ */
1752a58b312SMartin Matuska 
1762a58b312SMartin Matuska /* the two generic ones */
1772a58b312SMartin Matuska extern const sha256_ops_t sha256_generic_impl;
1782a58b312SMartin Matuska 
1792a58b312SMartin Matuska /* array with all sha256 implementations */
1802a58b312SMartin Matuska static const sha256_ops_t *const sha256_impls[] = {
1812a58b312SMartin Matuska 	&sha256_generic_impl,
1822a58b312SMartin Matuska #if defined(__x86_64)
1832a58b312SMartin Matuska 	&sha256_x64_impl,
1842a58b312SMartin Matuska #endif
1852a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSSE3)
1862a58b312SMartin Matuska 	&sha256_ssse3_impl,
1872a58b312SMartin Matuska #endif
1882a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX)
1892a58b312SMartin Matuska 	&sha256_avx_impl,
1902a58b312SMartin Matuska #endif
1912a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_AVX2)
1922a58b312SMartin Matuska 	&sha256_avx2_impl,
1932a58b312SMartin Matuska #endif
1942a58b312SMartin Matuska #if defined(__x86_64) && defined(HAVE_SSE4_1)
1952a58b312SMartin Matuska 	&sha256_shani_impl,
1962a58b312SMartin Matuska #endif
197*3494f7c0SMartin Matuska #if defined(__aarch64__) || defined(__arm__)
1982a58b312SMartin Matuska 	&sha256_armv7_impl,
199*3494f7c0SMartin Matuska #if __ARM_ARCH > 6
2002a58b312SMartin Matuska 	&sha256_neon_impl,
2012a58b312SMartin Matuska 	&sha256_armv8_impl,
2022a58b312SMartin Matuska #endif
203*3494f7c0SMartin Matuska #endif
2042a58b312SMartin Matuska #if defined(__PPC64__)
2052a58b312SMartin Matuska 	&sha256_ppc_impl,
2062a58b312SMartin Matuska 	&sha256_power8_impl,
2072a58b312SMartin Matuska #endif /* __PPC64__ */
2082a58b312SMartin Matuska };
2092a58b312SMartin Matuska 
2102a58b312SMartin Matuska /* use the generic implementation functions */
2112a58b312SMartin Matuska #define	IMPL_NAME		"sha256"
2122a58b312SMartin Matuska #define	IMPL_OPS_T		sha256_ops_t
2132a58b312SMartin Matuska #define	IMPL_ARRAY		sha256_impls
2142a58b312SMartin Matuska #define	IMPL_GET_OPS		sha256_get_ops
2152a58b312SMartin Matuska #define	ZFS_IMPL_OPS		zfs_sha256_ops
2162a58b312SMartin Matuska #include <generic_impl.c>
2172a58b312SMartin Matuska 
2182a58b312SMartin Matuska #ifdef _KERNEL
2192a58b312SMartin Matuska 
2202a58b312SMartin Matuska #define	IMPL_FMT(impl, i)	(((impl) == (i)) ? "[%s] " : "%s ")
2212a58b312SMartin Matuska 
2222a58b312SMartin Matuska #if defined(__linux__)
2232a58b312SMartin Matuska 
2242a58b312SMartin Matuska static int
sha256_param_get(char * buffer,zfs_kernel_param_t * unused)2252a58b312SMartin Matuska sha256_param_get(char *buffer, zfs_kernel_param_t *unused)
2262a58b312SMartin Matuska {
2272a58b312SMartin Matuska 	const uint32_t impl = IMPL_READ(generic_impl_chosen);
2282a58b312SMartin Matuska 	char *fmt;
2292a58b312SMartin Matuska 	int cnt = 0;
2302a58b312SMartin Matuska 
2312a58b312SMartin Matuska 	/* cycling */
2322a58b312SMartin Matuska 	fmt = IMPL_FMT(impl, IMPL_CYCLE);
2332a58b312SMartin Matuska 	cnt += sprintf(buffer + cnt, fmt, "cycle");
2342a58b312SMartin Matuska 
2352a58b312SMartin Matuska 	/* list fastest */
2362a58b312SMartin Matuska 	fmt = IMPL_FMT(impl, IMPL_FASTEST);
2372a58b312SMartin Matuska 	cnt += sprintf(buffer + cnt, fmt, "fastest");
2382a58b312SMartin Matuska 
2392a58b312SMartin Matuska 	/* list all supported implementations */
2402a58b312SMartin Matuska 	generic_impl_init();
2412a58b312SMartin Matuska 	for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2422a58b312SMartin Matuska 		fmt = IMPL_FMT(impl, i);
2432a58b312SMartin Matuska 		cnt += sprintf(buffer + cnt, fmt,
2442a58b312SMartin Matuska 		    generic_supp_impls[i]->name);
2452a58b312SMartin Matuska 	}
2462a58b312SMartin Matuska 
2472a58b312SMartin Matuska 	return (cnt);
2482a58b312SMartin Matuska }
2492a58b312SMartin Matuska 
2502a58b312SMartin Matuska static int
sha256_param_set(const char * val,zfs_kernel_param_t * unused)2512a58b312SMartin Matuska sha256_param_set(const char *val, zfs_kernel_param_t *unused)
2522a58b312SMartin Matuska {
2532a58b312SMartin Matuska 	(void) unused;
2542a58b312SMartin Matuska 	return (generic_impl_setname(val));
2552a58b312SMartin Matuska }
2562a58b312SMartin Matuska 
2572a58b312SMartin Matuska #elif defined(__FreeBSD__)
2582a58b312SMartin Matuska 
2592a58b312SMartin Matuska #include <sys/sbuf.h>
2602a58b312SMartin Matuska 
2612a58b312SMartin Matuska static int
sha256_param(ZFS_MODULE_PARAM_ARGS)2622a58b312SMartin Matuska sha256_param(ZFS_MODULE_PARAM_ARGS)
2632a58b312SMartin Matuska {
2642a58b312SMartin Matuska 	int err;
2652a58b312SMartin Matuska 
2662a58b312SMartin Matuska 	generic_impl_init();
2672a58b312SMartin Matuska 	if (req->newptr == NULL) {
2682a58b312SMartin Matuska 		const uint32_t impl = IMPL_READ(generic_impl_chosen);
2692a58b312SMartin Matuska 		const int init_buflen = 64;
2702a58b312SMartin Matuska 		const char *fmt;
2712a58b312SMartin Matuska 		struct sbuf *s;
2722a58b312SMartin Matuska 
2732a58b312SMartin Matuska 		s = sbuf_new_for_sysctl(NULL, NULL, init_buflen, req);
2742a58b312SMartin Matuska 
2752a58b312SMartin Matuska 		/* cycling */
2762a58b312SMartin Matuska 		fmt = IMPL_FMT(impl, IMPL_CYCLE);
2772a58b312SMartin Matuska 		(void) sbuf_printf(s, fmt, "cycle");
2782a58b312SMartin Matuska 
2792a58b312SMartin Matuska 		/* list fastest */
2802a58b312SMartin Matuska 		fmt = IMPL_FMT(impl, IMPL_FASTEST);
2812a58b312SMartin Matuska 		(void) sbuf_printf(s, fmt, "fastest");
2822a58b312SMartin Matuska 
2832a58b312SMartin Matuska 		/* list all supported implementations */
2842a58b312SMartin Matuska 		for (uint32_t i = 0; i < generic_supp_impls_cnt; ++i) {
2852a58b312SMartin Matuska 			fmt = IMPL_FMT(impl, i);
2862a58b312SMartin Matuska 			(void) sbuf_printf(s, fmt, generic_supp_impls[i]->name);
2872a58b312SMartin Matuska 		}
2882a58b312SMartin Matuska 
2892a58b312SMartin Matuska 		err = sbuf_finish(s);
2902a58b312SMartin Matuska 		sbuf_delete(s);
2912a58b312SMartin Matuska 
2922a58b312SMartin Matuska 		return (err);
2932a58b312SMartin Matuska 	}
2942a58b312SMartin Matuska 
2952a58b312SMartin Matuska 	char buf[16];
2962a58b312SMartin Matuska 
2972a58b312SMartin Matuska 	err = sysctl_handle_string(oidp, buf, sizeof (buf), req);
2982a58b312SMartin Matuska 	if (err) {
2992a58b312SMartin Matuska 		return (err);
3002a58b312SMartin Matuska 	}
3012a58b312SMartin Matuska 
3022a58b312SMartin Matuska 	return (-generic_impl_setname(buf));
3032a58b312SMartin Matuska }
3042a58b312SMartin Matuska #endif
3052a58b312SMartin Matuska 
3062a58b312SMartin Matuska #undef IMPL_FMT
3072a58b312SMartin Matuska 
3082a58b312SMartin Matuska ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs, zfs_, sha256_impl,
3092a58b312SMartin Matuska     sha256_param_set, sha256_param_get, ZMOD_RW, \
3102a58b312SMartin Matuska 	"Select SHA256 implementation.");
3112a58b312SMartin Matuska #endif
3122a58b312SMartin Matuska 
3132a58b312SMartin Matuska #undef TF
314