16df3ef80SGreg Tucker /**********************************************************************
26df3ef80SGreg Tucker Copyright(c) 2011-2016 Intel Corporation All rights reserved.
36df3ef80SGreg Tucker
46df3ef80SGreg Tucker Redistribution and use in source and binary forms, with or without
56df3ef80SGreg Tucker modification, are permitted provided that the following conditions
66df3ef80SGreg Tucker are met:
76df3ef80SGreg Tucker * Redistributions of source code must retain the above copyright
86df3ef80SGreg Tucker notice, this list of conditions and the following disclaimer.
96df3ef80SGreg Tucker * Redistributions in binary form must reproduce the above copyright
106df3ef80SGreg Tucker notice, this list of conditions and the following disclaimer in
116df3ef80SGreg Tucker the documentation and/or other materials provided with the
126df3ef80SGreg Tucker distribution.
136df3ef80SGreg Tucker * Neither the name of Intel Corporation nor the names of its
146df3ef80SGreg Tucker contributors may be used to endorse or promote products derived
156df3ef80SGreg Tucker from this software without specific prior written permission.
166df3ef80SGreg Tucker
176df3ef80SGreg Tucker THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186df3ef80SGreg Tucker "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196df3ef80SGreg Tucker LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206df3ef80SGreg Tucker A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216df3ef80SGreg Tucker OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226df3ef80SGreg Tucker SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236df3ef80SGreg Tucker LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246df3ef80SGreg Tucker DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256df3ef80SGreg Tucker THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266df3ef80SGreg Tucker (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276df3ef80SGreg Tucker OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286df3ef80SGreg Tucker **********************************************************************/
296df3ef80SGreg Tucker
303c423071SPablo de Lara #include "sha256_mb_internal.h"
316df3ef80SGreg Tucker #include "memcpy_inline.h"
3292aa5aa4SGreg Tucker #include "endian_helper.h"
336df3ef80SGreg Tucker
346df3ef80SGreg Tucker #ifdef _MSC_VER
356df3ef80SGreg Tucker #include <intrin.h>
366df3ef80SGreg Tucker #define inline __inline
376df3ef80SGreg Tucker #endif
386df3ef80SGreg Tucker
399ba6f238SMarcel Cornu static inline void
40*0a437795SPablo de Lara hash_init_digest(ISAL_SHA256_WORD_T *digest);
419ba6f238SMarcel Cornu static inline uint32_t
42*0a437795SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2], uint64_t total_len);
43*0a437795SPablo de Lara static ISAL_SHA256_HASH_CTX *
44*0a437795SPablo de Lara sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx);
456df3ef80SGreg Tucker
469ba6f238SMarcel Cornu void
_sha256_ctx_mgr_init_sse(ISAL_SHA256_HASH_CTX_MGR * mgr)47*0a437795SPablo de Lara _sha256_ctx_mgr_init_sse(ISAL_SHA256_HASH_CTX_MGR *mgr)
486df3ef80SGreg Tucker {
493c423071SPablo de Lara _sha256_mb_mgr_init_sse(&mgr->mgr);
506df3ef80SGreg Tucker }
516df3ef80SGreg Tucker
52*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *
_sha256_ctx_mgr_submit_sse(ISAL_SHA256_HASH_CTX_MGR * mgr,ISAL_SHA256_HASH_CTX * ctx,const void * buffer,uint32_t len,ISAL_HASH_CTX_FLAG flags)53*0a437795SPablo de Lara _sha256_ctx_mgr_submit_sse(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx,
54*0a437795SPablo de Lara const void *buffer, uint32_t len, ISAL_HASH_CTX_FLAG flags)
556df3ef80SGreg Tucker {
566df3ef80SGreg Tucker
578cb7fe78SPablo de Lara if (flags & (~ISAL_HASH_ENTIRE)) {
586df3ef80SGreg Tucker // User should not pass anything other than FIRST, UPDATE, or LAST
598cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_INVALID_FLAGS;
606df3ef80SGreg Tucker return ctx;
616df3ef80SGreg Tucker }
626df3ef80SGreg Tucker
638cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_PROCESSING) {
646df3ef80SGreg Tucker // Cannot submit to a currently processing job.
658cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_PROCESSING;
666df3ef80SGreg Tucker return ctx;
676df3ef80SGreg Tucker }
686df3ef80SGreg Tucker
698cb7fe78SPablo de Lara if ((ctx->status & ISAL_HASH_CTX_STS_COMPLETE) && !(flags & ISAL_HASH_FIRST)) {
706df3ef80SGreg Tucker // Cannot update a finished job.
718cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_COMPLETED;
726df3ef80SGreg Tucker return ctx;
736df3ef80SGreg Tucker }
746df3ef80SGreg Tucker
758cb7fe78SPablo de Lara if (flags & ISAL_HASH_FIRST) {
766df3ef80SGreg Tucker // Init digest
776df3ef80SGreg Tucker hash_init_digest(ctx->job.result_digest);
786df3ef80SGreg Tucker
796df3ef80SGreg Tucker // Reset byte counter
806df3ef80SGreg Tucker ctx->total_length = 0;
816df3ef80SGreg Tucker
826df3ef80SGreg Tucker // Clear extra blocks
836df3ef80SGreg Tucker ctx->partial_block_buffer_length = 0;
846df3ef80SGreg Tucker }
856df3ef80SGreg Tucker // If we made it here, there were no errors during this call to submit
868cb7fe78SPablo de Lara ctx->error = ISAL_HASH_CTX_ERROR_NONE;
876df3ef80SGreg Tucker
886df3ef80SGreg Tucker // Store buffer ptr info from user
896df3ef80SGreg Tucker ctx->incoming_buffer = buffer;
906df3ef80SGreg Tucker ctx->incoming_buffer_length = len;
916df3ef80SGreg Tucker
926df3ef80SGreg Tucker // Store the user's request flags and mark this ctx as currently being processed.
938cb7fe78SPablo de Lara ctx->status = (flags & ISAL_HASH_LAST) ? (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
948cb7fe78SPablo de Lara ISAL_HASH_CTX_STS_LAST)
958cb7fe78SPablo de Lara : ISAL_HASH_CTX_STS_PROCESSING;
966df3ef80SGreg Tucker
976df3ef80SGreg Tucker // Advance byte counter
986df3ef80SGreg Tucker ctx->total_length += len;
996df3ef80SGreg Tucker
1009ba6f238SMarcel Cornu // If there is anything currently buffered in the extra blocks, append to it until it
1019ba6f238SMarcel Cornu // contains a whole block. Or if the user's buffer contains less than a whole block, append
1029ba6f238SMarcel Cornu // as much as possible to the extra block.
103*0a437795SPablo de Lara if ((ctx->partial_block_buffer_length) | (len < ISAL_SHA256_BLOCK_SIZE)) {
1046df3ef80SGreg Tucker // Compute how many bytes to copy from user buffer into extra block
105*0a437795SPablo de Lara uint32_t copy_len = ISAL_SHA256_BLOCK_SIZE - ctx->partial_block_buffer_length;
1066df3ef80SGreg Tucker if (len < copy_len)
1076df3ef80SGreg Tucker copy_len = len;
1086df3ef80SGreg Tucker
1096df3ef80SGreg Tucker if (copy_len) {
1106df3ef80SGreg Tucker // Copy and update relevant pointers and counters
1119ba6f238SMarcel Cornu memcpy_varlen(&ctx->partial_block_buffer[ctx->partial_block_buffer_length],
1129ba6f238SMarcel Cornu buffer, copy_len);
1136df3ef80SGreg Tucker
1146df3ef80SGreg Tucker ctx->partial_block_buffer_length += copy_len;
1156df3ef80SGreg Tucker ctx->incoming_buffer = (const void *) ((const char *) buffer + copy_len);
1166df3ef80SGreg Tucker ctx->incoming_buffer_length = len - copy_len;
1176df3ef80SGreg Tucker }
1186df3ef80SGreg Tucker // The extra block should never contain more than 1 block here
119*0a437795SPablo de Lara assert(ctx->partial_block_buffer_length <= ISAL_SHA256_BLOCK_SIZE);
1206df3ef80SGreg Tucker
1216df3ef80SGreg Tucker // If the extra block buffer contains exactly 1 block, it can be hashed.
122*0a437795SPablo de Lara if (ctx->partial_block_buffer_length >= ISAL_SHA256_BLOCK_SIZE) {
1236df3ef80SGreg Tucker ctx->partial_block_buffer_length = 0;
1246df3ef80SGreg Tucker
1256df3ef80SGreg Tucker ctx->job.buffer = ctx->partial_block_buffer;
1266df3ef80SGreg Tucker ctx->job.len = 1;
127*0a437795SPablo de Lara ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_sse(&mgr->mgr,
128*0a437795SPablo de Lara &ctx->job);
1296df3ef80SGreg Tucker }
1306df3ef80SGreg Tucker }
1316df3ef80SGreg Tucker
1326df3ef80SGreg Tucker return sha256_ctx_mgr_resubmit(mgr, ctx);
1336df3ef80SGreg Tucker }
1346df3ef80SGreg Tucker
135*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *
_sha256_ctx_mgr_flush_sse(ISAL_SHA256_HASH_CTX_MGR * mgr)136*0a437795SPablo de Lara _sha256_ctx_mgr_flush_sse(ISAL_SHA256_HASH_CTX_MGR *mgr)
1376df3ef80SGreg Tucker {
138*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *ctx;
1396df3ef80SGreg Tucker
1406df3ef80SGreg Tucker while (1) {
141*0a437795SPablo de Lara ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_flush_sse(&mgr->mgr);
1426df3ef80SGreg Tucker
1436df3ef80SGreg Tucker // If flush returned 0, there are no more jobs in flight.
1446df3ef80SGreg Tucker if (!ctx)
1456df3ef80SGreg Tucker return NULL;
1466df3ef80SGreg Tucker
1476df3ef80SGreg Tucker // If flush returned a job, verify that it is safe to return to the user.
1486df3ef80SGreg Tucker // If it is not ready, resubmit the job to finish processing.
1496df3ef80SGreg Tucker ctx = sha256_ctx_mgr_resubmit(mgr, ctx);
1506df3ef80SGreg Tucker
1516df3ef80SGreg Tucker // If sha256_ctx_mgr_resubmit returned a job, it is ready to be returned.
1526df3ef80SGreg Tucker if (ctx)
1536df3ef80SGreg Tucker return ctx;
1546df3ef80SGreg Tucker
155*0a437795SPablo de Lara // Otherwise, all jobs currently being managed by the ISAL_SHA256_HASH_CTX_MGR still
156*0a437795SPablo de Lara // need processing. Loop.
1576df3ef80SGreg Tucker }
1586df3ef80SGreg Tucker }
1596df3ef80SGreg Tucker
160*0a437795SPablo de Lara static ISAL_SHA256_HASH_CTX *
sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR * mgr,ISAL_SHA256_HASH_CTX * ctx)161*0a437795SPablo de Lara sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx)
1626df3ef80SGreg Tucker {
1636df3ef80SGreg Tucker while (ctx) {
1648cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_COMPLETE) {
1658cb7fe78SPablo de Lara ctx->status = ISAL_HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
1666df3ef80SGreg Tucker return ctx;
1676df3ef80SGreg Tucker }
1686df3ef80SGreg Tucker // If the extra blocks are empty, begin hashing what remains in the user's buffer.
1696df3ef80SGreg Tucker if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
1706df3ef80SGreg Tucker const void *buffer = ctx->incoming_buffer;
1716df3ef80SGreg Tucker uint32_t len = ctx->incoming_buffer_length;
1726df3ef80SGreg Tucker
1736df3ef80SGreg Tucker // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
174*0a437795SPablo de Lara uint32_t copy_len = len & (ISAL_SHA256_BLOCK_SIZE - 1);
1756df3ef80SGreg Tucker
1766df3ef80SGreg Tucker if (copy_len) {
1776df3ef80SGreg Tucker len -= copy_len;
1786df3ef80SGreg Tucker memcpy_varlen(ctx->partial_block_buffer,
1796df3ef80SGreg Tucker ((const char *) buffer + len), copy_len);
1806df3ef80SGreg Tucker ctx->partial_block_buffer_length = copy_len;
1816df3ef80SGreg Tucker }
1826df3ef80SGreg Tucker
1836df3ef80SGreg Tucker ctx->incoming_buffer_length = 0;
1846df3ef80SGreg Tucker
1856df3ef80SGreg Tucker // len should be a multiple of the block size now
186*0a437795SPablo de Lara assert((len % ISAL_SHA256_BLOCK_SIZE) == 0);
1876df3ef80SGreg Tucker
1886df3ef80SGreg Tucker // Set len to the number of blocks to be hashed in the user's buffer
189*0a437795SPablo de Lara len >>= ISAL_SHA256_LOG2_BLOCK_SIZE;
1906df3ef80SGreg Tucker
1916df3ef80SGreg Tucker if (len) {
1926df3ef80SGreg Tucker ctx->job.buffer = (uint8_t *) buffer;
1936df3ef80SGreg Tucker ctx->job.len = len;
194*0a437795SPablo de Lara ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_sse(&mgr->mgr,
1956df3ef80SGreg Tucker &ctx->job);
1966df3ef80SGreg Tucker continue;
1976df3ef80SGreg Tucker }
1986df3ef80SGreg Tucker }
1996df3ef80SGreg Tucker // If the extra blocks are not empty, then we are either on the last block(s)
2006df3ef80SGreg Tucker // or we need more user input before continuing.
2018cb7fe78SPablo de Lara if (ctx->status & ISAL_HASH_CTX_STS_LAST) {
2026df3ef80SGreg Tucker uint8_t *buf = ctx->partial_block_buffer;
2036df3ef80SGreg Tucker uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
2046df3ef80SGreg Tucker
2058cb7fe78SPablo de Lara ctx->status = (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
2068cb7fe78SPablo de Lara ISAL_HASH_CTX_STS_COMPLETE);
2076df3ef80SGreg Tucker ctx->job.buffer = buf;
2086df3ef80SGreg Tucker ctx->job.len = (uint32_t) n_extra_blocks;
2096df3ef80SGreg Tucker
210*0a437795SPablo de Lara ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_sse(&mgr->mgr,
211*0a437795SPablo de Lara &ctx->job);
2126df3ef80SGreg Tucker continue;
2136df3ef80SGreg Tucker }
2146df3ef80SGreg Tucker
2156df3ef80SGreg Tucker if (ctx)
2168cb7fe78SPablo de Lara ctx->status = ISAL_HASH_CTX_STS_IDLE;
2176df3ef80SGreg Tucker return ctx;
2186df3ef80SGreg Tucker }
2196df3ef80SGreg Tucker
2206df3ef80SGreg Tucker return NULL;
2216df3ef80SGreg Tucker }
2226df3ef80SGreg Tucker
2239ba6f238SMarcel Cornu static inline void
hash_init_digest(ISAL_SHA256_WORD_T * digest)224*0a437795SPablo de Lara hash_init_digest(ISAL_SHA256_WORD_T *digest)
2256df3ef80SGreg Tucker {
226*0a437795SPablo de Lara static const ISAL_SHA256_WORD_T hash_initial_digest[ISAL_SHA256_DIGEST_NWORDS] = {
227*0a437795SPablo de Lara ISAL_SHA256_INITIAL_DIGEST
2289ba6f238SMarcel Cornu };
2296df3ef80SGreg Tucker memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
2306df3ef80SGreg Tucker }
2316df3ef80SGreg Tucker
2329ba6f238SMarcel Cornu static inline uint32_t
hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2],uint64_t total_len)233*0a437795SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2], uint64_t total_len)
2346df3ef80SGreg Tucker {
235*0a437795SPablo de Lara uint32_t i = (uint32_t) (total_len & (ISAL_SHA256_BLOCK_SIZE - 1));
2366df3ef80SGreg Tucker
237*0a437795SPablo de Lara memclr_fixedlen(&padblock[i], ISAL_SHA256_BLOCK_SIZE);
2386df3ef80SGreg Tucker padblock[i] = 0x80;
2396df3ef80SGreg Tucker
2406df3ef80SGreg Tucker // Move i to the end of either 1st or 2nd extra block depending on length
241*0a437795SPablo de Lara i += ((ISAL_SHA256_BLOCK_SIZE - 1) &
242*0a437795SPablo de Lara (0 - (total_len + ISAL_SHA256_PADLENGTHFIELD_SIZE + 1))) +
243*0a437795SPablo de Lara 1 + ISAL_SHA256_PADLENGTHFIELD_SIZE;
2446df3ef80SGreg Tucker
245*0a437795SPablo de Lara #if ISAL_SHA256_PADLENGTHFIELD_SIZE == 16
2466df3ef80SGreg Tucker *((uint64_t *) &padblock[i - 16]) = 0;
2476df3ef80SGreg Tucker #endif
2486df3ef80SGreg Tucker
249e3f7d4fbSUlrich Weigand *((uint64_t *) &padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
2506df3ef80SGreg Tucker
251*0a437795SPablo de Lara return i >> ISAL_SHA256_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
2526df3ef80SGreg Tucker }
2536df3ef80SGreg Tucker
2546df3ef80SGreg Tucker struct slver {
2556df3ef80SGreg Tucker uint16_t snum;
2566df3ef80SGreg Tucker uint8_t ver;
2576df3ef80SGreg Tucker uint8_t core;
2586df3ef80SGreg Tucker };
2592fb85107SPablo de Lara struct slver _sha256_ctx_mgr_init_sse_slver_00020151;
2602fb85107SPablo de Lara struct slver _sha256_ctx_mgr_init_sse_slver = { 0x0151, 0x02, 0x00 };
2616df3ef80SGreg Tucker
2622fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_sse_slver_00020152;
2632fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_sse_slver = { 0x0152, 0x02, 0x00 };
2646df3ef80SGreg Tucker
2652fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_sse_slver_00020153;
2662fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_sse_slver = { 0x0153, 0x02, 0x00 };
267