]> git.proxmox.com Git - ceph.git/blame - ceph/src/crypto/isa-l/isa-l_crypto/sha512_mb/sha512_ctx_avx512.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / crypto / isa-l / isa-l_crypto / sha512_mb / sha512_ctx_avx512.c
CommitLineData
7c673cae
FG
1/**********************************************************************
2 Copyright(c) 2011-2016 Intel Corporation All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
1e59de90 5 modification, are permitted provided that the following conditions
7c673cae
FG
6 are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in
11 the documentation and/or other materials provided with the
12 distribution.
13 * Neither the name of Intel Corporation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28**********************************************************************/
29
1e59de90
TL
30#if defined(__clang__)
31# pragma clang attribute push (__attribute__((target("avx2"))), apply_to=function)
32#elif defined(__ICC)
33# pragma intel optimization_parameter target_arch=AVX2
34#elif defined(__ICL)
35# pragma [intel] optimization_parameter target_arch=AVX2
36#elif (__GNUC__ >= 5)
37# pragma GCC target("avx2")
38#endif
39
7c673cae
FG
40#include "sha512_mb.h"
41#include "memcpy_inline.h"
1e59de90 42#include "endian_helper.h"
7c673cae
FG
43
44#ifdef _MSC_VER
45# include <intrin.h>
46# define inline __inline
47#endif
48
49#ifdef HAVE_AS_KNOWS_AVX512
50
51static inline void hash_init_digest(SHA512_WORD_T * digest);
1e59de90 52static inline uint32_t hash_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2], uint64_t total_len);
7c673cae
FG
53static SHA512_HASH_CTX *sha512_ctx_mgr_resubmit(SHA512_HASH_CTX_MGR * mgr,
54 SHA512_HASH_CTX * ctx);
55
56void sha512_ctx_mgr_init_avx512(SHA512_HASH_CTX_MGR * mgr)
57{
58 sha512_mb_mgr_init_avx512(&mgr->mgr);
59}
60
61SHA512_HASH_CTX *sha512_ctx_mgr_submit_avx512(SHA512_HASH_CTX_MGR * mgr, SHA512_HASH_CTX * ctx,
62 const void *buffer, uint32_t len,
63 HASH_CTX_FLAG flags)
64{
65 if (flags & (~HASH_ENTIRE)) {
66 // User should not pass anything other than FIRST, UPDATE, or LAST
67 ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
68 return ctx;
69 }
70
71 if (ctx->status & HASH_CTX_STS_PROCESSING) {
72 // Cannot submit to a currently processing job.
73 ctx->error = HASH_CTX_ERROR_ALREADY_PROCESSING;
74 return ctx;
75 }
76
77 if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
78 // Cannot update a finished job.
79 ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
80 return ctx;
81 }
82
83 if (flags & HASH_FIRST) {
84 // Init digest
85 hash_init_digest(ctx->job.result_digest);
86
87 // Reset byte counter
88 ctx->total_length = 0;
89
90 // Clear extra blocks
91 ctx->partial_block_buffer_length = 0;
92 }
93 // If we made it here, there were no errors during this call to submit
94 ctx->error = HASH_CTX_ERROR_NONE;
95
96 // Store buffer ptr info from user
97 ctx->incoming_buffer = buffer;
98 ctx->incoming_buffer_length = len;
99
100 // Store the user's request flags and mark this ctx as currently being processed.
101 ctx->status = (flags & HASH_LAST) ?
102 (HASH_CTX_STS) (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_LAST) :
103 HASH_CTX_STS_PROCESSING;
104
105 // Advance byte counter
106 ctx->total_length += len;
107
108 // If there is anything currently buffered in the extra blocks, append to it until it contains a whole block.
109 // Or if the user's buffer contains less than a whole block, append as much as possible to the extra block.
110 if ((ctx->partial_block_buffer_length) | (len < SHA512_BLOCK_SIZE)) {
111 // Compute how many bytes to copy from user buffer into extra block
112 uint32_t copy_len = SHA512_BLOCK_SIZE - ctx->partial_block_buffer_length;
113 if (len < copy_len)
114 copy_len = len;
115
116 if (copy_len) {
117 // Copy and update relevant pointers and counters
118 memcpy_varlen(&ctx->partial_block_buffer
119 [ctx->partial_block_buffer_length], buffer, copy_len);
120
121 ctx->partial_block_buffer_length += copy_len;
122 ctx->incoming_buffer = (const void *)((const char *)buffer + copy_len);
123 ctx->incoming_buffer_length = len - copy_len;
124 }
125 // The extra block should never contain more than 1 block here
126 assert(ctx->partial_block_buffer_length <= SHA512_BLOCK_SIZE);
127
128 // If the extra block buffer contains exactly 1 block, it can be hashed.
129 if (ctx->partial_block_buffer_length >= SHA512_BLOCK_SIZE) {
130 ctx->partial_block_buffer_length = 0;
131
132 ctx->job.buffer = ctx->partial_block_buffer;
133 ctx->job.len = 1;
134
135 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx512(&mgr->mgr,
136 &ctx->job);
137 }
138 }
139
140 return sha512_ctx_mgr_resubmit(mgr, ctx);
141}
142
143SHA512_HASH_CTX *sha512_ctx_mgr_flush_avx512(SHA512_HASH_CTX_MGR * mgr)
144{
145 SHA512_HASH_CTX *ctx;
146
147 while (1) {
148 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_flush_avx512(&mgr->mgr);
149
150 // If flush returned 0, there are no more jobs in flight.
151 if (!ctx)
152 return NULL;
153
154 // If flush returned a job, verify that it is safe to return to the user.
155 // If it is not ready, resubmit the job to finish processing.
156 ctx = sha512_ctx_mgr_resubmit(mgr, ctx);
157
158 // If sha512_ctx_mgr_resubmit returned a job, it is ready to be returned.
159 if (ctx)
160 return ctx;
161
162 // Otherwise, all jobs currently being managed by the SHA512_HASH_CTX_MGR still need processing. Loop.
163 }
164}
165
166static SHA512_HASH_CTX *sha512_ctx_mgr_resubmit(SHA512_HASH_CTX_MGR * mgr,
167 SHA512_HASH_CTX * ctx)
168{
169 while (ctx) {
170 if (ctx->status & HASH_CTX_STS_COMPLETE) {
171 ctx->status = HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
172 return ctx;
173 }
174 // If the extra blocks are empty, begin hashing what remains in the user's buffer.
175 if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
176 const void *buffer = ctx->incoming_buffer;
177 uint32_t len = ctx->incoming_buffer_length;
178
179 // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
180 uint32_t copy_len = len & (SHA512_BLOCK_SIZE - 1);
181
182 if (copy_len) {
183 len -= copy_len;
184 memcpy_varlen(ctx->partial_block_buffer,
185 ((const char *)buffer + len), copy_len);
186 ctx->partial_block_buffer_length = copy_len;
187 }
188
189 ctx->incoming_buffer_length = 0;
190
191 // len should be a multiple of the block size now
192 assert((len % SHA512_BLOCK_SIZE) == 0);
193
194 // Set len to the number of blocks to be hashed in the user's buffer
195 len >>= SHA512_LOG2_BLOCK_SIZE;
196
197 if (len) {
198 ctx->job.buffer = (uint8_t *) buffer;
199 ctx->job.len = len;
200 ctx =
201 (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx512(&mgr->mgr,
202 &ctx->job);
203 continue;
204 }
205 }
206 // If the extra blocks are not empty, then we are either on the last block(s)
207 // or we need more user input before continuing.
208 if (ctx->status & HASH_CTX_STS_LAST) {
209 uint8_t *buf = ctx->partial_block_buffer;
210 uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
211
212 ctx->status =
213 (HASH_CTX_STS) (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_COMPLETE);
214 ctx->job.buffer = buf;
215 ctx->job.len = (uint32_t) n_extra_blocks;
216 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx512(&mgr->mgr,
217 &ctx->job);
218 continue;
219 }
220
221 if (ctx)
222 ctx->status = HASH_CTX_STS_IDLE;
223 return ctx;
224 }
225
226 return NULL;
227}
228
229static inline void hash_init_digest(SHA512_WORD_T * digest)
230{
231 static const SHA512_WORD_T hash_initial_digest[SHA512_DIGEST_NWORDS] =
232 { SHA512_INITIAL_DIGEST };
233 memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
234}
235
1e59de90 236static inline uint32_t hash_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2], uint64_t total_len)
7c673cae 237{
1e59de90 238 uint32_t i = (uint32_t) (total_len & (SHA512_BLOCK_SIZE - 1));
7c673cae
FG
239
240 memclr_fixedlen(&padblock[i], SHA512_BLOCK_SIZE);
241 padblock[i] = 0x80;
242
243 // Move i to the end of either 1st or 2nd extra block depending on length
244 i += ((SHA512_BLOCK_SIZE - 1) & (0 - (total_len + SHA512_PADLENGTHFIELD_SIZE + 1))) +
245 1 + SHA512_PADLENGTHFIELD_SIZE;
246
247#if SHA512_PADLENGTHFIELD_SIZE == 16
248 *((uint64_t *) & padblock[i - 16]) = 0;
249#endif
250
1e59de90 251 *((uint64_t *) & padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
7c673cae
FG
252
253 return i >> SHA512_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
254}
255
256struct slver {
257 uint16_t snum;
258 uint8_t ver;
259 uint8_t core;
260};
261struct slver sha512_ctx_mgr_init_avx512_slver_0600016a;
262struct slver sha512_ctx_mgr_init_avx512_slver = { 0x016a, 0x00, 0x06 };
263
264struct slver sha512_ctx_mgr_submit_avx512_slver_0600016b;
265struct slver sha512_ctx_mgr_submit_avx512_slver = { 0x016b, 0x00, 0x06 };
266
267struct slver sha512_ctx_mgr_flush_avx512_slver_0600016c;
268struct slver sha512_ctx_mgr_flush_avx512_slver = { 0x016c, 0x00, 0x06 };
269
270#endif // HAVE_AS_KNOWS_AVX512
1e59de90
TL
271
272#if defined(__clang__)
273# pragma clang attribute pop
274#endif