4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2022 Tino Reichardt <milky-zfs@mcmilk.de>
27 #include <sys/zfs_context.h>
28 #include <sys/zfs_impl.h>
31 #include <sha2/sha2_impl.h>
32 #include <sys/asm_linkage.h>
35 extern void ASMABI E(uint64_t s[8], const void *, size_t); \
36 static inline void N(uint64_t s[8], const void *d, size_t b) { \
37 kfpu_begin(); E(s, d, b); kfpu_end(); \
40 /* some implementation is always okay */
41 static inline boolean_t
sha2_is_supported(void)
48 /* Users of ASMABI requires all calls to be from wrappers */
50 zfs_sha512_transform_x64(uint64_t s
[8], const void *, size_t);
53 tf_sha512_transform_x64(uint64_t s
[8], const void *d
, size_t b
)
55 zfs_sha512_transform_x64(s
, d
, b
);
57 const sha512_ops_t sha512_x64_impl
= {
58 .is_supported
= sha2_is_supported
,
59 .transform
= tf_sha512_transform_x64
,
64 static boolean_t
sha2_have_avx(void)
66 return (kfpu_allowed() && zfs_avx_available());
69 TF(zfs_sha512_transform_avx
, tf_sha512_avx
);
70 const sha512_ops_t sha512_avx_impl
= {
71 .is_supported
= sha2_have_avx
,
72 .transform
= tf_sha512_avx
,
77 #if defined(HAVE_AVX2)
78 static boolean_t
sha2_have_avx2(void)
80 return (kfpu_allowed() && zfs_avx2_available());
83 TF(zfs_sha512_transform_avx2
, tf_sha512_avx2
);
84 const sha512_ops_t sha512_avx2_impl
= {
85 .is_supported
= sha2_have_avx2
,
86 .transform
= tf_sha512_avx2
,
91 #elif defined(__aarch64__)
92 extern void zfs_sha512_block_armv7(uint64_t s
[8], const void *, size_t);
93 const sha512_ops_t sha512_armv7_impl
= {
94 .is_supported
= sha2_is_supported
,
95 .transform
= zfs_sha512_block_armv7
,
99 static boolean_t
sha512_have_armv8ce(void)
101 return (kfpu_allowed() && zfs_sha512_available());
104 TF(zfs_sha512_block_armv8
, tf_sha512_armv8ce
);
105 const sha512_ops_t sha512_armv8_impl
= {
106 .is_supported
= sha512_have_armv8ce
,
107 .transform
= tf_sha512_armv8ce
,
111 #elif defined(__arm__) && __ARM_ARCH > 6
112 extern void zfs_sha512_block_armv7(uint64_t s
[8], const void *, size_t);
113 const sha512_ops_t sha512_armv7_impl
= {
114 .is_supported
= sha2_is_supported
,
115 .transform
= zfs_sha512_block_armv7
,
119 static boolean_t
sha512_have_neon(void)
121 return (kfpu_allowed() && zfs_neon_available());
124 TF(zfs_sha512_block_neon
, tf_sha512_neon
);
125 const sha512_ops_t sha512_neon_impl
= {
126 .is_supported
= sha512_have_neon
,
127 .transform
= tf_sha512_neon
,
131 #elif defined(__PPC64__)
132 TF(zfs_sha512_ppc
, tf_sha512_ppc
);
133 const sha512_ops_t sha512_ppc_impl
= {
134 .is_supported
= sha2_is_supported
,
135 .transform
= tf_sha512_ppc
,
139 static boolean_t
sha512_have_isa207(void)
141 return (kfpu_allowed() && zfs_isa207_available());
144 TF(zfs_sha512_power8
, tf_sha512_power8
);
145 const sha512_ops_t sha512_power8_impl
= {
146 .is_supported
= sha512_have_isa207
,
147 .transform
= tf_sha512_power8
,
150 #endif /* __PPC64__ */
152 /* the two generic ones */
153 extern const sha512_ops_t sha512_generic_impl
;
155 /* array with all sha512 implementations */
156 static const sha512_ops_t
*const sha512_impls
[] = {
157 &sha512_generic_impl
,
158 #if defined(__x86_64)
161 #if defined(__x86_64) && defined(HAVE_AVX)
164 #if defined(__x86_64) && defined(HAVE_AVX2)
167 #if defined(__aarch64__)
171 #if defined(__arm__) && __ARM_ARCH > 6
175 #if defined(__PPC64__)
178 #endif /* __PPC64__ */
181 /* use the generic implementation functions */
182 #define IMPL_NAME "sha512"
183 #define IMPL_OPS_T sha512_ops_t
184 #define IMPL_ARRAY sha512_impls
185 #define IMPL_GET_OPS sha512_get_ops
186 #define ZFS_IMPL_OPS zfs_sha512_ops
187 #include <generic_impl.c>
191 #define IMPL_FMT(impl, i) (((impl) == (i)) ? "[%s] " : "%s ")
193 #if defined(__linux__)
196 sha512_param_get(char *buffer
, zfs_kernel_param_t
*unused
)
198 const uint32_t impl
= IMPL_READ(generic_impl_chosen
);
203 fmt
= IMPL_FMT(impl
, IMPL_CYCLE
);
204 cnt
+= sprintf(buffer
+ cnt
, fmt
, "cycle");
207 fmt
= IMPL_FMT(impl
, IMPL_FASTEST
);
208 cnt
+= sprintf(buffer
+ cnt
, fmt
, "fastest");
210 /* list all supported implementations */
212 for (uint32_t i
= 0; i
< generic_supp_impls_cnt
; ++i
) {
213 fmt
= IMPL_FMT(impl
, i
);
214 cnt
+= sprintf(buffer
+ cnt
, fmt
,
215 generic_supp_impls
[i
]->name
);
222 sha512_param_set(const char *val
, zfs_kernel_param_t
*unused
)
225 return (generic_impl_setname(val
));
228 #elif defined(__FreeBSD__)
230 #include <sys/sbuf.h>
233 sha512_param(ZFS_MODULE_PARAM_ARGS
)
238 if (req
->newptr
== NULL
) {
239 const uint32_t impl
= IMPL_READ(generic_impl_chosen
);
240 const int init_buflen
= 64;
244 s
= sbuf_new_for_sysctl(NULL
, NULL
, init_buflen
, req
);
247 fmt
= IMPL_FMT(impl
, IMPL_CYCLE
);
248 (void) sbuf_printf(s
, fmt
, "cycle");
251 fmt
= IMPL_FMT(impl
, IMPL_FASTEST
);
252 (void) sbuf_printf(s
, fmt
, "fastest");
254 /* list all supported implementations */
255 for (uint32_t i
= 0; i
< generic_supp_impls_cnt
; ++i
) {
256 fmt
= IMPL_FMT(impl
, i
);
257 (void) sbuf_printf(s
, fmt
, generic_supp_impls
[i
]->name
);
260 err
= sbuf_finish(s
);
266 /* we got module parameter */
269 err
= sysctl_handle_string(oidp
, buf
, sizeof (buf
), req
);
274 return (-generic_impl_setname(buf
));
280 ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs
, zfs_
, sha512_impl
,
281 sha512_param_set
, sha512_param_get
, ZMOD_RW
, \
282 "Select SHA512 implementation.");