blob: 3f27cf3f1eafd5156f9bddce56189608fdcfaea2 [file] [log] [blame]
#include <common.h>
#include <config.h>
#include <asm/arch/cpu.h>
#if CONFIG_PXA_DMA
#include <asm/arch/pxa_dma.h>
#endif
#include <stdbool.h>
#include <asm/io.h>
#include <malloc.h>
#include <asm/bitops.h>
#include "asr_geu.h"
#include "asr_rng.h"
#include "asr_fuse.h"
#include "aes.h"
/*
notice: 1) use hardware key if burned hardware key;
1) use input key if not burned hardware key but input key not null;
2) use default key if not burned rkek but input key is null;
char default_key[64] = {"asr-aes-default-key-without-rkek"};
*/
const char default_key[64] = {"asr-aes-default-key-without-rkek"};
#define AES_ALG_MASK (0xf)
#if CONFIG_PXA_DMA
#define ASR_AES_DMA_THRESHOLD (256)
#endif
static struct geu_data geu_data = {
.geu_phybase = GEU_BASE,
.apmu_phybase = APMU_BASE,
.clk_en = 0,
};
uint32_t geu_read32(uint32_t reg) {
return readl(geu_data.geu_phybase + reg);
}
void geu_write32(uint32_t reg, uint32_t val) {
writel(val, geu_data.geu_phybase + reg);
}
void geu_reset_unit(void)
{
uint32_t val;
mutex_lock(&geu_data.clk_lock);
val = readl(geu_data.apmu_phybase + AES_CLK_RES_CTRL);
val &= ~(1 << 0);
writel(val, geu_data.apmu_phybase + AES_CLK_RES_CTRL);
val |= (1 << 0);
writel(val, geu_data.apmu_phybase + AES_CLK_RES_CTRL);
mutex_unlock(&geu_data.clk_lock);
}
void geu_reset_aes(void)
{
uint32_t conf;
conf = geu_read32(GEU_CONFIG);
conf &= ~GEU_CFG_AES_MSK;
geu_write32(GEU_CONFIG, conf);
}
void geu_enable_clk(void)
{
uint32_t val;
mutex_lock(&geu_data.clk_lock);
if ( geu_data.clk_en == 0 ) {
val = readl(geu_data.apmu_phybase + AES_CLK_RES_CTRL);
/* it will no longer enable clk if the clk has been enabled */
if ((val & (1 << 3 | 1 << 0)) == (1 << 3 | 1 << 0)) {
return;
}
val |= (1 << 3);
val |= (1 << 0);
writel(val, geu_data.apmu_phybase + AES_CLK_RES_CTRL);
}
geu_data.clk_en ++;
mutex_unlock(&geu_data.clk_lock);
}
void geu_disable_clk(void)
{
uint32_t val;
mutex_lock(&geu_data.clk_lock);
if(geu_data.clk_en > 0) {
geu_data.clk_en --;
if(geu_data.clk_en == 0) {
val = readl(geu_data.apmu_phybase + AES_CLK_RES_CTRL);
val &= ~(1 << 3);
writel(val, geu_data.apmu_phybase + AES_CLK_RES_CTRL);
}
}
mutex_unlock(&geu_data.clk_lock);
}
void asr_geu_get(void)
{
mutex_lock(&geu_data.eng_lock);
}
void asr_geu_put(void)
{
mutex_unlock(&geu_data.eng_lock);
}
static int asr_aes_waiting_status(uint32_t bit_mask, uint32_t timeout,
int set_clr/* 1: set, 0: clear */)
{
uint32_t ret = 0;
uint32_t mytime;
uint32_t status;
uint32_t start = 0;
set_clr = !!set_clr;
start = get_timer(0);
if (ret != 0) {
printf("fail to get system time");
return -1;
}
do {
status = geu_read32(GEU_STATUS);
mytime = get_timer(start);
if(mytime > timeout) {
printf("aes waiting time out\n");
return -1;
}
}while( (!!(status & bit_mask)) ^ set_clr );
return 0;
}
static int asr_aes_setmode(int encrypt, int mode)
{
uint32_t conf;
conf = geu_read32(GEU_CONFIG);
switch(mode) {
case AES_ECB:
conf &= ~GEU_CFG_CBC_ECB;
conf &= ~GEU_CFG_OCB_BYP;
break;
case AES_CBC:
conf |= GEU_CFG_CBC_ECB;
conf |= GEU_CFG_OCB_BYP;
break;
default :
printf("Unsupported AES mode\n");
return -1;
}
if(encrypt)
conf &= ~GEU_CFG_ENC_DEC;
else
conf |= GEU_CFG_ENC_DEC;
geu_write32(GEU_CONFIG, conf);
return 0;
}
static int asr_aes_rkek_burned(void)
{
uint32_t val;
/* If RKEK is burned, SW access to it must be disabled as well */
if (cpu_is_asr1901() || cpu_is_asr1906()) {
/* check if LCS_DM is burned */
val = geu_read32(GEU_KSTR_BANK6_LCS);
val >>= GEU_KSTR_LCS_DM_BASE;
val &= GEU_KSTR_LCS_MASK;
if (hweight32(val) > 1)
return 1;
} else { /* 1803, 1806, 1828, 1903 */
/* check if secure key access disable is burned */
val = geu_read32(GEU_FUSE_APCFG2);
if (val & GEU_SECURE_KEY_ACCESS_DISABLED)
return 1;
}
return 0;
}
static int asr_aes_setkey(uint32_t *key, uint32_t key_size, bool use_rkek)
{
int ret = 0;
uint32_t index;
uint32_t conf, status;
int rkek_burned = 0;
key_size &= ~3;
conf = geu_read32(GEU_CONFIG);
status = geu_read32(GEU_STATUS);
conf |= GEU_CFG_PWR_BYP;
conf &= ~GEU_CFG_KEY_SIZE(3); /* clear key size conf */
rkek_burned = asr_aes_rkek_burned();
if (use_rkek && rkek_burned) {
/* using rkek from fuse block */
conf |= GEU_CFG_ENA_RKEK;
conf |= GEU_CFG_KEY_SIZE((key_size >> 3) - 1);
} else {
conf &= ~GEU_CFG_ENA_RKEK;
conf |= GEU_CFG_KEY_SIZE((key_size >> 3) - 1);
for (index = 0; index < 8; index ++)
geu_write32(GEU_INIT_KEY(index), 0); /* clear key reg */
for (index = 0; index < (key_size >> 2); index++)
geu_write32(GEU_INIT_KEY(index), key[index]);
}
geu_write32(GEU_CONFIG, conf);
status |= GEU_STATUS_ROUND_KEY_START;
geu_write32(GEU_STATUS, status);
ret = asr_aes_waiting_status(GEU_STATUS_ROUND_KEY_READY, 100, 1);
return ret;
}
static int asr_aes_setiv(uint32_t *iv)
{
uint32_t conf;
int index;
for (index = 0; index < 4; index ++)
geu_write32(GEU_INIT_IV(index), iv[index]);
conf = geu_read32(GEU_CONFIG);
conf |= GEU_CFG_WRITE_IV;
geu_write32(GEU_CONFIG, conf);
return 0;
}
static int asr_aes_getiv(uint32_t *iv)
{
iv[0] = geu_read32(GEU_OUT_DATA(0));
iv[1] = geu_read32(GEU_OUT_DATA(1));
iv[2] = geu_read32(GEU_OUT_DATA(2));
iv[3] = geu_read32(GEU_OUT_DATA(3));
return 0;
}
#if CONFIG_PXA_DMA
static int asr_aes_enable_dma(void)
{
uint32_t conf;
conf = geu_read32(GEU_CONFIG);
conf |= GEU_CFG_DMA_MODE_EN;
geu_write32(GEU_CONFIG, conf);
return 0;
}
static int asr_aes_disable_dma(void)
{
uint32_t conf;
conf = geu_read32(GEU_CONFIG);
conf &= ~GEU_CFG_DMA_MODE_EN;
geu_write32(GEU_CONFIG, conf);
return 0;
}
#endif
static int asr_aes_process_pio(uint32_t *in, uint32_t len, uint32_t *out)
{
int ret;
int len_bytes = len;
uint32_t status;
uint32_t *in_buf = in;
uint32_t *out_buf = out;
assert(!(len_bytes % 16));
while(len_bytes > 0) {
geu_write32(GEU_IN_DATA(0), in_buf[0]);
geu_write32(GEU_IN_DATA(1), in_buf[1]);
geu_write32(GEU_IN_DATA(2), in_buf[2]);
geu_write32(GEU_IN_DATA(3), in_buf[3]);
status = geu_read32(GEU_STATUS);
status |= GEU_STATUS_DATA_ENCDEC_ENA;
geu_write32(GEU_STATUS, status);
ret = asr_aes_waiting_status(GEU_STATUS_DATA_ENCDEC_READY, 100, 1);
if( ret ) return -1;
out_buf[0] = geu_read32(GEU_OUT_DATA(0));
out_buf[1] = geu_read32(GEU_OUT_DATA(1));
out_buf[2] = geu_read32(GEU_OUT_DATA(2));
out_buf[3] = geu_read32(GEU_OUT_DATA(3));
len_bytes -= 16;
in_buf += 4;
out_buf += 4;
}
return 0;
}
#if CONFIG_PXA_DMA
static int geu_dma_read_prepare(uint32_t dst, uint32_t src,
uint32_t size, uint32_t chl, struct dma_descp *desc)
{
#define MAX_DATA_SIZE_OF_EACH_DESC (0x1000)
uint32_t cmd = 0;
cmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
cmd |= DCMD_BURST16 | DCMD_WIDTH4;
if (desc) {
uint32_t desc_src, desc_cmd;
uint32_t remain_len = size;
struct dma_descp *desc_curr = NULL;
struct dma_descp *desc_next = NULL;
for (uint32_t i = 0; i < size / MAX_DATA_SIZE_OF_EACH_DESC; i++) {
remain_len -= MAX_DATA_SIZE_OF_EACH_DESC;
desc_cmd = (cmd & ~(DCMD_LENGTH)) | MAX_DATA_SIZE_OF_EACH_DESC;
desc_src = (uint32_t)(src + MAX_DATA_SIZE_OF_EACH_DESC * i);
desc_curr = desc + i;
if (0 == remain_len) {
desc_next = 0;
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
desc_src, dst, desc_cmd, 1);
} else {
desc_next = desc + (i + 1);
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
desc_src, dst, desc_cmd, 0);
}
}
if ((remain_len > 0) && (remain_len < MAX_DATA_SIZE_OF_EACH_DESC )) {
desc_cmd = (cmd & ~(DCMD_LENGTH)) | remain_len;
desc_src = (uint32_t)(src + (size - remain_len));
desc_curr = desc + (size / MAX_DATA_SIZE_OF_EACH_DESC);
desc_next = 0;
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
desc_src, dst, desc_cmd, 1);
}
load_descriptor((struct dma_descp *)desc, chl);
} else {
DCSR(chl) |= DCSR_NODESC;
DTADR(chl) = dst;
DSADR(chl) = src;
DCMD(chl) = cmd | (size & DCMD_LENGTH);
}
}
static int geu_dma_write_prepare(uint32_t dst, uint32_t src,
uint32_t size, uint32_t chl, struct dma_descp *desc)
{
uint32_t cmd = 0;
cmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
cmd |= DCMD_BURST16 | DCMD_WIDTH4;
if (desc) {
uint32_t desc_dst, desc_cmd;
uint32_t remain_len = size;
struct dma_descp *desc_curr = NULL;
struct dma_descp *desc_next = NULL;
for (uint32_t i = 0; i < size/MAX_DATA_SIZE_OF_EACH_DESC; i++) {
remain_len -= MAX_DATA_SIZE_OF_EACH_DESC;
desc_cmd = (cmd & ~(DCMD_LENGTH)) | MAX_DATA_SIZE_OF_EACH_DESC;
desc_dst = (uint32_t)(dst + MAX_DATA_SIZE_OF_EACH_DESC*i);
desc_curr = desc + i;
if (0 == remain_len) {
desc_next = 0;
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
src, desc_dst, desc_cmd, 1);
} else {
desc_next = desc + (i + 1);
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
src, desc_dst, desc_cmd, 0);
}
}
if ((remain_len > 0) && (remain_len < MAX_DATA_SIZE_OF_EACH_DESC )) {
desc_cmd = (cmd & ~(DCMD_LENGTH)) | remain_len;
desc_dst = (uint32_t)(dst + (size - remain_len));
desc_curr = desc + (size/MAX_DATA_SIZE_OF_EACH_DESC);
desc_next = 0;
config_descriptor((unsigned int *)desc_curr,
(unsigned int *)desc_next,
src, desc_dst, desc_cmd, 1);
}
load_descriptor((struct dma_descp *)desc, chl);
} else {
DCSR(chl) |= DCSR_NODESC;
DTADR(chl) = dst;
DSADR(chl) = src;
DCMD(chl) = cmd;
DCMD(chl) = cmd | (size & DCMD_LENGTH);
}
}
static int asr_aes_process_dma(uint32_t *in, uint32_t len, uint32_t *out)
{
int init = 0;
int ret = 0;
int remain_len = 0;
uint32_t start = 0, src, dst, step_szie;
struct dma_descp rc_desc[64] __attribute__ ((aligned (32)));
struct dma_descp tx_desc[64] __attribute__ ((aligned (32)));
if (!init) {
dmac_map_device_to_channel(DMA_DEVICE_GEU_RXREQ,
GEU_RX_CHANNEL);
dmac_map_device_to_channel(DMA_DEVICE_GEU_TXREQ,
GEU_TX_CHANNEL);
dmac_user_aligment(GEU_RX_CHANNEL);
dmac_user_aligment(GEU_TX_CHANNEL);
init = 1;
}
src = (uint32_t)virt_to_phys((void *)in);
dst = (uint32_t)virt_to_phys((void *)out);
remain_len = len;
step_szie = EACH_DMA_PROCESS_SIZE;
while (remain_len > 0) {
step_szie = (remain_len > step_szie) ? step_szie:remain_len;
geu_dma_read_prepare(GEU_BASE + GEU_IN_DATA(0), (uint32_t)src,\
step_szie, GEU_RX_CHANNEL, rc_desc);
geu_dma_write_prepare((uint32_t)dst, GEU_BASE + GEU_OUT_DATA(0), \
step_szie, GEU_TX_CHANNEL, tx_desc);
flush_dcache_all();
dmac_start_transfer(GEU_RX_CHANNEL);
dmac_start_transfer(GEU_TX_CHANNEL);
asr_aes_enable_dma();
start = get_timer(0);
do {
for (uint32_t i = 0; i < 500; i++)
nop();
if (dmac_read_dcsr(GEU_TX_CHANNEL) & DCSR_STOPSTATE)
break;
if (2000 < get_timer(start)) {
printf("aes dma tx timeout !\n");
ret = -1;
break;
goto exit;
}
} while (1);
start = get_timer(0);
do {
if (dmac_read_dcsr(GEU_RX_CHANNEL) & DCSR_STOPSTATE)
break;
if (2000 < get_timer(start)) {
printf("aes dma rx timeout !\n");
ret = -1;
break;
goto exit;
}
} while (1);
if (!(dmac_read_dcsr(GEU_TX_CHANNEL) & DCSR_STOPSTATE)) {
printf("Error:DMA write operate timeout.\n");
ret = -1;
goto exit;
}
if (!(dmac_read_dcsr(GEU_RX_CHANNEL) & DCSR_STOPSTATE)) {
printf("Error:DMA read operate timeout.\n");
ret = -1;
goto exit;
}
asr_aes_disable_dma();
remain_len -= step_szie;
src += step_szie;
dst += step_szie;
}
exit:
asr_aes_disable_dma();
return ret;
}
#endif
int aes_ecb_encrypt_geu(const uint8_t *key, uint32_t keylen, bool use_rkek,\
const void* plaintext, void* ciphertext, size_t size)
{
int ret = 0;
#if CONFIG_PXA_DMA
bool use_dma = 0;
#endif
uint32_t crylen = 0;
void *ptext = NULL, *ctext = NULL;
uint8_t use_key[32];
if ((keylen > 32) && (keylen < 16)) {
printf("aes ecb encrypt key len %d error\n", keylen);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (key == NULL) {
memcpy(use_key, default_key, keylen);
} else {
memcpy(use_key, key, keylen);
}
crylen = (size + AES_ALG_MASK) & (~AES_ALG_MASK);
/* if not align, malloc tmp alignmask */
ptext = buf_align(plaintext, AES_ALG_MASK);
if (ptext != plaintext) {
ptext = memalign(16, crylen);
if (!ptext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memcpy(ptext, plaintext, size);
}
ctext = buf_align(ciphertext, AES_ALG_MASK);
if (ctext != ciphertext) {
ctext = memalign(16, crylen);
if (!ctext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memset(ctext, 0, crylen);
}
asr_geu_get();
geu_reset_unit();
geu_enable_clk();
geu_reset_aes();
ret = asr_aes_setmode(AES_ENCRYPT, AES_ECB);
if(ret) {
printf("ecb encrypt set mode error\n");
goto exit;
}
ret = asr_aes_setkey((uint32_t *)key, keylen, use_rkek);
if(ret) {
printf("ecb encrypt set key error\n");
goto exit;
}
#if CONFIG_PXA_DMA
use_dma = (size >= ASR_AES_DMA_THRESHOLD);
if (use_dma)
ret = asr_aes_process_dma((uint32_t *)ptext, size, (uint32_t *)ctext);
else
#endif
ret = asr_aes_process_pio((uint32_t *)ptext, size, (uint32_t *)ctext);
if (ctext != ciphertext)
memcpy(ciphertext, ctext, size);
exit:
geu_disable_clk();
asr_geu_put();
if (ptext && (ptext != plaintext))
free(ptext);
if (ctext && (ctext != ciphertext))
free(ctext);
return ret;
}
int aes_ecb_decrypt_geu(const uint8_t *key, uint32_t keylen, bool use_rkek,\
const void* ciphertext, void* plaintext, size_t size)
{
int ret = 0;
#if CONFIG_PXA_DMA
bool use_dma = 0;
#endif
uint32_t crylen = 0;
void *ptext = NULL, *ctext = NULL;
uint8_t use_key[32];
if ((keylen > 32) && (keylen < 16)) {
printf("aes ecb decrypt key len %d error\n", keylen);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (key == NULL) {
memcpy(use_key, default_key, keylen);
} else {
memcpy(use_key, key, keylen);
}
crylen = (size + AES_ALG_MASK) & (~AES_ALG_MASK);
/* malloc tmp alignmask alignment mem to encrypt */
ptext = buf_align(plaintext, AES_ALG_MASK);
if (ptext != plaintext) {
ptext = memalign(16, crylen);
if (!ptext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memset(ptext, 0, crylen);
}
ctext = buf_align(ciphertext, AES_ALG_MASK);
if (ctext != ciphertext) {
ctext = memalign(16, crylen);
if (!ctext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memcpy(ctext, ciphertext, size);
}
asr_geu_get();
geu_reset_unit();
geu_enable_clk();
geu_reset_aes();
ret = asr_aes_setmode(AES_DECRYPT, AES_ECB);
if(ret) {
printf("ecb decrypt set mode error\n");
goto exit;
}
ret = asr_aes_setkey((uint32_t *)key, keylen, use_rkek);
if(ret) {
printf("ecb decrypt set key error\n");
goto exit;
}
#if CONFIG_PXA_DMA
use_dma = (size >= ASR_AES_DMA_THRESHOLD);
if (use_dma)
ret = asr_aes_process_dma((uint32_t *)ctext, size, (uint32_t *)ptext);
else
#endif
ret = asr_aes_process_pio((uint32_t *)ctext, size, (uint32_t *)ptext);
if (ptext != plaintext)
memcpy(plaintext, ptext, size);
exit:
geu_disable_clk();
asr_geu_put();
if (ptext && (ptext != plaintext))
free(ptext);
if (ctext && (ctext != ciphertext))
free(ctext);
return ret;
}
int aes_cbc_encrypt_geu(const uint8_t *iv, const uint8_t *key, uint32_t keylen, \
bool use_rkek, const void* plaintext, void* ciphertext, size_t size)
{
int ret = 0;
#if CONFIG_PXA_DMA
bool use_dma = 0;
#endif
uint32_t crylen = 0;
void *ptext = NULL, *ctext = NULL;
uint8_t use_key[32];
if ((keylen > 32) && (keylen < 16)) {
printf("aes cbc encrypt key len %d error\n", keylen);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (key == NULL) {
memcpy(use_key, default_key, keylen);
} else {
memcpy(use_key, key, keylen);
}
crylen = (size + AES_ALG_MASK) & (~AES_ALG_MASK);
/* if not align, malloc tmp alignmask */
ptext = buf_align(plaintext, AES_ALG_MASK);
if (ptext != plaintext) {
ptext = memalign(16, crylen);
if (!ptext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memcpy(ptext, plaintext, size);
}
ctext = buf_align(ciphertext, AES_ALG_MASK);
if (ctext != ciphertext) {
ctext = memalign(16, crylen);
if (!ctext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memset(ctext, 0, crylen);
}
asr_geu_get();
geu_reset_unit();
geu_enable_clk();
geu_reset_aes();
ret = asr_aes_setmode(AES_ENCRYPT, AES_CBC);
if(ret) {
printf("cbc encrypt: set mode error\n");
goto exit;
}
ret = asr_aes_setkey((uint32_t *)key, keylen, use_rkek);
if(ret) {
printf("cbc encrypt: set key error\n");
goto exit;
}
ret = asr_aes_setiv(iv);
if(ret) {
printf("cbc encrypt: set iv error\n");
goto exit;
}
#if CONFIG_PXA_DMA
use_dma = (size >= ASR_AES_DMA_THRESHOLD);
if (use_dma)
ret = asr_aes_process_dma((uint32_t *)ptext, size, (uint32_t *)ctext);
else
#endif
ret = asr_aes_process_pio((uint32_t *)ptext, size, (uint32_t *)ctext);
if (ctext != ciphertext)
memcpy(ciphertext, ctext, size);
exit:
geu_disable_clk();
asr_geu_put();
if (ptext && (ptext != plaintext))
free(ptext);
if (ctext && (ctext != ciphertext))
free(ctext);
return ret;
}
int aes_cbc_decrypt_geu(const uint8_t *iv, const uint8_t *key, uint32_t keylen, \
bool use_rkek, const void* ciphertext, void* plaintext, size_t size)
{
int ret = 0;
#if CONFIG_PXA_DMA
bool use_dma = 0;
#endif
uint32_t crylen = 0;
void *ptext = NULL, *ctext = NULL;
uint8_t use_key[32];
if ((keylen > 32) && (keylen < 16)) {
printf("aes cbc decrypt key len %d error\n", keylen);
return -1;
}
if ((key == NULL) && (use_rkek == false)) {
printf("%s error: key can't NULL when not use rkek\n", __func__);
return -1;
}
if (key == NULL) {
memcpy(use_key, default_key, keylen);
} else {
memcpy(use_key, key, keylen);
}
crylen = (size + AES_ALG_MASK) & (~AES_ALG_MASK);
/* if not align, malloc tmp alignmask */
ptext = buf_align(plaintext, AES_ALG_MASK);
if (ptext != plaintext) {
ptext = memalign(16, crylen);
if (!ptext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memset(ptext, 0, crylen);
}
ctext = buf_align(ciphertext, AES_ALG_MASK);
if (ctext != ciphertext) {
ctext = memalign(16, crylen);
if (!ctext) {
printf("%s: %d, malloc failed\n", __func__, __LINE__);
ret = -1;
goto exit;
}
memcpy(ctext, ciphertext, size);
}
asr_geu_get();
geu_reset_unit();
geu_enable_clk();
geu_reset_aes();
ret = asr_aes_setmode(AES_DECRYPT, AES_CBC);
if(ret) {
printf("cbc decrypt: set mode error\n");
goto exit;
}
ret = asr_aes_setkey((uint32_t *)key, keylen, use_rkek);
if(ret) {
printf("cbc decrypt: set key error\n");
goto exit;
}
ret = asr_aes_setiv(iv);
if(ret) {
printf("cbc decrypt: set iv error\n");
goto exit;
}
#if CONFIG_PXA_DMA
use_dma = (size >= ASR_AES_DMA_THRESHOLD);
if (use_dma)
ret = asr_aes_process_dma((uint32_t *)ctext, size, (uint32_t *)ptext);
else
#endif
ret = asr_aes_process_pio((uint32_t *)ctext, size, (uint32_t *)ptext);
if (ptext != plaintext)
memcpy(plaintext, ptext, size);
exit:
geu_disable_clk();
asr_geu_put();
if (ptext && (ptext != plaintext))
free(ptext);
if (ctext && (ctext != ciphertext))
free(ctext);
return ret;
}
#ifdef GEU_SELFTEST
static int asr_aes_ecb_sfotware_test(void)
{
#define DATA_SIZE 256*1024
#define BLOCK_SIZE 16
#define KEY_SIZE 32
uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext;
uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext;
plaintext = buf_align(plaintext_raw, 0xf);
ciphertext = buf_align(ciphertext_raw, 0xf);
memset(plaintext, 0xAB, DATA_SIZE);
memset(ciphertext, 0, DATA_SIZE);
uint8_t zero_key[KEY_SIZE] = {0x7a, 0xca, 0x6a, 0x07,\
0x78, 0x57, 0xe3, 0xf9,\
0xab, 0x30, 0xbb, 0xf2,\
0x07, 0xdd, 0x9f, 0x40,\
0xf7, 0xaf, 0x1f, 0x34,\
0xe0, 0xb8, 0x45, 0xda,\
0x12, 0x11, 0xee, 0x66,\
0x02, 0x51, 0x4c, 0x5f};
uint32_t key_schedule[AES_EXPAND_KEY_LENGTH/4] = {0};
aes_expand_key(zero_key, (u8 *)key_schedule);
for(uint32_t i = 0; i < DATA_SIZE; i += (AES_STATECOLS * 4))
{
aes_encrypt(plaintext + i, (u8 *)key_schedule, ciphertext + i);
}
for(uint32_t i = 0; i < DATA_SIZE; i += (AES_STATECOLS * 4))
{
aes_decrypt(ciphertext + i, (u8 *)key_schedule, ciphertext + i);
}
if (memcmp(plaintext, ciphertext, DATA_SIZE)) {
printf("sfot_plaintext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", plaintext[i]);
}
printf("soft_ciphertext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", ciphertext[i]);
}
printf("soft aes ecb test failed");
goto err;
}
printf("soft aes ecb test result: pass\n");
return 0;
err:
return -1;
}
static int asr_aes_test(void)
{
#define DATA_SIZE 0x850
#define BLOCK_SIZE 16
#define KEY_SIZE 32
uint8_t plaintext_raw[DATA_SIZE + 63], *plaintext;
uint8_t ciphertext_raw[DATA_SIZE + 63], *ciphertext;
plaintext = buf_align(plaintext_raw, 0xf);
ciphertext = buf_align(ciphertext_raw, 0xf);
memset(plaintext, 0xAB, DATA_SIZE);
memset(ciphertext, 0, DATA_SIZE);
uint8_t iv[BLOCK_SIZE];
uint8_t key[KEY_SIZE] = {0x7a, 0xca, 0x6a, 0x07,\
0x78, 0x57, 0xe3, 0xf9,\
0xab, 0x30, 0xbb, 0xf2,\
0x07, 0xdd, 0x9f, 0x40,\
0xf7, 0xaf, 0x1f, 0x34,\
0xe0, 0xb8, 0x45, 0xda,\
0x12, 0x11, 0xee, 0x66,\
0x02, 0x51, 0x4c, 0x5f};
/*step1: aes ecb test*/
if (0 > aes_ecb_encrypt(key, KEY_SIZE, true, plaintext, ciphertext, DATA_SIZE)) {
printf("aes_ecb_encrypt error\n");
goto err;
}
if (0 > aes_ecb_decrypt(key, KEY_SIZE, true, ciphertext, ciphertext, DATA_SIZE)) {
printf("aes_ecb_decrypt error\n");
goto err;
}
if (memcmp(plaintext, ciphertext, DATA_SIZE)) {
printf("plaintext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", plaintext[i]);
}
printf("ciphertext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", ciphertext[i]);
}
printf("aes ecb test failed");
goto err;
}
printf("aes ecb test result: pass\n");
#if 1
/*step2: aes cbc test*/
memset(iv, 0xB, BLOCK_SIZE);
memset(plaintext, 0xCD, DATA_SIZE);
memset(ciphertext, 0, DATA_SIZE);
if (0 > aes_cbc_encrypt(iv, key, KEY_SIZE, true, plaintext, ciphertext, DATA_SIZE)) {
printf("aes_cbc_encrypt error\n");
goto err;
}
if (0 > aes_cbc_decrypt(iv, key, KEY_SIZE, true, ciphertext, ciphertext, DATA_SIZE)) {
printf("aes_cbc_decrypt error\n");
goto err;
}
if (memcmp(plaintext, ciphertext, DATA_SIZE)) {
printf("plaintext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", plaintext[i]);
}
printf("ciphertext:\n");
for (uint32_t i = 0; i < DATA_SIZE; i++) {
if ((i % 30) == 0)
printf("\n");
printf("%02x ", ciphertext[i]);
}
printf("aes cbc test failed");
goto err;
}
printf("aes cbc test result: pass\n");
#endif
return 0;
err:
return -1;
}
void asr_geu_test_init(void)
{
uint32_t start = 0, time = 0;
printf("soft aes ecb start test:\n");
start = get_timer(0);
asr_aes_ecb_sfotware_test();
time = get_timer(start);
printf("soft aes ecb time = %d\n", time);
printf("aes ecb start test:\n");
start = get_timer(0);
asr_aes_test();
time = get_timer(start);
printf("hard aes ecb time = %d\n", time);
printf("aes fuse start test:\n");
geu_fuse_test();
printf("aes rng start test:\n");
geu_random_test();
}
#endif