]> git.proxmox.com Git - ceph.git/blame - ceph/src/crypto/isa-l/isa-l_crypto/sha512_mb/sha512_ctx_avx2.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / crypto / isa-l / isa-l_crypto / sha512_mb / sha512_ctx_avx2.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
49static inline void hash_init_digest(SHA512_WORD_T * digest);
1e59de90 50static inline uint32_t hash_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2], uint64_t total_len);
7c673cae
FG
51static SHA512_HASH_CTX *sha512_ctx_mgr_resubmit(SHA512_HASH_CTX_MGR * mgr,
52 SHA512_HASH_CTX * ctx);
53
54void sha512_ctx_mgr_init_avx2(SHA512_HASH_CTX_MGR * mgr)
55{
56 sha512_mb_mgr_init_avx2(&mgr->mgr);
57}
58
59SHA512_HASH_CTX *sha512_ctx_mgr_submit_avx2(SHA512_HASH_CTX_MGR * mgr, SHA512_HASH_CTX * ctx,
60 const void *buffer, uint32_t len,
61 HASH_CTX_FLAG flags)
62{
63 if (flags & (~HASH_ENTIRE)) {
64 // User should not pass anything other than FIRST, UPDATE, or LAST
65 ctx->error = HASH_CTX_ERROR_INVALID_FLAGS;
66 return ctx;
67 }
68
69 if (ctx->status & HASH_CTX_STS_PROCESSING) {
70 // Cannot submit to a currently processing job.
71 ctx->error = HASH_CTX_ERROR_ALREADY_PROCESSING;
72 return ctx;
73 }
74
75 if ((ctx->status & HASH_CTX_STS_COMPLETE) && !(flags & HASH_FIRST)) {
76 // Cannot update a finished job.
77 ctx->error = HASH_CTX_ERROR_ALREADY_COMPLETED;
78 return ctx;
79 }
80
81 if (flags & HASH_FIRST) {
82 // Init digest
83 hash_init_digest(ctx->job.result_digest);
84
85 // Reset byte counter
86 ctx->total_length = 0;
87
88 // Clear extra blocks
89 ctx->partial_block_buffer_length = 0;
90 }
91 // If we made it here, there were no errors during this call to submit
92 ctx->error = HASH_CTX_ERROR_NONE;
93
94 // Store buffer ptr info from user
95 ctx->incoming_buffer = buffer;
96 ctx->incoming_buffer_length = len;
97
98 // Store the user's request flags and mark this ctx as currently being processed.
99 ctx->status = (flags & HASH_LAST) ?
100 (HASH_CTX_STS) (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_LAST) :
101 HASH_CTX_STS_PROCESSING;
102
103 // Advance byte counter
104 ctx->total_length += len;
105
106 // If there is anything currently buffered in the extra blocks, append to it until it contains a whole block.
107 // Or if the user's buffer contains less than a whole block, append as much as possible to the extra block.
108 if ((ctx->partial_block_buffer_length) | (len < SHA512_BLOCK_SIZE)) {
109 // Compute how many bytes to copy from user buffer into extra block
110 uint32_t copy_len = SHA512_BLOCK_SIZE - ctx->partial_block_buffer_length;
111 if (len < copy_len)
112 copy_len = len;
113
114 if (copy_len) {
115 // Copy and update relevant pointers and counters
116 memcpy_varlen(&ctx->partial_block_buffer
117 [ctx->partial_block_buffer_length], buffer, copy_len);
118
119 ctx->partial_block_buffer_length += copy_len;
120 ctx->incoming_buffer = (const void *)((const char *)buffer + copy_len);
121 ctx->incoming_buffer_length = len - copy_len;
122 }
123 // The extra block should never contain more than 1 block here
124 assert(ctx->partial_block_buffer_length <= SHA512_BLOCK_SIZE);
125
126 // If the extra block buffer contains exactly 1 block, it can be hashed.
127 if (ctx->partial_block_buffer_length >= SHA512_BLOCK_SIZE) {
128 ctx->partial_block_buffer_length = 0;
129
130 ctx->job.buffer = ctx->partial_block_buffer;
131 ctx->job.len = 1;
132
133 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx2(&mgr->mgr,
134 &ctx->job);
135 }
136 }
137
138 return sha512_ctx_mgr_resubmit(mgr, ctx);
139}
140
141SHA512_HASH_CTX *sha512_ctx_mgr_flush_avx2(SHA512_HASH_CTX_MGR * mgr)
142{
143 SHA512_HASH_CTX *ctx;
144
145 while (1) {
146 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_flush_avx2(&mgr->mgr);
147
148 // If flush returned 0, there are no more jobs in flight.
149 if (!ctx)
150 return NULL;
151
152 // If flush returned a job, verify that it is safe to return to the user.
153 // If it is not ready, resubmit the job to finish processing.
154 ctx = sha512_ctx_mgr_resubmit(mgr, ctx);
155
156 // If sha512_ctx_mgr_resubmit returned a job, it is ready to be returned.
157 if (ctx)
158 return ctx;
159
160 // Otherwise, all jobs currently being managed by the SHA512_HASH_CTX_MGR still need processing. Loop.
161 }
162}
163
164static SHA512_HASH_CTX *sha512_ctx_mgr_resubmit(SHA512_HASH_CTX_MGR * mgr,
165 SHA512_HASH_CTX * ctx)
166{
167 while (ctx) {
168 if (ctx->status & HASH_CTX_STS_COMPLETE) {
169 ctx->status = HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
170 return ctx;
171 }
172 // If the extra blocks are empty, begin hashing what remains in the user's buffer.
173 if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
174 const void *buffer = ctx->incoming_buffer;
175 uint32_t len = ctx->incoming_buffer_length;
176
177 // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
178 uint32_t copy_len = len & (SHA512_BLOCK_SIZE - 1);
179
180 if (copy_len) {
181 len -= copy_len;
182 memcpy_varlen(ctx->partial_block_buffer,
183 ((const char *)buffer + len), copy_len);
184 ctx->partial_block_buffer_length = copy_len;
185 }
186
187 ctx->incoming_buffer_length = 0;
188
189 // len should be a multiple of the block size now
190 assert((len % SHA512_BLOCK_SIZE) == 0);
191
192 // Set len to the number of blocks to be hashed in the user's buffer
193 len >>= SHA512_LOG2_BLOCK_SIZE;
194
195 if (len) {
196 ctx->job.buffer = (uint8_t *) buffer;
197 ctx->job.len = len;
198 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx2(&mgr->mgr,
199 &ctx->job);
200 continue;
201 }
202 }
203 // If the extra blocks are not empty, then we are either on the last block(s)
204 // or we need more user input before continuing.
205 if (ctx->status & HASH_CTX_STS_LAST) {
206 uint8_t *buf = ctx->partial_block_buffer;
207 uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
208
209 ctx->status =
210 (HASH_CTX_STS) (HASH_CTX_STS_PROCESSING | HASH_CTX_STS_COMPLETE);
211 ctx->job.buffer = buf;
212 ctx->job.len = (uint32_t) n_extra_blocks;
213 ctx = (SHA512_HASH_CTX *) sha512_mb_mgr_submit_avx2(&mgr->mgr,
214 &ctx->job);
215 continue;
216 }
217
218 if (ctx)
219 ctx->status = HASH_CTX_STS_IDLE;
220 return ctx;
221 }
222
223 return NULL;
224}
225
226static inline void hash_init_digest(SHA512_WORD_T * digest)
227{
228 static const SHA512_WORD_T hash_initial_digest[SHA512_DIGEST_NWORDS] =
229 { SHA512_INITIAL_DIGEST };
230 memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
231}
232
1e59de90 233static inline uint32_t hash_pad(uint8_t padblock[SHA512_BLOCK_SIZE * 2], uint64_t total_len)
7c673cae 234{
1e59de90 235 uint32_t i = (uint32_t) (total_len & (SHA512_BLOCK_SIZE - 1));
7c673cae
FG
236
237 memclr_fixedlen(&padblock[i], SHA512_BLOCK_SIZE);
238 padblock[i] = 0x80;
239
240 // Move i to the end of either 1st or 2nd extra block depending on length
241 i += ((SHA512_BLOCK_SIZE - 1) & (0 - (total_len + SHA512_PADLENGTHFIELD_SIZE + 1))) +
242 1 + SHA512_PADLENGTHFIELD_SIZE;
243
244#if SHA512_PADLENGTHFIELD_SIZE == 16
245 *((uint64_t *) & padblock[i - 16]) = 0;
246#endif
247
1e59de90 248 *((uint64_t *) & padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
7c673cae
FG
249
250 return i >> SHA512_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
251}
252
253struct slver {
254 uint16_t snum;
255 uint8_t ver;
256 uint8_t core;
257};
258struct slver sha512_ctx_mgr_init_avx2_slver_04020169;
259struct slver sha512_ctx_mgr_init_avx2_slver = { 0x0169, 0x02, 0x04 };
260
261struct slver sha512_ctx_mgr_submit_avx2_slver_04020170;
262struct slver sha512_ctx_mgr_submit_avx2_slver = { 0x0170, 0x02, 0x04 };
263
264struct slver sha512_ctx_mgr_flush_avx2_slver_04020171;
265struct slver sha512_ctx_mgr_flush_avx2_slver = { 0x0171, 0x02, 0x04 };
1e59de90
TL
266
267#if defined(__clang__)
268# pragma clang attribute pop
269#endif