~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plat/gxb/sha2.c')
-rw-r--r--plat/gxb/sha2.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/plat/gxb/sha2.c b/plat/gxb/sha2.c
new file mode 100644
index 0000000..0ccf5bd
--- /dev/null
+++ b/plat/gxb/sha2.c
@@ -0,0 +1,416 @@
+
+/*
+ * arch/arm/cpu/armv8/common/firmware/plat/gxb/sha2.c
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <asm/arch/romboot.h>
+#include <string.h>
+#include <io.h>
+#include <platform_def.h>
+#include <sha2.h>
+#include <asm/arch/secure_apb.h>
+#include <ndma_utils.h>
+
+#define CONFIG_AML_SHA2_HW_DMA
+
+static sha2_ctx *cur_ctx;
+static void hw_init(uint32_t is224)
+{
+ uint32_t i, tmp;
+ uint32_t state[10];
+ if (is224 == 0) {
+ /* SHA-256 */
+ state[7] = 0x6A09E667;
+ state[6] = 0xBB67AE85;
+ state[5] = 0x3C6EF372;
+ state[4] = 0xA54FF53A;
+ state[3] = 0x510E527F;
+ state[2] = 0x9B05688C;
+ state[1] = 0x1F83D9AB;
+ state[0] = 0x5BE0CD19;
+ }
+ else {
+ /* SHA-224 */
+ state[7] = 0xC1059ED8;
+ state[6] = 0x367CD507;
+ state[5] = 0x3070DD17;
+ state[4] = 0xF70E5939;
+ state[3] = 0xFFC00B31;
+ state[2] = 0x68581511;
+ state[1] = 0x64F98FA7;
+ state[0] = 0xBEFA4FA4;
+ }
+
+ state[8] = 0;
+ state[9] = 0;
+
+ tmp = readl(SEC_SEC_BLKMV_GEN_REG0);
+ tmp &= ~((3 << 12) | (0xf << 8) | (0xf << 4));
+ tmp |= (1 << 12) | (0xa << 8) | (4 << 4);
+ writel(tmp, (int *)SEC_SEC_BLKMV_GEN_REG0);
+
+ writel((0 << 21) | // last wdata
+ (0 << 20) | // last block
+ (3 << 18) | // byte transfer count
+ ((is224 ? 3 : 2) << 16) | // SHA mode
+ (0 << 12) | // out endian
+ (0 << 8) | // in endian
+ (0 << 4) | //
+ (0 << 4) | //
+ (1 << 3) | // enable
+ (0 << 2) | //
+ (0 << 1) | //
+ (1 << 0), // enable SHA PIO data engine
+ SEC_SEC_BLKMV_SHA_CONTROL);
+
+ // sha=5
+ writel((1 << 4) | 5, SEC_SEC_BLKMV_PIO_CNTL0);
+ while (((readl(SEC_SEC_BLKMV_PIO_CNTL0) >> 31) & 1) == 0)
+ ;
+
+ // initial
+ for (i = 0; i < 10; i++)
+ writel(state[i], (long)(SEC_SEC_BLKMV_PIO_DATA0 + i * 4));
+}
+
+static void hw_update(const uint8_t *input, uint32_t ilen, uint8_t last_update)
+{
+ uint32_t bytes, left, tmp;
+ uint32_t *p;
+
+ if (!last_update && (ilen % 64)) {
+ serial_puts("Err:sha\n");
+ // sha2 usage problem
+ return;
+ }
+
+ // block
+ p = (uint32_t *)input;
+ while (ilen > 0) {
+ if (ilen >= 64) {
+ bytes = 64;
+ ilen -= 64;
+ }
+ else {
+ bytes = ilen;
+ ilen = 0;
+ }
+
+ while (bytes > 0) {
+ if (bytes >= 4) {
+ left = 4;
+ bytes -= 4;
+ }
+ else {
+ left = bytes;
+ bytes = 0;
+ }
+
+ if (left < 4) { // last write, last block
+ tmp = readl(SEC_SEC_BLKMV_SHA_CONTROL);
+ tmp &= ~(0xf << 18);
+ tmp |= ((left - 1) << 18) | (3 << 20);
+ writel(tmp, SEC_SEC_BLKMV_SHA_CONTROL);
+ }
+ else if (bytes == 0) { // last write,
+ tmp = readl(SEC_SEC_BLKMV_SHA_CONTROL);
+ tmp &= ~(3 << 20);
+ tmp |= (1 << 21);
+
+ if (last_update && ilen == 0)
+ tmp |= (1 << 20); // last block
+
+ writel(tmp, SEC_SEC_BLKMV_SHA_CONTROL);
+ }
+
+ writel(*p++, SEC_SEC_BLKMV_SHA_PIO_WDATA);
+
+ if (bytes == 0) {
+ while ((readl(SEC_SEC_BLKMV_SHA_CONTROL) >> 31) & 1)
+ ;
+
+ tmp = readl(SEC_SEC_BLKMV_SHA_CONTROL);
+ tmp &= ~(3 << 20);
+ tmp |= (1 << 22);
+ writel(tmp, SEC_SEC_BLKMV_SHA_CONTROL);
+ }
+ }
+ }
+}
+
+static void hw_final(uint8_t output[32])
+{
+ uint32_t *p;
+ uint32_t i;
+ setbits_le32(SEC_SEC_BLKMV_PIO_CNTL0, 1 << 6);
+ clrbits_le32(SEC_SEC_BLKMV_PIO_CNTL0, 1 << 6);
+
+ for (p = (uint32_t *)(output), i = 0; i < 8; i++)
+ *p++ = readl((long)(SEC_SEC_BLKMV_PIO_DATA0 + i * 4));
+}
+
+/**
+ * SHA-2 Family Hash Init
+ *
+ * @param ctx context
+ * @param digest_len digest length in bits (224 or 256)
+ */
+void SHA2_HW_init(sha2_ctx *ctx, uint32_t digest_len)
+{
+ if (cur_ctx != NULL) {
+ serial_puts("Err:sha\n");
+ // sha2 usage problem
+ return;
+ }
+ cur_ctx = ctx;
+
+ hw_init(digest_len == 224);
+
+ ctx->len = 0;
+}
+
+/**
+ * SHA-2 Family Hash Update
+ */
+void SHA2_HW_update(sha2_ctx *ctx, const uint8_t *data, uint32_t len)
+{
+ unsigned int fill_len, data_len, rem_len,offset;
+
+ if (cur_ctx != ctx) {
+ serial_puts("Err:sha\n");
+ // sha2 usage problem
+ return;
+ }
+ /* This method updates the hash for the input data in blocks, except the last
+ * partial|full block, which is saved in ctx->block. The last partial|full
+ * block will be added to the hash in SHA2_final.
+ */
+ data_len = len;
+ offset = 0;
+ /* fill saved block from beginning of input data */
+ if (ctx->len) {
+ fill_len = SHA256_BLOCK_SIZE - ctx->len;
+ memcpy(&ctx->block[ctx->len], data, fill_len);
+ data_len -= fill_len;
+ offset = fill_len;
+ ctx->len += fill_len;
+ }
+ if (ctx->len == SHA256_BLOCK_SIZE && data_len > 0) {
+ /* saved block is full and is not last block, hash it */
+ hw_update(ctx->block, SHA256_BLOCK_SIZE, 0);
+ ctx->len = 0;
+ }
+ if (data_len > SHA256_BLOCK_SIZE) {
+ /* still have more than 1 block. hash up until last [partial|full] block */
+ rem_len = data_len % SHA256_BLOCK_SIZE;
+ if (rem_len == 0) {
+ rem_len = SHA256_BLOCK_SIZE;
+ }
+
+ data_len -= rem_len;
+ hw_update(&data[offset], data_len, 0);
+ offset += data_len;
+ } else {
+ rem_len = data_len;
+ }
+
+ if (rem_len) {
+ /* save the remaining data */
+ memcpy(ctx->block, &data[offset], rem_len);
+ ctx->len = rem_len;
+ }
+}
+
+/**
+ * SHA-2 Family Hash Update
+ *
+ * Returns pointer to ctx->buf containing hash.
+ */
+uint8_t *SHA2_HW_final(sha2_ctx *ctx)
+{
+ if (cur_ctx != ctx) {
+ serial_puts("Err:sha\n");
+ // sha2 usage problem
+ return ctx->buf;
+ }
+ if (ctx->len == 0 || ctx->len > SHA256_BLOCK_SIZE) {
+ serial_puts("Err:sha\n");
+ // internal sha2 problem
+ return ctx->buf;
+ }
+ hw_update(ctx->block, ctx->len, 1);
+ hw_final(ctx->buf);
+ cur_ctx = NULL;
+ return ctx->buf;
+}
+
+#if defined(CONFIG_AML_SHA2_HW_DMA)
+#define THREAD1_TABLE_LOC 0x5510000
+#define SHA_Wr(addr, data) *(volatile uint32_t *)(addr)=(data)
+#define SHA_Rd(addr) *(volatile uint32_t *)(addr)
+#define SEC_ALLOWED_MASK 0xa // thread 3 and thread 1 are allowed non-secure
+int g_n_sha_Start_flag = 0;
+int g_n_sha_thread_num = 0;
+#endif
+
+void SHA2_init(sha2_ctx *ctx, unsigned int digest_len)
+{
+#if defined(CONFIG_AML_SHA2_HW_DMA)
+
+ unsigned int sha2_256_msg_in[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
+
+ g_n_sha_thread_num = 0; //fixed SHA2 with thread 0
+
+
+ // Setup secure and non-secure transfers
+ // Also set up the general readback of crypto outputs to the SHA engine
+ // assign sec_allowed_mask = sec_gen_reg0[11:8];
+ // wire [1:0] sec_read_sel = sec_gen_reg0[13:12];
+ SHA_Wr(SEC_SEC_BLKMV_GEN_REG0, ((SHA_Rd(SEC_SEC_BLKMV_GEN_REG0) & ~((0x3 << 12) | (0xf << 8))) | (1 << 12) | (SEC_ALLOWED_MASK << 8)) );
+ // Allow secure DDR tranfers for the Secure domains
+ // wire [3:0] sec_ddr_sec_id_en = sec_gen_reg0[7:4]; // Even though a thread is secure, we may not want it to use the DDR secure ID (just in case);
+ SHA_Wr(SEC_SEC_BLKMV_GEN_REG0, ((SHA_Rd(SEC_SEC_BLKMV_GEN_REG0) & ~(0xf << 4)) | (0x4 << 4)) ); // only thread 2 can issue Secure transfers
+
+ // Enable the SHA engine
+ // wire sec_sha_dma_enable = sec_sha_control[3];
+ SHA_Wr( SEC_SEC_BLKMV_SHA_CONTROL, SHA_Rd(SEC_SEC_BLKMV_SHA_CONTROL) | (1 << 3) );
+
+ // For DMA modes, pretend there is a PIO request for the AES (not SHA)
+ // reg pio_granted; // pio_control[31];
+ // wire pio_hold_all = pio_control[5]; // set to 1 to block all in-line processing regardless of the PIO being used
+ // wire pio_request = pio_control[4];
+ // wire [2:0] pio_inline_type = pio_control[2:0];
+ SHA_Wr( SEC_SEC_BLKMV_PIO_CNTL0, (SHA_Rd(SEC_SEC_BLKMV_PIO_CNTL0) & ~((1 << 4) | (0x7 << 0))) | ((1 << 4) | (4 << 0)) ); // Request for AES
+
+ //
+ // Write the initial message and datatlen
+ //
+ // initial the internal CPU fifo write counter for the save/restore engine
+ // wire sec_sha_cpu_save_init = sec_sha_control[6]; // Pulsed
+ // wire [1:0] sec_sha_thread = sec_sha_control[5:4];
+ SHA_Wr( SEC_SEC_BLKMV_SHA_CONTROL, (SHA_Rd(SEC_SEC_BLKMV_SHA_CONTROL) & ~(3 << 4)) | (1 << 6) | (g_n_sha_thread_num << 4) ); // pulse bit (init cpu counters)
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[7] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[6] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[5] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[4] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[3] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[2] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[1] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_MSG_IN, sha2_256_msg_in[0] );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_DATALEN_IN, 0 );
+ SHA_Wr( SEC_SEC_BLKMV_SHA_DMA_DATALEN_IN, 0 );
+
+ memset((void*)THREAD1_TABLE_LOC,0,10*32);
+
+ NDMA_set_table_position_secure( g_n_sha_thread_num, THREAD1_TABLE_LOC, THREAD1_TABLE_LOC + (10*32) ); // 2 thread entries
+ g_n_sha_Start_flag = 0;
+#else
+ SHA2_HW_init(ctx, digest_len);
+#endif
+}
+
+void SHA2_update(sha2_ctx *ctx, const unsigned char *data, unsigned int len)
+{
+
+#if defined(CONFIG_AML_SHA2_HW_DMA)
+
+ if (!len)
+ return;
+
+ NDMA_add_descriptor_sha( g_n_sha_thread_num, // uint32_t thread_num,
+ 1, // uint32_t irq,
+ 2, // uint32_t sha_mode, // 1:sha1;2:sha2-256;3:sha2_224
+ 0, // uint32_t pre_endian,
+ len, // uint32_t bytes_to_move,
+ (uint32_t)(unsigned long)data, // uint32_t src_addr,
+ 0 ); // uint32_t last_block,
+ if (!g_n_sha_Start_flag)
+ {
+ NDMA_start(g_n_sha_thread_num);
+ g_n_sha_Start_flag = 1;
+ }
+#else
+ SHA2_HW_update(ctx, data, len);
+#endif
+}
+
+void SHA2_final(sha2_ctx *ctx,const unsigned char *data, unsigned int len)
+{
+#if defined(CONFIG_AML_SHA2_HW_DMA)
+ unsigned int *pOUT = (unsigned int *)(unsigned char *)ctx->buf;
+
+ NDMA_add_descriptor_sha( g_n_sha_thread_num, // uint32_t thread_num,
+ 1, // uint32_t irq,
+ 2, // uint32_t sha_mode, // 1:sha1;2:sha2-256;3:sha2_224
+ 0, // uint32_t pre_endian,
+ len, // uint32_t bytes_to_move,
+ (uint32_t)(unsigned long)data, // uint32_t src_addr,
+ 1 ); // uint32_t last_block,
+
+ if (!g_n_sha_Start_flag)
+ {
+ NDMA_start(g_n_sha_thread_num);
+ g_n_sha_Start_flag = 1;
+ }
+
+ NDMA_wait_for_completion(g_n_sha_thread_num);
+ NDMA_stop(g_n_sha_thread_num);
+ g_n_sha_Start_flag = 0;
+
+ pOUT[0] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA0);
+ pOUT[1] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA1);
+ pOUT[2] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA2);
+ pOUT[3] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA3);
+ pOUT[4] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA4);
+ pOUT[5] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA5);
+ pOUT[6] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA6);
+ pOUT[7] = SHA_Rd(SEC_SEC_BLKMV_PIO_DATA7);
+
+#else
+ SHA2_HW_update(ctx, data, len);
+ SHA2_HW_final(ctx);
+#endif
+
+}
+
+
+void sha2(const uint8_t *input, unsigned int ilen, unsigned char output[32], unsigned int is224)
+{
+ sha2_ctx sha_ctx;
+ unsigned long nSRCAddr = (unsigned long)input;
+
+ if (((nSRCAddr >> 24) & (0xFF)) == 0xD9)
+ {
+ //serial_puts("aml log : PIO SHA\n");
+ SHA2_HW_init(&sha_ctx, is224 ? 224: 256);
+ SHA2_HW_update(&sha_ctx, input, ilen);
+ SHA2_HW_final(&sha_ctx);
+
+ }
+ else
+ {
+ //serial_puts("aml log : DMA SHA\n");
+ SHA2_init( &sha_ctx, is224 ? 224: 256);
+ SHA2_final( &sha_ctx, input,ilen);
+ }
+ memcpy(output,sha_ctx.buf,32);
+}