mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-22 19:23:07 +00:00
898 lines
35 KiB
C
898 lines
35 KiB
C
|
// SPDX-License-Identifier: GPL-2.0+
|
||
|
/*
|
||
|
* Copyright (c) 2022 Nuvoton Technology Corp.
|
||
|
*/
|
||
|
|
||
|
#include <common.h>
|
||
|
#include <dm.h>
|
||
|
#include <hash.h>
|
||
|
#include <malloc.h>
|
||
|
#include <uboot_aes.h>
|
||
|
#include <asm/io.h>
|
||
|
|
||
|
#define HASH_DIG_H_NUM 8
|
||
|
|
||
|
#define HASH_CTR_STS_SHA_EN BIT(0)
|
||
|
#define HASH_CTR_STS_SHA_BUSY BIT(1)
|
||
|
#define HASH_CTR_STS_SHA_RST BIT(2)
|
||
|
#define HASH_CFG_SHA1_SHA2 BIT(0)
|
||
|
|
||
|
/* SHA type */
|
||
|
enum npcm_sha_type {
|
||
|
npcm_sha_type_sha2 = 0,
|
||
|
npcm_sha_type_sha1,
|
||
|
npcm_sha_type_num
|
||
|
};
|
||
|
|
||
|
struct npcm_sha_regs {
|
||
|
unsigned int hash_data_in;
|
||
|
unsigned char hash_ctr_sts;
|
||
|
unsigned char reserved_0[0x03];
|
||
|
unsigned char hash_cfg;
|
||
|
unsigned char reserved_1[0x03];
|
||
|
unsigned char hash_ver;
|
||
|
unsigned char reserved_2[0x13];
|
||
|
unsigned int hash_dig[HASH_DIG_H_NUM];
|
||
|
};
|
||
|
|
||
|
struct npcm_sha_priv {
|
||
|
struct npcm_sha_regs *regs;
|
||
|
};
|
||
|
|
||
|
static struct npcm_sha_priv *sha_priv;
|
||
|
|
||
|
#ifdef SHA_DEBUG_MODULE
|
||
|
#define sha_print(fmt, args...) printf(fmt, ##args)
|
||
|
#else
|
||
|
#define sha_print(fmt, args...) (void)0
|
||
|
#endif
|
||
|
|
||
|
#define SHA_BLOCK_LENGTH (512 / 8)
|
||
|
#define SHA_2_HASH_LENGTH (256 / 8)
|
||
|
#define SHA_1_HASH_LENGTH (160 / 8)
|
||
|
#define SHA_HASH_LENGTH(type) ((type == npcm_sha_type_sha2) ? \
|
||
|
(SHA_2_HASH_LENGTH) : (SHA_1_HASH_LENGTH))
|
||
|
|
||
|
#define SHA_SECRUN_BUFF_SIZE 64
|
||
|
#define SHA_TIMEOUT 100
|
||
|
#define SHA_DATA_LAST_BYTE 0x80
|
||
|
|
||
|
#define SHA2_NUM_OF_SELF_TESTS 3
|
||
|
#define SHA1_NUM_OF_SELF_TESTS 4
|
||
|
|
||
|
#define NUVOTON_ALIGNMENT 4
|
||
|
|
||
|
/*-----------------------------------------------------------------------------*/
|
||
|
/* SHA instance struct handler */
|
||
|
/*-----------------------------------------------------------------------------*/
|
||
|
struct SHA_HANDLE_T {
|
||
|
u32 hv[SHA_2_HASH_LENGTH / sizeof(u32)];
|
||
|
u32 length0;
|
||
|
u32 length1;
|
||
|
u32 block[SHA_BLOCK_LENGTH / sizeof(u32)];
|
||
|
u8 type;
|
||
|
bool active;
|
||
|
};
|
||
|
|
||
|
// The # of bytes currently in the sha block buffer
|
||
|
#define SHA_BUFF_POS(length) ((length) & (SHA_BLOCK_LENGTH - 1))
|
||
|
|
||
|
// The # of free bytes in the sha block buffer
|
||
|
#define SHA_BUFF_FREE(length) (SHA_BLOCK_LENGTH - SHA_BUFF_POS(length))
|
||
|
|
||
|
static void SHA_FlushLocalBuffer_l(const u32 *buff);
|
||
|
static int SHA_BusyWait_l(void);
|
||
|
static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type);
|
||
|
static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type);
|
||
|
static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block);
|
||
|
static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block);
|
||
|
static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block);
|
||
|
|
||
|
static int SHA_Init(struct SHA_HANDLE_T *handleptr);
|
||
|
static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type);
|
||
|
static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len);
|
||
|
static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest);
|
||
|
static int SHA_Reset(void);
|
||
|
static int SHA_Power(bool on);
|
||
|
#ifdef SHA_PRINT
|
||
|
static void SHA_PrintRegs(void);
|
||
|
static void SHA_PrintVersion(void);
|
||
|
#endif
|
||
|
|
||
|
static struct SHA_HANDLE_T sha_handle;
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Checks if give function returns int error, and returns the error */
|
||
|
/* immediately after SHA disabling */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
int npcm_sha_check(int status)
|
||
|
{
|
||
|
if (status != 0) {
|
||
|
SHA_Power(false);
|
||
|
return status;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: npcm_sha_calc */
|
||
|
/* */
|
||
|
/* Parameters: type - SHA module type */
|
||
|
/* inBuff - Pointer to a buffer containing the data to */
|
||
|
/* be hashed */
|
||
|
/* len - Length of the data to hash */
|
||
|
/* hashDigest - Pointer to a buffer where the reseulting */
|
||
|
/* digest will be copied to */
|
||
|
/* */
|
||
|
/* Returns: 0 on success or other int error code on error */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine performs complete SHA calculation in one */
|
||
|
/* step */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
int npcm_sha_calc(u8 type, const u8 *inbuff, u32 len, u8 *hashdigest)
|
||
|
{
|
||
|
int status;
|
||
|
struct SHA_HANDLE_T handle;
|
||
|
|
||
|
SHA_Init(&handle);
|
||
|
SHA_Power(true);
|
||
|
SHA_Reset();
|
||
|
SHA_Start(&handle, type);
|
||
|
status = SHA_Update(&handle, inbuff, len);
|
||
|
npcm_sha_check(status);
|
||
|
status = SHA_Finish(&handle, hashdigest);
|
||
|
npcm_sha_check(status);
|
||
|
SHA_Power(false);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Computes hash value of input pbuf using h/w acceleration
|
||
|
*
|
||
|
* @param in_addr A pointer to the input buffer
|
||
|
* @param bufleni Byte length of input buffer
|
||
|
* @param out_addr A pointer to the output buffer. When complete
|
||
|
* 32 bytes are copied to pout[0]...pout[31]. Thus, a user
|
||
|
* should allocate at least 32 bytes at pOut in advance.
|
||
|
* @param chunk_size chunk size for sha256
|
||
|
*/
|
||
|
void hw_sha256(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size)
|
||
|
{
|
||
|
puts("\nhw_sha256 using BMC HW accelerator\t");
|
||
|
npcm_sha_calc(npcm_sha_type_sha2, (u8 *)in_addr, buflen, (u8 *)out_addr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Computes hash value of input pbuf using h/w acceleration
|
||
|
*
|
||
|
* @param in_addr A pointer to the input buffer
|
||
|
* @param bufleni Byte length of input buffer
|
||
|
* @param out_addr A pointer to the output buffer. When complete
|
||
|
* 32 bytes are copied to pout[0]...pout[31]. Thus, a user
|
||
|
* should allocate at least 32 bytes at pOut in advance.
|
||
|
* @param chunk_size chunk_size for sha1
|
||
|
*/
|
||
|
void hw_sha1(const uchar *in_addr, uint buflen, uchar *out_addr, uint chunk_size)
|
||
|
{
|
||
|
puts("\nhw_sha1 using BMC HW accelerator\t");
|
||
|
npcm_sha_calc(npcm_sha_type_sha1, (u8 *)in_addr, buflen, (u8 *)out_addr);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Create the context for sha progressive hashing using h/w acceleration
|
||
|
*
|
||
|
* @algo: Pointer to the hash_algo struct
|
||
|
* @ctxp: Pointer to the pointer of the context for hashing
|
||
|
* @return 0 if ok, -ve on error
|
||
|
*/
|
||
|
int hw_sha_init(struct hash_algo *algo, void **ctxp)
|
||
|
{
|
||
|
const char *algo_name1 = "sha1";
|
||
|
const char *algo_name2 = "sha256";
|
||
|
|
||
|
SHA_Init(&sha_handle);
|
||
|
SHA_Power(true);
|
||
|
SHA_Reset();
|
||
|
if (!strcmp(algo_name1, algo->name))
|
||
|
return SHA_Start(&sha_handle, npcm_sha_type_sha1);
|
||
|
else if (!strcmp(algo_name2, algo->name))
|
||
|
return SHA_Start(&sha_handle, npcm_sha_type_sha2);
|
||
|
else
|
||
|
return -EPROTO;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Update buffer for sha progressive hashing using h/w acceleration
|
||
|
*
|
||
|
* The context is freed by this function if an error occurs.
|
||
|
*
|
||
|
* @algo: Pointer to the hash_algo struct
|
||
|
* @ctx: Pointer to the context for hashing
|
||
|
* @buf: Pointer to the buffer being hashed
|
||
|
* @size: Size of the buffer being hashed
|
||
|
* @is_last: 1 if this is the last update; 0 otherwise
|
||
|
* @return 0 if ok, -ve on error
|
||
|
*/
|
||
|
int hw_sha_update(struct hash_algo *algo, void *ctx, const void *buf,
|
||
|
unsigned int size, int is_last)
|
||
|
{
|
||
|
return SHA_Update(&sha_handle, buf, size);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Copy sha hash result at destination location
|
||
|
*
|
||
|
* The context is freed after completion of hash operation or after an error.
|
||
|
*
|
||
|
* @algo: Pointer to the hash_algo struct
|
||
|
* @ctx: Pointer to the context for hashing
|
||
|
* @dest_buf: Pointer to the destination buffer where hash is to be copied
|
||
|
* @size: Size of the buffer being hashed
|
||
|
* @return 0 if ok, -ve on error
|
||
|
*/
|
||
|
int hw_sha_finish(struct hash_algo *algo, void *ctx, void *dest_buf, int size)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
status = SHA_Finish(&sha_handle, dest_buf);
|
||
|
npcm_sha_check(status);
|
||
|
return SHA_Power(false);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Init */
|
||
|
/* */
|
||
|
/* Parameters: handlePtr - SHA processing handle pointer */
|
||
|
/* Returns: 0 on success or other int error code on error. */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine initialize the SHA module */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Init(struct SHA_HANDLE_T *handleptr)
|
||
|
{
|
||
|
handleptr->active = false;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Start */
|
||
|
/* */
|
||
|
/* Parameters: handlePtr - SHA processing handle pointer */
|
||
|
/* type - SHA module type */
|
||
|
/* */
|
||
|
/* Returns: 0 on success or other int error code on error. */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine start a single SHA process */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Start(struct SHA_HANDLE_T *handleptr, u8 type)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
|
||
|
// Initialize handle
|
||
|
handleptr->length0 = 0;
|
||
|
handleptr->length1 = 0;
|
||
|
handleptr->type = type;
|
||
|
handleptr->active = true;
|
||
|
|
||
|
// Set SHA type
|
||
|
writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg);
|
||
|
|
||
|
// Reset SHA hardware
|
||
|
SHA_Reset();
|
||
|
|
||
|
/* The handlePtr->hv is initialized with the correct IV as the SHA engine
|
||
|
* automatically fill the HASH_DIG_Hn registers according to SHA spec
|
||
|
* (following SHA_RST assertion)
|
||
|
*/
|
||
|
SHA_GetShaDigest_l((u8 *)handleptr->hv, type);
|
||
|
|
||
|
// Init block with zeros
|
||
|
memset(handleptr->block, 0, sizeof(handleptr->block));
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Update */
|
||
|
/* */
|
||
|
/* Parameters: handlePtr - SHA processing handle pointer */
|
||
|
/* buffer - Pointer to the data that will be added to */
|
||
|
/* the hash calculation */
|
||
|
/* len - Length of data to add to SHA calculation */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* Returns: 0 on success or other int error code on error */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine adds data to previously started SHA */
|
||
|
/* calculation */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Update(struct SHA_HANDLE_T *handleptr, const u8 *buffer, u32 len)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)];
|
||
|
u32 bufferlen = len;
|
||
|
u16 pos = 0;
|
||
|
u8 *blockptr;
|
||
|
int status;
|
||
|
|
||
|
// Error check
|
||
|
if (!handleptr->active)
|
||
|
return -EPROTO;
|
||
|
|
||
|
// Wait till SHA is not busy
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
|
||
|
// Set SHA type
|
||
|
writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg);
|
||
|
|
||
|
// Write SHA latest digest into SHA module
|
||
|
SHA_SetShaDigest_l(handleptr->hv, handleptr->type);
|
||
|
|
||
|
// Set number of unhashed bytes which remained from last update
|
||
|
pos = SHA_BUFF_POS(handleptr->length0);
|
||
|
|
||
|
// Copy unhashed bytes which remained from last update to secrun buffer
|
||
|
SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer);
|
||
|
|
||
|
while (len) {
|
||
|
// Wait for the hardware to be available (in case we are hashing)
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
|
||
|
// Move as much bytes as we can into the secrun buffer
|
||
|
bufferlen = min(len, SHA_BUFF_FREE(handleptr->length0));
|
||
|
|
||
|
// Copy current given buffer to the secrun buffer
|
||
|
SHA_SetBlock_l((u8 *)buffer, bufferlen, pos, localbuffer);
|
||
|
|
||
|
// Update size of hashed bytes
|
||
|
handleptr->length0 += bufferlen;
|
||
|
|
||
|
if (handleptr->length0 < bufferlen)
|
||
|
handleptr->length1++;
|
||
|
|
||
|
// Update length of data left to digest
|
||
|
len -= bufferlen;
|
||
|
|
||
|
// Update given buffer pointer
|
||
|
buffer += bufferlen;
|
||
|
|
||
|
// If secrun buffer is full
|
||
|
if (SHA_BUFF_POS(handleptr->length0) == 0) {
|
||
|
/* We just filled up the buffer perfectly, so let it hash (we'll
|
||
|
* unload the hash only when we are done with all hashing)
|
||
|
*/
|
||
|
SHA_FlushLocalBuffer_l(localbuffer);
|
||
|
|
||
|
pos = 0;
|
||
|
bufferlen = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Wait till SHA is not busy
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
|
||
|
/* Copy unhashed bytes from given buffer to handle block for next update/finish */
|
||
|
blockptr = (u8 *)handleptr->block;
|
||
|
while (bufferlen)
|
||
|
blockptr[--bufferlen + pos] = *(--buffer);
|
||
|
|
||
|
// Save SHA current digest
|
||
|
SHA_GetShaDigest_l((u8 *)handleptr->hv, handleptr->type);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Finish */
|
||
|
/* */
|
||
|
/* Parameters: handlePtr - SHA processing handle pointer */
|
||
|
/* hashDigest - Pointer to a buffer where the final digest */
|
||
|
/* will be copied to */
|
||
|
/* */
|
||
|
/* Returns: 0 on success or other int error code on error */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine finish SHA calculation and get */
|
||
|
/* the resulting SHA digest */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Finish(struct SHA_HANDLE_T *handleptr, u8 *hashdigest)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u32 localbuffer[SHA_SECRUN_BUFF_SIZE / sizeof(u32)];
|
||
|
const u8 lastbyte = SHA_DATA_LAST_BYTE;
|
||
|
u16 pos;
|
||
|
int status;
|
||
|
|
||
|
// Error check
|
||
|
if (!handleptr->active)
|
||
|
return -EPROTO;
|
||
|
|
||
|
// Set SHA type
|
||
|
writeb(handleptr->type & HASH_CFG_SHA1_SHA2, ®s->hash_cfg);
|
||
|
|
||
|
// Wait till SHA is not busy
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
|
||
|
// Finish off the current buffer with the SHA spec'ed padding
|
||
|
pos = SHA_BUFF_POS(handleptr->length0);
|
||
|
|
||
|
// Init SHA digest
|
||
|
SHA_SetShaDigest_l(handleptr->hv, handleptr->type);
|
||
|
|
||
|
// Load data into secrun buffer
|
||
|
SHA_SetBlock_l((u8 *)handleptr->block, pos, 0, localbuffer);
|
||
|
|
||
|
// Set data last byte as in SHA algorithm spec
|
||
|
SHA_SetBlock_l(&lastbyte, 1, pos++, localbuffer);
|
||
|
|
||
|
// If the remainder of data is longer then one block
|
||
|
if (pos > (SHA_BLOCK_LENGTH - 8)) {
|
||
|
/* The length will be in the next block Pad the rest of the last block with 0's */
|
||
|
SHA_ClearBlock_l((SHA_BLOCK_LENGTH - pos), pos, localbuffer);
|
||
|
|
||
|
// Hash the current block
|
||
|
SHA_FlushLocalBuffer_l(localbuffer);
|
||
|
|
||
|
pos = 0;
|
||
|
|
||
|
// Wait till SHA is not busy
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
}
|
||
|
|
||
|
// Pad the rest of the last block with 0's except for the last 8-3 bytes
|
||
|
SHA_ClearBlock_l((SHA_BLOCK_LENGTH - (8 - 3)) - pos, pos, localbuffer);
|
||
|
|
||
|
/* The last 8-3 bytes are set to the bit-length of the message in big-endian form */
|
||
|
SHA_SetLength32_l(handleptr, localbuffer);
|
||
|
|
||
|
// Hash all that, and save the hash for the caller
|
||
|
SHA_FlushLocalBuffer_l(localbuffer);
|
||
|
|
||
|
// Wait till SHA is not busy
|
||
|
status = SHA_BusyWait_l();
|
||
|
npcm_sha_check(status);
|
||
|
|
||
|
// Save SHA final digest into given buffer
|
||
|
SHA_GetShaDigest_l(hashdigest, handleptr->type);
|
||
|
|
||
|
// Free handle
|
||
|
handleptr->active = false;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Reset */
|
||
|
/* */
|
||
|
/* Parameters: none */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine reset SHA module */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Reset(void)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
|
||
|
writel(readl(®s->hash_ctr_sts) | HASH_CTR_STS_SHA_RST, ®s->hash_ctr_sts);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_Power */
|
||
|
/* */
|
||
|
/* Parameters: on - true enable the module, false disable the module */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine set SHA module power on/off */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_Power(bool on)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u8 hash_sts;
|
||
|
|
||
|
hash_sts = readb(®s->hash_ctr_sts) & ~HASH_CTR_STS_SHA_EN;
|
||
|
writeb(hash_sts | (on & HASH_CTR_STS_SHA_EN), ®s->hash_ctr_sts);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef SHA_PRINT
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_PrintRegs */
|
||
|
/* */
|
||
|
/* Parameters: none */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine prints the module registers */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_PrintRegs(void)
|
||
|
{
|
||
|
#ifdef SHA_DEBUG_MODULE
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
#endif
|
||
|
unsigned int i;
|
||
|
|
||
|
sha_print("/*--------------*/\n");
|
||
|
sha_print("/* SHA */\n");
|
||
|
sha_print("/*--------------*/\n\n");
|
||
|
|
||
|
sha_print("HASH_CTR_STS = 0x%02X\n", readb(®s->hash_ctr_sts));
|
||
|
sha_print("HASH_CFG = 0x%02X\n", readb(®s->hash_cfg));
|
||
|
|
||
|
for (i = 0; i < HASH_DIG_H_NUM; i++)
|
||
|
sha_print("HASH_DIG_H%d = 0x%08X\n", i, readl(®s->hash_dig[i]));
|
||
|
|
||
|
sha_print("HASH_VER = 0x%08X\n", readb(®s->hash_ver));
|
||
|
|
||
|
sha_print("\n");
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_PrintVersion */
|
||
|
/* */
|
||
|
/* Parameters: none */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine prints the module version */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_PrintVersion(void)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
|
||
|
printf("SHA MODULE VER = %d\n", readb(®s->hash_ver));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: npcm_sha_selftest */
|
||
|
/* */
|
||
|
/* Parameters: type - SHA module type */
|
||
|
/* Returns: 0 on success or other int error code on error */
|
||
|
/* Side effects: */
|
||
|
/* Description: */
|
||
|
/* This routine performs various tests on the SHA HW and SW */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
int npcm_sha_selftest(u8 type)
|
||
|
{
|
||
|
int status;
|
||
|
struct SHA_HANDLE_T handle;
|
||
|
u8 hashdigest[max(SHA_1_HASH_LENGTH, SHA_2_HASH_LENGTH)];
|
||
|
u16 i, j;
|
||
|
|
||
|
/*------------------------------------------------------------------------*/
|
||
|
/* SHA1 tests info */
|
||
|
/*------------------------------------------------------------------------*/
|
||
|
|
||
|
static const u8 sha1selftestbuff[SHA1_NUM_OF_SELF_TESTS][94] = {
|
||
|
{"abc"},
|
||
|
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
|
||
|
{"0123456789012345678901234567890123456789012345678901234567890123"},
|
||
|
{0x30, 0x5c, 0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b,
|
||
|
0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a,
|
||
|
0x01, 0x0c, 0x04, 0x14, 0xe1, 0xb6, 0x93, 0xfe, 0x33, 0x43, 0xc1, 0x20,
|
||
|
0x5d, 0x4b, 0xaa, 0xb8, 0x63, 0xfb, 0xcf, 0x6c, 0x46, 0x1e, 0x88, 0x04,
|
||
|
0x30, 0x2c, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||
|
0x02, 0x1a, 0x05, 0x00, 0x30, 0x06, 0x06, 0x04, 0x67, 0x2a, 0x01, 0x0c,
|
||
|
0x04, 0x14, 0x13, 0xc1, 0x0c, 0xfc, 0xc8, 0x92, 0xd7, 0xde, 0x07, 0x1c,
|
||
|
0x40, 0xde, 0x4f, 0xcd, 0x07, 0x5b, 0x68, 0x20, 0x5a, 0x6c}
|
||
|
};
|
||
|
|
||
|
static const u8 sha1selftestbufflen[SHA1_NUM_OF_SELF_TESTS] = {
|
||
|
3, 56, 64, 94
|
||
|
};
|
||
|
|
||
|
static const u8 sha1selftestexpres[SHA1_NUM_OF_SELF_TESTS][SHA_1_HASH_LENGTH] = {
|
||
|
{0xA9, 0x99, 0x3E, 0x36,
|
||
|
0x47, 0x06, 0x81, 0x6A,
|
||
|
0xBA, 0x3E, 0x25, 0x71,
|
||
|
0x78, 0x50, 0xC2, 0x6C,
|
||
|
0x9C, 0xD0, 0xD8, 0x9D},
|
||
|
{0x84, 0x98, 0x3E, 0x44,
|
||
|
0x1C, 0x3B, 0xD2, 0x6E,
|
||
|
0xBA, 0xAE, 0x4A, 0xA1,
|
||
|
0xF9, 0x51, 0x29, 0xE5,
|
||
|
0xE5, 0x46, 0x70, 0xF1},
|
||
|
{0xCF, 0x08, 0x00, 0xF7,
|
||
|
0x64, 0x4A, 0xCE, 0x3C,
|
||
|
0xB4, 0xC3, 0xFA, 0x33,
|
||
|
0x38, 0x8D, 0x3B, 0xA0,
|
||
|
0xEA, 0x3C, 0x8B, 0x6E},
|
||
|
{0xc9, 0x84, 0x45, 0xc8,
|
||
|
0x64, 0x04, 0xb1, 0xe3,
|
||
|
0x3c, 0x6b, 0x0a, 0x8c,
|
||
|
0x8b, 0x80, 0x94, 0xfc,
|
||
|
0xf3, 0xc9, 0x98, 0xab}
|
||
|
};
|
||
|
|
||
|
/*------------------------------------------------------------------------*/
|
||
|
/* SHA2 tests info */
|
||
|
/*------------------------------------------------------------------------*/
|
||
|
|
||
|
static const u8 sha2selftestbuff[SHA2_NUM_OF_SELF_TESTS][100] = {
|
||
|
{ "abc" },
|
||
|
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
|
||
|
{'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
|
||
|
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'}
|
||
|
};
|
||
|
|
||
|
static const u8 sha2selftestbufflen[SHA2_NUM_OF_SELF_TESTS] = {
|
||
|
3, 56, 100
|
||
|
};
|
||
|
|
||
|
static const u8 sha2selftestexpres[SHA2_NUM_OF_SELF_TESTS][SHA_2_HASH_LENGTH] = {
|
||
|
/*
|
||
|
* SHA-256 test vectors
|
||
|
*/
|
||
|
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
|
||
|
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
|
||
|
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
|
||
|
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
|
||
|
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
|
||
|
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
|
||
|
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
|
||
|
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
|
||
|
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
|
||
|
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
|
||
|
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
|
||
|
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 },
|
||
|
};
|
||
|
|
||
|
if (type == npcm_sha_type_sha1) {
|
||
|
/*--------------------------------------------------------------------*/
|
||
|
/* SHA 1 TESTS */
|
||
|
/*--------------------------------------------------------------------*/
|
||
|
for (i = 0; i < SHA1_NUM_OF_SELF_TESTS; i++) {
|
||
|
if (i != 3) {
|
||
|
status = npcm_sha_calc(npcm_sha_type_sha1, sha1selftestbuff[i], sha1selftestbufflen[i], hashdigest);
|
||
|
npcm_sha_check(status);
|
||
|
} else {
|
||
|
SHA_Power(true);
|
||
|
SHA_Reset();
|
||
|
status = SHA_Start(&handle, npcm_sha_type_sha1);
|
||
|
npcm_sha_check(status);
|
||
|
status = SHA_Update(&handle, sha1selftestbuff[i], 73);
|
||
|
npcm_sha_check(status);
|
||
|
status = SHA_Update(&handle, &sha1selftestbuff[i][73], sha1selftestbufflen[i] - 73);
|
||
|
npcm_sha_check(status);
|
||
|
status = SHA_Finish(&handle, hashdigest);
|
||
|
npcm_sha_check(status);
|
||
|
SHA_Power(false);
|
||
|
}
|
||
|
|
||
|
if (memcmp(hashdigest, sha1selftestexpres[i], SHA_1_HASH_LENGTH))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
/*--------------------------------------------------------------------*/
|
||
|
/* SHA 2 TESTS */
|
||
|
/*--------------------------------------------------------------------*/
|
||
|
for (i = 0; i < SHA2_NUM_OF_SELF_TESTS; i++) {
|
||
|
SHA_Power(true);
|
||
|
SHA_Reset();
|
||
|
status = SHA_Start(&handle, npcm_sha_type_sha2);
|
||
|
npcm_sha_check(status);
|
||
|
if (i == 2) {
|
||
|
for (j = 0; j < 10000; j++) { //not working
|
||
|
status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]);
|
||
|
npcm_sha_check(status);
|
||
|
}
|
||
|
} else {
|
||
|
status = SHA_Update(&handle, sha2selftestbuff[i], sha2selftestbufflen[i]);
|
||
|
npcm_sha_check(status);
|
||
|
}
|
||
|
|
||
|
status = SHA_Finish(&handle, hashdigest);
|
||
|
npcm_sha_check(status);
|
||
|
SHA_Power(false);
|
||
|
if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH))
|
||
|
return -1;
|
||
|
|
||
|
npcm_sha_calc(npcm_sha_type_sha2, sha2selftestbuff[i], sha2selftestbufflen[i], hashdigest);
|
||
|
if (memcmp(hashdigest, sha2selftestexpres[i], SHA_2_HASH_LENGTH))
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_FlushLocalBuffer_l */
|
||
|
/* */
|
||
|
/* Parameters: */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine flush secrun buffer to SHA module */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_FlushLocalBuffer_l(const u32 *buff)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u32 i;
|
||
|
|
||
|
for (i = 0; i < (SHA_BLOCK_LENGTH / sizeof(u32)); i++)
|
||
|
writel(buff[i], ®s->hash_data_in);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_BusyWait_l */
|
||
|
/* */
|
||
|
/* Parameters: */
|
||
|
/* Returns: 0 if no error was found or DEFS_STATUS_ERROR otherwise */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine wait for SHA unit to no longer be busy */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static int SHA_BusyWait_l(void)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u32 timeout = SHA_TIMEOUT;
|
||
|
|
||
|
do {
|
||
|
if (timeout-- == 0)
|
||
|
return -ETIMEDOUT;
|
||
|
} while ((readb(®s->hash_ctr_sts) & HASH_CTR_STS_SHA_BUSY)
|
||
|
== HASH_CTR_STS_SHA_BUSY);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_GetShaDigest_l */
|
||
|
/* */
|
||
|
/* Parameters: hashDigest - buffer for the hash output. */
|
||
|
/* type - SHA module type */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine copy the hash digest from the hardware */
|
||
|
/* and into given buffer (in ram) */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_GetShaDigest_l(u8 *hashdigest, u8 type)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u16 j;
|
||
|
u8 len = SHA_HASH_LENGTH(type) / sizeof(u32);
|
||
|
|
||
|
// Copy Bytes from SHA module to given buffer
|
||
|
for (j = 0; j < len; j++)
|
||
|
((u32 *)hashdigest)[j] = readl(®s->hash_dig[j]);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_SetShaDigest_l */
|
||
|
/* */
|
||
|
/* Parameters: hashDigest - input buffer to set as hash digest */
|
||
|
/* type - SHA module type */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine set the hash digest in the hardware from */
|
||
|
/* a given buffer (in ram) */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_SetShaDigest_l(const u32 *hashdigest, u8 type)
|
||
|
{
|
||
|
struct npcm_sha_regs *regs = sha_priv->regs;
|
||
|
u16 j;
|
||
|
u8 len = SHA_HASH_LENGTH(type) / sizeof(u32);
|
||
|
|
||
|
// Copy Bytes from given buffer to SHA module
|
||
|
for (j = 0; j < len; j++)
|
||
|
writel(hashdigest[j], ®s->hash_dig[j]);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_SetBlock_l */
|
||
|
/* */
|
||
|
/* Parameters: data - data to copy */
|
||
|
/* len - size of data */
|
||
|
/* position - byte offset into the block at which data */
|
||
|
/* should be placed */
|
||
|
/* block - block buffer */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine load bytes into block buffer */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_SetBlock_l(const u8 *data, u32 len, u16 position, u32 *block)
|
||
|
{
|
||
|
u8 *dest = (u8 *)block;
|
||
|
|
||
|
memcpy(dest + position, data, len);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_SetBlock_l */
|
||
|
/* */
|
||
|
/* Parameters: */
|
||
|
/* len - size of data */
|
||
|
/* position - byte offset into the block at which data */
|
||
|
/* should be placed */
|
||
|
/* block - block buffer */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine load zero's into the block buffer */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_ClearBlock_l(u16 len, u16 position, u32 *block)
|
||
|
{
|
||
|
u8 *dest = (u8 *)block;
|
||
|
|
||
|
memset(dest + position, 0, len);
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
/* Function: SHA_SetLength32_l */
|
||
|
/* */
|
||
|
/* Parameters: */
|
||
|
/* handlePtr - SHA processing handle pointer */
|
||
|
/* block - block buffer */
|
||
|
/* Returns: none */
|
||
|
/* Side effects: */
|
||
|
/* Description: This routine set the length of the hash's data */
|
||
|
/* len is the 32-bit byte length of the message */
|
||
|
/*lint -efunc(734,SHA_SetLength32_l) Supperess loss of percision lint warning */
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
static void SHA_SetLength32_l(struct SHA_HANDLE_T *handleptr, u32 *block)
|
||
|
{
|
||
|
u16 *secrunbufferswappedptr = (u16 *)(void *)(block);
|
||
|
|
||
|
secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 1] = (u16)
|
||
|
((handleptr->length0 << 3) << 8) | ((u16)(handleptr->length0 << 3) >> 8);
|
||
|
secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 2] = (u16)
|
||
|
((handleptr->length0 >> (16 - 3)) >> 8) | ((u16)(handleptr->length0 >> (16 - 3)) << 8);
|
||
|
secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 3] = (u16)
|
||
|
((handleptr->length1 << 3) << 8) | ((u16)(handleptr->length1 << 3) >> 8);
|
||
|
secrunbufferswappedptr[(SHA_BLOCK_LENGTH / sizeof(u16)) - 4] = (u16)
|
||
|
((handleptr->length1 >> (16 - 3)) >> 8) | ((u16)(handleptr->length1 >> (16 - 3)) << 8);
|
||
|
}
|
||
|
|
||
|
static int npcm_sha_bind(struct udevice *dev)
|
||
|
{
|
||
|
sha_priv = calloc(1, sizeof(struct npcm_sha_priv));
|
||
|
if (!sha_priv)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
sha_priv->regs = dev_remap_addr_index(dev, 0);
|
||
|
if (!sha_priv->regs) {
|
||
|
printf("Cannot find sha reg address, binding failed\n");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
printf("SHA: NPCM SHA module bind OK\n");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const struct udevice_id npcm_sha_ids[] = {
|
||
|
{ .compatible = "nuvoton,npcm845-sha" },
|
||
|
{ .compatible = "nuvoton,npcm750-sha" },
|
||
|
{ }
|
||
|
};
|
||
|
|
||
|
U_BOOT_DRIVER(npcm_sha) = {
|
||
|
.name = "npcm_sha",
|
||
|
.id = UCLASS_MISC,
|
||
|
.of_match = npcm_sha_ids,
|
||
|
.priv_auto = sizeof(struct npcm_sha_priv),
|
||
|
.bind = npcm_sha_bind,
|
||
|
};
|