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