summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/sha256.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/cr50/dcrypto/sha256.c')
-rw-r--r--board/cr50/dcrypto/sha256.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/board/cr50/dcrypto/sha256.c b/board/cr50/dcrypto/sha256.c
new file mode 100644
index 0000000000..f127ab445a
--- /dev/null
+++ b/board/cr50/dcrypto/sha256.c
@@ -0,0 +1,195 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dcrypto.h"
+#include "internal.h"
+#include "registers.h"
+#include "util.h"
+
+#include "cryptoc/sha256.h"
+
+static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx);
+static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx);
+
+#ifdef SECTION_IS_RO
+/* RO is single threaded. */
+#define mutex_lock(x)
+#define mutex_unlock(x)
+static inline int dcrypto_grab_sha_hw(void)
+{
+ return 1;
+}
+static inline void dcrypto_release_sha_hw(void)
+{
+}
+#else
+#include "task.h"
+static struct mutex hw_busy_mutex;
+
+static int hw_busy;
+
+int dcrypto_grab_sha_hw(void)
+{
+ int rv = 0;
+
+ mutex_lock(&hw_busy_mutex);
+ if (!hw_busy) {
+ rv = 1;
+ hw_busy = 1;
+ }
+ mutex_unlock(&hw_busy_mutex);
+
+ return rv;
+}
+
+void dcrypto_release_sha_hw(void)
+{
+ mutex_lock(&hw_busy_mutex);
+ hw_busy = 0;
+ mutex_unlock(&hw_busy_mutex);
+}
+
+#endif /* ! SECTION_IS_RO */
+
+void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest)
+{
+ int i;
+ const int digest_len = (mode == SHA1_MODE) ?
+ SHA_DIGEST_SIZE :
+ SHA256_DIGEST_SIZE;
+
+ /* Stop LIVESTREAM mode. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK;
+
+ /* Wait for SHA DONE interrupt. */
+ while (!GREG32(KEYMGR, SHA_ITOP))
+ ;
+
+ /* Read out final digest. */
+ for (i = 0; i < digest_len / 4; ++i)
+ *digest++ = GR_KEYMGR_SHA_HASH(i);
+ dcrypto_release_sha_hw();
+}
+
+/* Hardware SHA implementation. */
+static const HASH_VTAB HW_SHA256_VTAB = {
+ dcrypto_sha256_init,
+ dcrypto_sha_update,
+ dcrypto_sha256_final,
+ DCRYPTO_SHA256_hash,
+ SHA256_DIGEST_SIZE
+};
+
+void dcrypto_sha_hash(enum sha_mode mode, const uint8_t *data, uint32_t n,
+ uint8_t *digest)
+{
+ dcrypto_sha_init(mode);
+ dcrypto_sha_update(NULL, data, n);
+ dcrypto_sha_wait(mode, (uint32_t *) digest);
+}
+
+void dcrypto_sha_update(struct HASH_CTX *unused,
+ const void *data, uint32_t n)
+{
+ const uint8_t *bp = (const uint8_t *) data;
+ const uint32_t *wp;
+
+ /* Feed unaligned start bytes. */
+ while (n != 0 && ((uint32_t)bp & 3)) {
+ GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++;
+ n -= 1;
+ }
+
+ /* Feed groups of aligned words. */
+ wp = (uint32_t *)bp;
+ while (n >= 8*4) {
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ n -= 8*4;
+ }
+ /* Feed individual aligned words. */
+ while (n >= 4) {
+ GREG32(KEYMGR, SHA_INPUT_FIFO) = *wp++;
+ n -= 4;
+ }
+
+ /* Feed remaing bytes. */
+ bp = (uint8_t *) wp;
+ while (n != 0) {
+ GREG8(KEYMGR, SHA_INPUT_FIFO) = *bp++;
+ n -= 1;
+ }
+}
+
+void dcrypto_sha_init(enum sha_mode mode)
+{
+ int val;
+
+ /* Stop LIVESTREAM mode, in case final() was not called. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_STOP_MASK;
+ /* Clear interrupt status. */
+ GREG32(KEYMGR, SHA_ITOP) = 0;
+
+ /* Enable streaming mode. */
+ val = GC_KEYMGR_SHA_CFG_EN_LIVESTREAM_MASK;
+ /* Enable SHA DONE interrupt. */
+ val |= GC_KEYMGR_SHA_CFG_EN_INT_EN_DONE_MASK;
+ /* Select SHA mode. */
+ if (mode == SHA1_MODE)
+ val |= GC_KEYMGR_SHA_CFG_EN_SHA1_MASK;
+ GREG32(KEYMGR, SHA_CFG_EN) = val;
+
+ /* Turn off random nops (which are enabled by default). */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 0);
+ /* Configure random nop percentage at 12%. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, FREQ, 2);
+ /* Now turn on random nops. */
+ GWRITE_FIELD(KEYMGR, SHA_RAND_STALL_CTL, STALL_EN, 1);
+
+ /* Start SHA engine. */
+ GREG32(KEYMGR, SHA_TRIG) = GC_KEYMGR_SHA_TRIG_TRIG_GO_MASK;
+}
+
+static void dcrypto_sha256_init(LITE_SHA256_CTX *ctx)
+{
+ ctx->f = &HW_SHA256_VTAB;
+ dcrypto_sha_init(SHA256_MODE);
+}
+
+/* Requires dcrypto_grab_sha_hw() to be called first. */
+void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required)
+{
+ if (!sw_required && dcrypto_grab_sha_hw())
+ dcrypto_sha256_init(ctx);
+#ifndef SECTION_IS_RO
+ else
+ SHA256_init(ctx);
+#endif
+}
+
+static const uint8_t *dcrypto_sha256_final(LITE_SHA256_CTX *ctx)
+{
+ dcrypto_sha_wait(SHA256_MODE, (uint32_t *) ctx->buf);
+ return ctx->buf;
+}
+
+const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n,
+ uint8_t *digest)
+{
+ if (dcrypto_grab_sha_hw())
+ /* dcrypto_sha_wait() will release the hw. */
+ dcrypto_sha_hash(SHA256_MODE, data, n, digest);
+#ifndef SECTION_IS_RO
+ else
+ SHA256_hash(data, n, digest);
+#endif
+ return digest;
+}