450 lines
12 KiB
C
450 lines
12 KiB
C
|
|
/**
|
||
|
|
******************************************************************************
|
||
|
|
* @file hgsha.c
|
||
|
|
* @author HUGE-IC Application Team
|
||
|
|
* @version V1.0.0
|
||
|
|
* @date
|
||
|
|
* @brief sha256
|
||
|
|
******************************************************************************
|
||
|
|
* @attention
|
||
|
|
*
|
||
|
|
* <h2><center>© COPYRIGHT 2019 HUGE-IC</center></h2>
|
||
|
|
*
|
||
|
|
*
|
||
|
|
*
|
||
|
|
******************************************************************************
|
||
|
|
*/
|
||
|
|
#include "typesdef.h"
|
||
|
|
#include "list.h"
|
||
|
|
#include "errno.h"
|
||
|
|
#include "dev.h"
|
||
|
|
#include "devid.h"
|
||
|
|
|
||
|
|
#include "osal/string.h"
|
||
|
|
#include "osal/semaphore.h"
|
||
|
|
#include "osal/mutex.h"
|
||
|
|
#include "osal/irq.h"
|
||
|
|
#include "osal/string.h"
|
||
|
|
#include "osal/sleep.h"
|
||
|
|
|
||
|
|
#include "dev/sha/hgsha_v1.h"
|
||
|
|
#include "hgsha_v1_hw.h"
|
||
|
|
#include "hal/sha.h"
|
||
|
|
|
||
|
|
#if 1
|
||
|
|
#define SHA_PRINTF(fmt, arg...) printf(fmt, ##arg)
|
||
|
|
#else
|
||
|
|
#define SHA_PRINTF(fmt, arg...)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
typedef enum {
|
||
|
|
SHA1_INIT = BIT(3) | BIT(1),
|
||
|
|
SHA1_UPDATE = BIT(3),
|
||
|
|
SHA1_FINISH = BIT(3) | BIT(2),
|
||
|
|
SHA2_INIT = BIT(1),
|
||
|
|
SHA2_UPDATE = 0,
|
||
|
|
SHA2_FINISH = BIT(2),
|
||
|
|
|
||
|
|
SHA_INTR_EN = BIT(0),
|
||
|
|
} SHA_HWMODE;
|
||
|
|
|
||
|
|
|
||
|
|
#define SHA_NONBLOCK (0x1000)
|
||
|
|
|
||
|
|
/********************************
|
||
|
|
*
|
||
|
|
* LOW LAYER FUNCTION AREA
|
||
|
|
*
|
||
|
|
* *****************************/
|
||
|
|
static inline void ll_sha_get_result_big_endian(struct hgsha_v1_hw *hw, uint8 *buf)
|
||
|
|
{
|
||
|
|
volatile uint32_t *tmp = (uint32_t *) & (hw->SHA_RESULT0);
|
||
|
|
uint32_t tmp_dat = 0;
|
||
|
|
|
||
|
|
for (uint32_t i = 0; i < 8; i++, tmp++) {
|
||
|
|
tmp_dat = *tmp;
|
||
|
|
*buf++ = (tmp_dat ) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat >> 8) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat >> 16) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat >> 24) & 0xFF;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static inline void ll_sha_get_result_little_endian(struct hgsha_v1_hw *hw, uint8 *buf)
|
||
|
|
{
|
||
|
|
volatile uint32_t *tmp = (uint32_t *) & (hw->SHA_RESULT0);
|
||
|
|
uint32_t tmp_dat = 0;
|
||
|
|
|
||
|
|
for (uint32_t i = 0; i < 8; i++, tmp++) {
|
||
|
|
tmp_dat = *tmp;
|
||
|
|
*buf++ = (tmp_dat >> 24) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat >> 16) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat >> 8) & 0xFF;
|
||
|
|
*buf++ = (tmp_dat ) & 0xFF;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void ll_sha_calc(struct hgsha_v1_hw *sha, uint8_t *buf, uint16_t len, SHA_HWMODE mode)
|
||
|
|
{
|
||
|
|
sha->SHA_STADDR = (uint32)buf;
|
||
|
|
sha->SHA_BYTELEN = len;
|
||
|
|
sha->SHA_PENDING = 1;
|
||
|
|
sha->SHA_CONFIG = mode;
|
||
|
|
sha->SHA_START = 1;
|
||
|
|
// while(!sha->SHA_PENDING);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/********************************
|
||
|
|
*
|
||
|
|
* DRIVE LAYER FUNCTION AREA
|
||
|
|
*
|
||
|
|
* *****************************/
|
||
|
|
|
||
|
|
static void hgsha_irq_handle(void *args)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)args;
|
||
|
|
struct hgsha_v1_hw *sha_reg = (struct hgsha_v1_hw *)sha->hw;
|
||
|
|
|
||
|
|
sha_reg->SHA_PENDING = 1;
|
||
|
|
|
||
|
|
os_sema_up(&sha->done);
|
||
|
|
if (sha->irq_func) {
|
||
|
|
sha->irq_func(sha->irq_data);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static int32_t hgsha_v1_request_irq(struct sha_dev *dev, void * irq_handle, void *args)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
sha->irq_func = args;
|
||
|
|
sha->irq_data = irq_handle;
|
||
|
|
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int hgsha_v1_release_irq(struct sha_dev *dev)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
sha->irq_func = NULL;
|
||
|
|
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int hgsha_v1_transform(struct sha_dev *dev, struct sha_req *req)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
struct hgsha_v1_hw *hw = (struct hgsha_v1_hw *)sha->hw;
|
||
|
|
int ret = 0;
|
||
|
|
uint8_t *buf = req->input;
|
||
|
|
uint32_t blocks = req->len / 64;
|
||
|
|
uint32_t stas = 0;
|
||
|
|
SHA_HWMODE mode = 0;
|
||
|
|
if (os_mutex_lock(&sha->lock, 4000)) {
|
||
|
|
printf("sha get mutex failure\r\n");
|
||
|
|
return RET_ERR;
|
||
|
|
}
|
||
|
|
switch (req->type) {
|
||
|
|
case T_SHA1:
|
||
|
|
stas = 5 * 4;
|
||
|
|
mode = SHA1_UPDATE;
|
||
|
|
break;
|
||
|
|
case T_SHA256:
|
||
|
|
stas = 8 * 4;
|
||
|
|
mode = SHA2_UPDATE;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
mode |= SHA_INTR_EN;
|
||
|
|
|
||
|
|
memcpy((void*)&hw->SHA_RESULT0, req->state, stas);
|
||
|
|
|
||
|
|
sys_dcache_clean_range_unaligned((void*)req->input, req->len);
|
||
|
|
os_sema_eat(&sha->done);
|
||
|
|
for (int bs = 512;bs>8;bs/=2) {
|
||
|
|
for (;blocks>=bs;) {
|
||
|
|
ll_sha_calc(hw, buf, bs * 64, mode);
|
||
|
|
buf += bs * 64;
|
||
|
|
blocks -= bs;
|
||
|
|
ret |= !os_sema_down(&sha->done, 8000);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (blocks) {
|
||
|
|
uint64_t tick = os_jiffies();
|
||
|
|
mode &= ~SHA_INTR_EN;
|
||
|
|
ll_sha_calc(hw, buf, blocks * 64, mode);
|
||
|
|
while(!hw->SHA_PENDING)
|
||
|
|
{
|
||
|
|
if (os_jiffies()-tick >= 8000) {
|
||
|
|
ret = 1;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
memcpy(req->state, (void*)&hw->SHA_RESULT0, stas);
|
||
|
|
os_mutex_unlock(&sha->lock);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int __sha_init(struct sha_dev *dev, struct sha_ctx * ctx)
|
||
|
|
{
|
||
|
|
if (ctx->type == T_SHA1) {
|
||
|
|
ctx->state[0] = 0x67452301;
|
||
|
|
ctx->state[1] = 0xEFCDAB89;
|
||
|
|
ctx->state[2] = 0x98BADCFE;
|
||
|
|
ctx->state[3] = 0x10325476;
|
||
|
|
ctx->state[4] = 0xC3D2E1F0;
|
||
|
|
} else {
|
||
|
|
ctx->state[0] = 0x6a09e667;
|
||
|
|
ctx->state[1] = 0xbb67ae85;
|
||
|
|
ctx->state[2] = 0x3c6ef372;
|
||
|
|
ctx->state[3] = 0xa54ff53a;
|
||
|
|
ctx->state[4] = 0x510e527f;
|
||
|
|
ctx->state[5] = 0x9b05688c;
|
||
|
|
ctx->state[6] = 0x1f83d9ab;
|
||
|
|
ctx->state[7] = 0x5be0cd19;
|
||
|
|
}
|
||
|
|
ctx->dlen = 0;
|
||
|
|
ctx->bit_len = 0;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int __sha_update(struct sha_dev *sha, struct sha_ctx *ctx, uint8_t *buf, uint32_t len)
|
||
|
|
{
|
||
|
|
struct sha_req req = {
|
||
|
|
.state = ctx->state,
|
||
|
|
.type = ctx->type,
|
||
|
|
};
|
||
|
|
|
||
|
|
if (ctx->dlen) {
|
||
|
|
if (ctx->dlen + len >= 64) {
|
||
|
|
memcpy(&ctx->buf[ctx->dlen], buf, 64 - ctx->dlen);
|
||
|
|
buf += 64 - ctx->dlen;
|
||
|
|
len -= 64 - ctx->dlen;
|
||
|
|
req.input = ctx->buf;
|
||
|
|
req.len = 64;
|
||
|
|
hgsha_v1_transform(sha, &req);
|
||
|
|
ctx->bit_len += req.len * 8;
|
||
|
|
ctx->dlen = 0;
|
||
|
|
} else {
|
||
|
|
memcpy(&ctx->buf[ctx->dlen], buf, len);
|
||
|
|
ctx->dlen += len;
|
||
|
|
len = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 512; i != 0; i /= 2) {
|
||
|
|
while (len / 64 >= i) {
|
||
|
|
req.input = buf;
|
||
|
|
req.len = i * 64;
|
||
|
|
hgsha_v1_transform(sha, &req);
|
||
|
|
ctx->bit_len += req.len * 8;
|
||
|
|
buf += i * 64;
|
||
|
|
len -= i * 64;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (len) {
|
||
|
|
memcpy(ctx->buf, buf, len);
|
||
|
|
ctx->dlen = len;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int __sha_final(struct sha_dev *sha, struct sha_ctx *ctx, uint8_t *hash)
|
||
|
|
{
|
||
|
|
struct sha_req req = {
|
||
|
|
.state = ctx->state,
|
||
|
|
.type = ctx->type,
|
||
|
|
.input = ctx->buf,
|
||
|
|
.len = 64,
|
||
|
|
};
|
||
|
|
// Pad whatever data is left in the buffer.
|
||
|
|
int i = ctx->dlen;
|
||
|
|
if (ctx->dlen < 56) {
|
||
|
|
ctx->buf[i++] = 0x80;
|
||
|
|
while (i < 56)
|
||
|
|
ctx->buf[i++] = 0x00;
|
||
|
|
} else {
|
||
|
|
ctx->buf[i++] = 0x80;
|
||
|
|
while (i < 64)
|
||
|
|
ctx->buf[i++] = 0x00;
|
||
|
|
hgsha_v1_transform(sha, &req);
|
||
|
|
memset(ctx->buf, 0, 56);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Append to the padding the total message's length in bits and transform.
|
||
|
|
ctx->bit_len += ctx->dlen * 8;
|
||
|
|
ctx->buf[63] = ctx->bit_len;
|
||
|
|
ctx->buf[62] = ctx->bit_len >> 8;
|
||
|
|
ctx->buf[61] = ctx->bit_len >> 16;
|
||
|
|
ctx->buf[60] = ctx->bit_len >> 24;
|
||
|
|
ctx->buf[59] = ctx->bit_len >> 32;
|
||
|
|
ctx->buf[58] = ctx->bit_len >> 40;
|
||
|
|
ctx->buf[57] = ctx->bit_len >> 48;
|
||
|
|
ctx->buf[56] = ctx->bit_len >> 56;
|
||
|
|
hgsha_v1_transform(sha, &req);
|
||
|
|
|
||
|
|
// Since this implementation uses little endian uint8_t ordering and SHA uses big endian,
|
||
|
|
// reverse all the bytes when copying the final state to the output hash.
|
||
|
|
for (i = 0; i < 4; ++i) {
|
||
|
|
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
if (ctx->type == T_SHA256) {
|
||
|
|
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int hgsha_v1_init(struct sha_dev *dev, SHA_TYPE type)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
sha->ctx.type = type;
|
||
|
|
sha->ctx.bit_len = 0;
|
||
|
|
sha->ctx.dlen = 0;
|
||
|
|
__sha_init(dev, sha->pctx);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int32 hgsha_v1_update(struct sha_dev *dev, uint8 *input, uint32 len)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
return __sha_update(dev, sha->pctx, input, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int32 hgsha_v1_final(struct sha_dev *dev, uint8 *output)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
return __sha_final(dev, sha->pctx, output);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int32 hgsha_v1_ioctl(struct sha_dev *dev, uint32 cmd, uint32 param1, uint32 param2)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha = (struct hgsha_v1 *)dev;
|
||
|
|
|
||
|
|
switch (cmd) {
|
||
|
|
case SHA_IOCTL_CMD_START:
|
||
|
|
os_mutex_lock(&sha->lock, osWaitForever);
|
||
|
|
break;
|
||
|
|
case SHA_IOCTL_CMD_END:
|
||
|
|
os_mutex_unlock(&sha->lock);
|
||
|
|
break;
|
||
|
|
case SHA_IOCTL_CMD_RESET:
|
||
|
|
break;
|
||
|
|
case SHA_IOCTL_GET_CTX:
|
||
|
|
*((struct sha_ctx*)param1) = sha->ctx;
|
||
|
|
break;
|
||
|
|
case SHA_IOCTL_PUT_CTX:
|
||
|
|
sha->ctx = *((struct sha_ctx*)param1);
|
||
|
|
break;
|
||
|
|
case SHA_IOCTL_RELOAD_CTX:
|
||
|
|
sha->pctx = (struct sha_ctx*)param1;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return RET_ERR;
|
||
|
|
}
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
void hg_sha_test_printf(struct sha_dev *dev)
|
||
|
|
{
|
||
|
|
uint8_t src[64];
|
||
|
|
uint32_t rsum = 0;
|
||
|
|
uint32_t state[8] = {
|
||
|
|
0x12345678, 0x66225544, 0x11447788, 0x22441597,
|
||
|
|
0x22441597, 0x11447788, 0x66225544, 0x12345678
|
||
|
|
};
|
||
|
|
for (int i = 0;i<64;i++)
|
||
|
|
src[i] = i;
|
||
|
|
struct sha_req req = {
|
||
|
|
.type = T_SHA256,
|
||
|
|
.input = src,
|
||
|
|
.state = state,
|
||
|
|
.len = 64,
|
||
|
|
};
|
||
|
|
hgsha_v1_transform(dev, &req);
|
||
|
|
for (int i = 0;i<8;i++)
|
||
|
|
rsum += state[i];
|
||
|
|
|
||
|
|
_os_printf("sha test: %x\r\n", rsum);
|
||
|
|
if (rsum != 0x4a635c1c) {
|
||
|
|
_os_printf("sha lp err\r\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef CONFIG_SLEEP
|
||
|
|
// #define HGSHA_SLEEP_TEST(dev) hg_sha_test_printf(dev)
|
||
|
|
#define HGSHA_SLEEP_TEST(dev)
|
||
|
|
static int32 hgsha_v1_suspend(struct sha_dev *dev)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha =(struct hgsha_v1 *)dev;
|
||
|
|
struct hgsha_v1_hw *sha_reg = sha->hw;
|
||
|
|
HGSHA_SLEEP_TEST(dev);
|
||
|
|
if(os_mutex_lock(&sha->lock, 80000)) {
|
||
|
|
return RET_ERR;
|
||
|
|
}
|
||
|
|
|
||
|
|
irq_disable(sha->irq_num);
|
||
|
|
sysctrl_sha_clk_close();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int32 hgsha_v1_resume(struct sha_dev *dev)
|
||
|
|
{
|
||
|
|
struct hgsha_v1 *sha =(struct hgsha_v1 *)dev;
|
||
|
|
struct hgsha_v1_hw *hw = (struct hgsha_v1_hw *)sha->hw;
|
||
|
|
os_mutex_unlock(&sha->lock);
|
||
|
|
sysctrl_sha_clk_open();
|
||
|
|
sysctrl_sha_reset();
|
||
|
|
hw->SHA_PENDING |= 1;
|
||
|
|
irq_enable(sha->irq_num);
|
||
|
|
HGSHA_SLEEP_TEST(dev);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
static const struct sha_hal_ops sha_v1_ops = {
|
||
|
|
.init = hgsha_v1_init,
|
||
|
|
.update = hgsha_v1_update,
|
||
|
|
.final = hgsha_v1_final,
|
||
|
|
.xform = hgsha_v1_transform,
|
||
|
|
.ioctl = hgsha_v1_ioctl,
|
||
|
|
.requset_irq = hgsha_v1_request_irq,
|
||
|
|
.release_irq = hgsha_v1_release_irq,
|
||
|
|
#ifdef CONFIG_SLEEP
|
||
|
|
.ops.suspend = (int32 (*)(struct dev_obj *obj))hgsha_v1_suspend,
|
||
|
|
.ops.resume = (int32 (*)(struct dev_obj *obj))hgsha_v1_resume,
|
||
|
|
#endif
|
||
|
|
};
|
||
|
|
|
||
|
|
__init int32_t hgsha_v1_attach(uint32_t dev_id, struct hgsha_v1 *sha)
|
||
|
|
{
|
||
|
|
sha->dev.dev.ops = (const struct devobj_ops *)&sha_v1_ops;
|
||
|
|
struct hgsha_v1_hw *hw = (struct hgsha_v1_hw *)sha->hw;
|
||
|
|
|
||
|
|
//clear pending
|
||
|
|
hw->SHA_PENDING |= 1;
|
||
|
|
sha->irq_func = NULL;
|
||
|
|
sha->flags = 0;
|
||
|
|
sha->pctx = &sha->ctx;
|
||
|
|
|
||
|
|
os_mutex_init(&sha->lock);
|
||
|
|
os_sema_init(&sha->done, 0);
|
||
|
|
|
||
|
|
request_irq(sha->irq_num, hgsha_irq_handle, sha);
|
||
|
|
irq_enable(sha->irq_num);
|
||
|
|
|
||
|
|
dev_register(dev_id, (struct dev_obj *)sha);
|
||
|
|
return RET_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|