iBoot/drivers/samsung/aes/aes.c

605 lines
13 KiB
C

/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <lib/libc.h>
#include <platform.h>
#include <platform/int.h>
#include <platform/clocks.h>
#include <platform/soc/hwclocks.h>
#include <sys.h>
#include "aes.h"
/* aes driver, copy and customize */
#define AES_MAX_BOUNCE_BUFFER 64
static volatile u_int32_t gAesIrqDoneFlag = 0;
static u_int8_t g_bounce_buffer[AES_MAX_BOUNCE_BUFFER] __attribute__ ((aligned (32)));
static int aes_inited = 0;
static int key_size_to_bytes(enum aes_key_size size)
{
return 16 + (size * 8);
}
void aes_init(void)
{
dprintf(DEBUG_SPEW,"aes_init()\n");
clock_gate(CLK_AES, true);
AES_MODULE_POWER_ON();
AesInit();
aes_inited = 1;
}
/*! \fn void AesInit(void)
* \brief power on and initialize AES module
* \param none
* \return none
*/
u_int32_t AesInit(void)
{
gAesIrqDoneFlag = 0;
/* install_int_handler(INT_AES, Isr_AesHandler, 0); */
/* unmask_int(INT_AES); */
rAES_IRQ_MASK = 0x00000000; /** Mask all interrupt source */
return 0;
}
/*! \fn void AesUninit(void)
* \brief release AES module
* \param none
* \return none
*/
u_int32_t AesUninit(void)
{
gAesIrqDoneFlag = 0;
AES_MODULE_POWER_OFF();
//rAES_IRQ_MASK = 0x00000000; /** Mask all interrupt source */
/* mask_int(INT_AES); */
// SysResetInterrupt(INT_AES);
return 0;
}
/*! \fn void AesOff(void)
* \brief Power Off AES module
* \param none
* \return
*/
void AesOff(void)
{
AES_MODULE_POWER_OFF(); /** AES module is disabled and preparation for clock down */
//while(!(rAES_POWER & 0x02)); /** ready for clock down */
}
/*! \fn void _AesSetKeyType(u_int32_t cipherKeyType)
* \brief power off AES module
* \param cipherKeyType cipher key type
* \return none
*/
void _AesSetKeyType(enum aes_key_type cipherKeyType)
{
rAES_CIPHERKEY_SEL = cipherKeyType;
#if AES_VERSION > 0
rAES_COMPLIMENT = ~rAES_CIPHERKEY_SEL;
#endif
}
/*! \fn void _AesSetKey(u_int8_t *pKeyArr)
* \brief set cipher keys into AES module
* \param[in] pKeyArr 128-bit Key
* \return none
*/
void _AesSetKey(u_int8_t *pKeyArr)
{
/*<<< joe.kang@H1 061212: EVT 2 new code 061212*/
u_int32_t index;
u_int32_t uLength;
volatile u_int32_t * reg;
if(rAES_CIPHERKEY_SEL == 0) /* 0 is a user defined key */
{
switch ((rAES_CFG & 0x30)>>4)
{
case 1: // 192 bit
reg = &rAES_KEY_MM;
uLength = 6;
break;
case 2: // 256 bit
reg = &rAES_KEY_MX;
uLength = 8;
break;
case 0: // 128 bit
default:
reg = &rAES_KEY_X;
uLength = 4;
break;
}
for(index = 0 ;index < uLength ;index ++)
{
#if AES_VERSION > 0
*(reg + index) = *(u_int32_t *)(pKeyArr + index * 4);
#else
*(reg + index) = swap32(*(u_int32_t *)(pKeyArr + index * 4));
#endif
}
}
}
/*! \fn void _AesClearKey(void)
* \brief clear cipher keys into AES module
* \param[in] void
* \return none
*/
void _AesClearKey(void)
{
/*<<< joe.kang@H1 061212: EVT 2 new code 061212*/
memset ((void *) &rAES_KEY_MX, 0, 32);
}
/*! \fn void _AesClearIV(void)
* \brief clear cipher keys into AES module
* \param[in] void
* \return none
*/
void _AesClearIV(void)
{
/*<<< joe.kang@H1 061212: EVT 2 new code 061212*/
memset ((void *) &rAES_IV_1, 0, 16);
}
/*! \fn void AesSoftwareReset(void)
* \brief apply software reset to AES module
* \param none
* \return none
*/
void AesSoftwareReset(void)
{
rAES_SWRST = 0x00000001; /** Software Reset for AES */
rAES_SWRST = 0x00000000; /** No Reset */
}
/*! \fn INT32T AesReadyToStart(void);
* @brief This function set configurations for ready to start AES Engine.
*
* @param NONE
* @return 0 if success. others if failed.
* @see AesNotifyComplete
*/
u_int32_t AesReadyToStart(void)
{
/* Set ready to start */
gAesIrqDoneFlag = 0;
return 0;
}
void AesSetVector(u_int8_t * pLocalIv)
{
int index;
volatile u_int32_t * reg;
if (pLocalIv == 0)
{
rAES_IV_1 = 0;
rAES_IV_2 = 0;
rAES_IV_3 = 0;
rAES_IV_4 = 0;
}
else
{
/*<<< joe.kang@H1 061212: EVT 2 new code 061212*/
reg = &rAES_IV_1;
for(index = 0 ;index < 4 ;index ++)
{
#if AES_VERSION > 0
*(reg + index) = *(u_int32_t *)(pLocalIv + index * 4);
#else
*(reg + index) = swap32(*(u_int32_t *)(pLocalIv + index * 4));
#endif
}
}
return;
}
/*! \fn void AesStartEncryption(u_int8_t *destAddr, u_int8_t *srcAddr, u_int32_t size, u_int32_t keyType, u_int32_t *keyArr)
* \brief encrypt data
* \param destAddr destination address
* \param srcAddr source address
* \param size number of bytes
* \param[in] keyArr cipher key array
* \return none
*/
void AesStartEncryption(
u_int8_t *destAddr,
u_int8_t *srcAddr,
u_int8_t *cryptoAddr,
u_int32_t size,
u_int32_t keyType,
u_int8_t *keyArr,
u_int32_t keySize,
bool bChainingMode,
u_int32_t srcSize,
u_int32_t dstSize,
u_int32_t cryptoSize,
u_int8_t *pIv)
{
/* Ready to start */
AesReadyToStart();
AesSoftwareReset();
AES_MODULE_POWER_ON();
// rAES_IRQ_MASK = 0x0000000F; /** Unmask all interrupt source */
_AesSetKeyType(keyType);
_AesSetKey(keyArr);
//if(bChainingMode == true)
//AesSetVector();
/** aes key size : 128bit, stay in pause state & wait for CPU's action, Encryption */
rAES_CFG = (0x3<<1);
AesSetCryption(true);
AesSetKeySize(keySize);
AesSetChainingMode(bChainingMode);
AesSetVector(pIv);
rAES_XFR_NUM = size; /** Total Transfer Number (number of bytes) */
rAES_TBUF_START = (u_int32_t)destAddr; /** Start Address of Target Buffer (byte aligned) */
rAES_TBUF_SIZE = dstSize; /** Size of Taget Buffer (byte aligned) */
rAES_SBUF_START = (u_int32_t)srcAddr; /** Start Address of Source Buffer (byte aligned) */
rAES_SBUF_SIZE = srcSize; /** Size of Source Buffer (byte aligned) */
rAES_CRYPT_START = (u_int32_t)cryptoAddr; /** Starting Address of Encryption in Source Buffer (byte aligned) */
rAES_CRYPT_SIZE = cryptoSize; /** Size of Encryption (16 byte aligned) */
gAesIrqDoneFlag = 0;
_AesStart();
}
/*! \fn void AesStartDecryption(u_int8_t *destAddr, u_int8_t *srcAddr, u_int32_t size, u_int32_t keyType, u_int32_t *keyArr)
* \brief decrypt data
* \param destAddr destination address
* \param srcAddr source address
* \param size number of bytes
* \param[in] keyArr cipher key array
* \return none
*/
void AesStartDecryption(
u_int8_t *destAddr,
u_int8_t *srcAddr,
u_int8_t *cryptoAddr,
u_int32_t size,
u_int32_t keyType,
u_int8_t *keyArr,
u_int32_t keySize,
bool bChainingMode,
u_int32_t srcSize,
u_int32_t dstSize,
u_int32_t cryptoSize,
u_int8_t *pIv)
{
/* Ready to start */
AesReadyToStart();
AesSoftwareReset();
AES_MODULE_POWER_ON();
_AesSetKeyType(keyType);
// rAES_IRQ_MASK = 0x0000000F; /** Unmask all interrupt source */
_AesSetKey(keyArr);
//if(bChainingMode == true)
//AesSetVector();
/** aes key size : 128bit, stay in pause state & wait for CPU's action, Decryption */
rAES_CFG = (0x3<<1);
AesSetCryption(false);
AesSetKeySize(keySize);
AesSetChainingMode(bChainingMode);
AesSetVector(pIv);
rAES_XFR_NUM = size;
rAES_TBUF_START = (u_int32_t)destAddr; /** Start Address of Target Buffer (number of bytes) */
rAES_TBUF_SIZE = dstSize; /** Size of Target Buffer (byte aligned) */
rAES_SBUF_START = (u_int32_t)srcAddr; /** Start Address of Source Buffer (byte aligned) */
rAES_SBUF_SIZE = srcSize; /** Unmask all interrupt source */
rAES_CRYPT_START = (u_int32_t)cryptoAddr; /** Starting Address of Decryption in Source Buffer (byte aligned) */
rAES_CRYPT_SIZE = cryptoSize; /** Size of Decryotion (16 byte aligned) */
gAesIrqDoneFlag = 0;
_AesStart();
}
/*! \fn void _AesStart(void)
* \brief start aes
* \param none
* \return none
*/
void _AesStart(void)
{
#if AES_SYNCH_START
rAES_ENDIAN = (1 << 1); // Set Synch-Start bit
#else
rAES_COMMAND = CMD_AES_START; // Set Asynch-Start bit
#endif
}
/*! \fn u_int32_t AesGetIrqStatus(void)
* \brief Get IRQ status return
* \param none
* \return none
*/
u_int32_t
AesGetIrqStatus(void)
{
return rAES_IRQ;
}
/*! \fn void AesGetIrqStatus(u_int32_t status)
* \brief Set IRQ status return
* \param IRQ status
* \return none
*/
void AesSetIrqStatus(u_int32_t status)
{
rAES_IRQ = status;
}
/*! \fn INT32T AesNotifyComplete(void);
* @remark This function must be implemented by apple. SAMSUNG just offer
* a reference code.
*
* @brief Nofity AES operation complete.
* @param NONE
* @return @c 0 if success. @c -1 if failed.
* @see AesWaitForComplete, AesReadyToStart
*/
u_int32_t AesNotifyComplete(void)
{
gAesIrqDoneFlag = 1;
return 0;
}
/*! \fn INT32T AesWaitForComplete(void);
* \remark This function must be implemented by apple. SAMSUNG just offer
* a reference code.
* \brief Wait until AES operation complete.
* \param NONE
* \return @c 0 if success. @c -1 if failed.
* \see AesNotifyComplete
*/
u_int32_t
AesWaitForComplete(void)
{
/* polling until AES I/O complete */
//while(gAesIrqDoneFlag == 0);
while( 0 == (rAES_IRQ & 0xf) ) ;
#if AES_SYNCH_START
/* synch zeroes XFR_NUM - must wait to avoid racing */
while( 0 != rAES_XFR_NUM ) ;
#endif
/*<<< joe.kang@H1 061212: EVT 2 new code 061212*/
_AesClearKey();
_AesClearIV();
// clear all pending IRQs
rAES_IRQ = 0xf;
return 0;
}
/*! \fn void Isr_AesHandler(void)
* \brief interrupt service routine
* \param none
* \return none
*/
void Isr_AesHandler(void *arg)
{
u_int32_t status;
status = rAES_IRQ;
dprintf(DEBUG_SPEW,"aes_int: status 0x%x\n", status);
#if 0
/* check the status */
if(status & AES_IRQ_XFR_DONE_BIT)
{
gAesIrqDoneFlag = 1;
}
if(status & AES_IRQ_TBUF_FULL_BIT)
{
g_pRomGlobals->gAesIrqDoneFlag = 1;
}
if(status & AES_IRQ_SBUF_EMPTY_BIT)
{
;
}
if(status & AES_IRQ_ILLEGAL_OP_BIT)
{
;
}
#endif
/* clear status register */
rAES_IRQ = status;
/* Notify to the module pended */
if (AesNotifyComplete() != 0)
{
panic("AesNotifyComplete() return !0");
}
}
/*! \fn void AesSetKeySize(void)
* \brief set key size
* \param none
* \return none
*/
void AesSetKeySize(enum aes_key_size keysize)
{
u_int32_t rdata;
u_int32_t wmask;
u_int32_t wdata;
wmask = (3<<4);
rdata = rAES_CFG & (~wmask);
wdata = rdata | (keysize<<4);
rAES_CFG = wdata;
}
/*! \fn void AesSetChainingMode(void)
* \brief select chaining Mode
* \param none
* \return none
*/
void AesSetChainingMode(bool bFlag)
{
u_int32_t rdata;
u_int32_t wmask;
u_int32_t wdata;
wmask = (1<<3);
rdata = rAES_CFG & (~wmask);
wdata = rdata | (bFlag<<3);
rAES_CFG = wdata;
}
/*! \fn void AesSetCryption(void)
* \brief select cryption mode
* \param none
* \return none
*/
void AesSetCryption(bool bFlag)
{
/**
* bFlag 0: decryption / 1: encryption
*/
u_int32_t rdata;
u_int32_t wmask;
u_int32_t wdata;
wmask = (1<<0);
rdata = rAES_CFG & (~wmask);
wdata = rdata | (bFlag<<0);
rAES_CFG = wdata;
}
bool
AesGetCryption(void)
{
bool result;
result = (bool)(rAES_CFG & 0x01);
return result;
}
/*!
*/
void
AesSetCommand(u_int32_t cmd)
{
rAES_COMMAND = cmd;
}
/*!
*/
void
AesSetSourceConfig(u_int32_t addr, u_int32_t size)
{
rAES_SBUF_START = addr;
if(size != 0xffffffff)
{
rAES_SBUF_SIZE = size;
}
}
/*!
*/
void
AesSetCryptConfig(u_int32_t addr, u_int32_t size)
{
rAES_CRYPT_START = addr;
if(size != 0xffffffff)
{
rAES_CRYPT_SIZE = size;
}
}
int
AES_CBC_DecryptInPlace(u_int8_t * pAddr, u_int32_t u32Len, u_int32_t keyType, u_int8_t * pKey, u_int8_t * pIv)
{
u_int8_t *addr = pAddr;
aes_init();
if ( AES_MAX_BOUNCE_BUFFER >= u32Len ) {
memcpy( g_bounce_buffer, pAddr, u32Len );
addr = g_bounce_buffer;
}
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, 0, 0);
AesStartDecryption((u_int8_t *)addr, (u_int8_t *)addr, (u_int8_t *)addr, u32Len, keyType, pKey, 0, 1, u32Len, u32Len, u32Len, pIv);
AesWaitForComplete();
if ( AES_MAX_BOUNCE_BUFFER >= u32Len ) {
memcpy( pAddr, addr, u32Len );
}
return 0;
}
bool
AES_CBC_EncryptInPlace(u_int8_t * pAddr, u_int32_t u32Len, u_int32_t keyType, u_int8_t * pKey, u_int8_t * pIv)
{
u_int8_t *addr = pAddr;
aes_init();
if ( AES_MAX_BOUNCE_BUFFER >= u32Len ) {
memcpy( g_bounce_buffer, pAddr, u32Len );
addr = g_bounce_buffer;
}
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, 0, 0);
AesStartEncryption((u_int8_t *)addr, (u_int8_t *)addr, (u_int8_t *)addr, u32Len, keyType, pKey, 0, 1, u32Len, u32Len, u32Len, pIv);
AesWaitForComplete();
if ( AES_MAX_BOUNCE_BUFFER >= u32Len ) {
memcpy( pAddr, addr, u32Len );
}
return 0;
}