aboutsummaryrefslogtreecommitdiffstats
path: root/security/smc/tf_crypto_des.c
diff options
context:
space:
mode:
authorTrusted Logic <smc_support@trusted-logic.com>2011-09-30 20:44:11 -0700
committerBrian Swetland <swetland@google.com>2011-10-06 16:30:06 -0700
commitc3984cfa72275ab5d79a0875486653c5b0998a50 (patch)
tree8daaa249617463591ba891856d07736bbde4a162 /security/smc/tf_crypto_des.c
parent2b42bfaf7291a591da87be3675b7b55e51ec83c4 (diff)
downloadkernel_samsung_tuna-c3984cfa72275ab5d79a0875486653c5b0998a50.zip
kernel_samsung_tuna-c3984cfa72275ab5d79a0875486653c5b0998a50.tar.gz
kernel_samsung_tuna-c3984cfa72275ab5d79a0875486653c5b0998a50.tar.bz2
OMAP4: SMC: 01.04 P6 Release
This patch is to port SMC 01.04 P6 Release for K3.0 Change-Id: Ia95fffd927b353eca3caf58bc4097eed97544705 Signed-off-by: Gonzalo Alexandre <alexandre.gonzalo@trusted-logic.com> Signed-off-by: Florian Sylvestre <florian.sylvestre@trusted-logic.com> Signed-off-by: Praneeth Bajjuri <praneeth@ti.com> Signed-off-by: Trusted Logic <smc_support@trusted-logic.com> Signed-off-by: Bryan Buckley <bryan.buckley@ti.com>
Diffstat (limited to 'security/smc/tf_crypto_des.c')
-rw-r--r--security/smc/tf_crypto_des.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/security/smc/tf_crypto_des.c b/security/smc/tf_crypto_des.c
new file mode 100644
index 0000000..716a60f
--- /dev/null
+++ b/security/smc/tf_crypto_des.c
@@ -0,0 +1,404 @@
+/**
+ * Copyright (c) 2011 Trusted Logic S.A.
+ * 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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "tf_defs.h"
+#include "tf_util.h"
+#include "tf_crypto.h"
+#include "tf_dma.h"
+
+#include <linux/io.h>
+#include <mach/io.h>
+
+/*
+ * DES Hardware Accelerator: Base address
+ */
+#define DES_REGS_HW_ADDR 0x480A5000
+
+/*
+ * CTRL register Masks
+ */
+#define DES_CTRL_OUTPUT_READY_BIT (1<<0)
+#define DES_CTRL_INPUT_READY_BIT (1<<1)
+
+#define DES_CTRL_GET_DIRECTION(x) (x&4)
+#define DES_CTRL_DIRECTION_DECRYPT 0
+#define DES_CTRL_DIRECTION_ENCRYPT (1<<2)
+
+#define DES_CTRL_GET_TDES(x) (x&8)
+#define DES_CTRL_TDES_DES 0
+#define DES_CTRL_TDES_TRIPLE_DES (1<<3)
+
+#define DES_CTRL_GET_MODE(x) (x&0x10)
+#define DES_CTRL_MODE_ECB 0
+#define DES_CTRL_MODE_CBC (1<<4)
+
+/*
+ * SYSCONFIG register masks
+ */
+#define DES_SYSCONFIG_DMA_REQ_IN_EN_BIT (1<<5)
+#define DES_SYSCONFIG_DMA_REQ_OUT_EN_BIT (1<<6)
+
+/*------------------------------------------------------------------------*/
+/* DES/DES3 Context */
+/*------------------------------------------------------------------------*/
+/**
+ * This structure contains the registers of the DES HW accelerator.
+ */
+struct des3_des_reg {
+ u32 DES_KEY3_L; /* DES Key 3 Low Register */
+ u32 DES_KEY3_H; /* DES Key 3 High Register */
+ u32 DES_KEY2_L; /* DES Key 2 Low Register */
+ u32 DES_KEY2_H; /* DES Key 2 High Register */
+ u32 DES_KEY1_L; /* DES Key 1 Low Register */
+ u32 DES_KEY1_H; /* DES Key 1 High Register */
+ u32 DES_IV_L; /* DES Initialization Vector Low Reg */
+ u32 DES_IV_H; /* DES Initialization Vector High Reg */
+ u32 DES_CTRL; /* DES Control Register */
+ u32 DES_LENGTH; /* DES Length Register */
+ u32 DES_DATA_L; /* DES Data Input/Output Low Register */
+ u32 DES_DATA_H; /* DES Data Input/Output High Register */
+ u32 DES_REV; /* DES Revision Register */
+ u32 DES_SYSCONFIG; /* DES Mask and Reset Register */
+ u32 DES_SYSSTATUS; /* DES System Status Register */
+};
+
+static struct des3_des_reg *des_reg;
+
+/*------------------------------------------------------------------------
+ *Forward declarations
+ *------------------------------------------------------------------------ */
+
+static bool tf_des_update_dma(u8 *src, u8 *dest, u32 nb_blocks);
+
+/*-------------------------------------------------------------------------
+ *Save HWA registers into the specified operation state structure
+ *-------------------------------------------------------------------------*/
+static void tf_des_save_registers(u32 DES_CTRL,
+ struct tf_crypto_des_operation_state *des_state)
+{
+ dprintk(KERN_INFO
+ "tf_des_save_registers in des_state=%p CTRL=0x%08x\n",
+ des_state, DES_CTRL);
+
+ /*Save the IV if we are in CBC mode */
+ if (DES_CTRL_GET_MODE(DES_CTRL) == DES_CTRL_MODE_CBC) {
+ des_state->DES_IV_L = INREG32(&des_reg->DES_IV_L);
+ des_state->DES_IV_H = INREG32(&des_reg->DES_IV_H);
+ }
+}
+
+/*-------------------------------------------------------------------------
+ *Restore the HWA registers from the operation state structure
+ *-------------------------------------------------------------------------*/
+static void tf_des_restore_registers(u32 DES_CTRL,
+ struct tf_crypto_des_operation_state *des_state)
+{
+ dprintk(KERN_INFO "tf_des_restore_registers from "
+ "des_state=%p CTRL=0x%08x\n",
+ des_state, DES_CTRL);
+
+ /*Write the IV ctx->reg */
+ if (DES_CTRL_GET_MODE(DES_CTRL) == DES_CTRL_MODE_CBC) {
+ OUTREG32(&des_reg->DES_IV_L, des_state->DES_IV_L);
+ OUTREG32(&des_reg->DES_IV_H, des_state->DES_IV_H);
+ }
+
+ /*Set the DIRECTION and CBC bits in the CTRL register.
+ *Keep the TDES from the accelerator */
+ OUTREG32(&des_reg->DES_CTRL,
+ (INREG32(&des_reg->DES_CTRL) & (1 << 3)) |
+ (DES_CTRL & ((1 << 2) | (1 << 4))));
+
+ /*Set the SYSCONFIG register to 0 */
+ OUTREG32(&des_reg->DES_SYSCONFIG, 0);
+}
+
+/*------------------------------------------------------------------------- */
+
+void tf_des_init(void)
+{
+ des_reg = omap_ioremap(DES_REGS_HW_ADDR, SZ_1M, MT_DEVICE);
+ if (des_reg == NULL)
+ panic("Unable to remap DES/3DES module");
+}
+
+void tf_des_exit(void)
+{
+ omap_iounmap(des_reg);
+}
+
+bool tf_des_update(u32 DES_CTRL,
+ struct tf_crypto_des_operation_state *des_state,
+ u8 *src, u8 *dest, u32 nb_blocks)
+{
+ u32 nbr_of_blocks;
+ u32 temp;
+ u8 *process_src;
+ u8 *process_dest;
+ u32 dma_use = PUBLIC_CRYPTO_DMA_USE_NONE;
+
+ /*
+ *Choice of the processing type
+ */
+ if (nb_blocks * DES_BLOCK_SIZE >= DMA_TRIGGER_IRQ_DES)
+ dma_use = PUBLIC_CRYPTO_DMA_USE_IRQ;
+
+ dprintk(KERN_INFO "tf_des_update: "
+ "src=0x%08x, dest=0x%08x, nb_blocks=0x%08x, dma_use=0x%08x\n",
+ (unsigned int)src, (unsigned int)dest,
+ (unsigned int)nb_blocks, (unsigned int)dma_use);
+
+ if (nb_blocks == 0) {
+ dprintk(KERN_INFO "tf_des_update: Nothing to process\n");
+ return true;
+ }
+
+ if (DES_CTRL_GET_DIRECTION(INREG32(&des_reg->DES_CTRL)) !=
+ DES_CTRL_GET_DIRECTION(DES_CTRL)) {
+ dprintk(KERN_WARNING "HWA configured for another direction\n");
+ return false;
+ }
+
+ /*Restore the registers of the accelerator from the operation state */
+ tf_des_restore_registers(DES_CTRL, des_state);
+
+ OUTREG32(&des_reg->DES_LENGTH, nb_blocks * DES_BLOCK_SIZE);
+
+ if (dma_use == PUBLIC_CRYPTO_DMA_USE_IRQ) {
+
+ /*perform the update with DMA */
+ if (!tf_des_update_dma(src, dest, nb_blocks))
+ return false;
+
+ } else {
+ u8 buf[DMA_TRIGGER_IRQ_DES];
+
+ process_src = process_dest = buf;
+
+ if (copy_from_user(buf, src, nb_blocks * DES_BLOCK_SIZE))
+ return false;
+
+ for (nbr_of_blocks = 0;
+ nbr_of_blocks < nb_blocks; nbr_of_blocks++) {
+
+ /*We wait for the input ready */
+ /*Crash the system as this should never occur */
+ if (tf_crypto_wait_for_ready_bit(
+ (u32 *)&des_reg->DES_CTRL,
+ DES_CTRL_INPUT_READY_BIT) !=
+ PUBLIC_CRYPTO_OPERATION_SUCCESS) {
+ panic("Wait too long for DES HW "
+ "accelerator Input data to be ready\n");
+ }
+
+ /*We copy the 8 bytes of data src->reg */
+ temp = (u32) BYTES_TO_LONG(process_src);
+ OUTREG32(&des_reg->DES_DATA_L, temp);
+ process_src += 4;
+ temp = (u32) BYTES_TO_LONG(process_src);
+ OUTREG32(&des_reg->DES_DATA_H, temp);
+ process_src += 4;
+
+ /*We wait for the output ready */
+ tf_crypto_wait_for_ready_bit_infinitely(
+ (u32 *)&des_reg->DES_CTRL,
+ DES_CTRL_OUTPUT_READY_BIT);
+
+ /*We copy the 8 bytes of data reg->dest */
+ temp = INREG32(&des_reg->DES_DATA_L);
+ LONG_TO_BYTE(process_dest, temp);
+ process_dest += 4;
+ temp = INREG32(&des_reg->DES_DATA_H);
+ LONG_TO_BYTE(process_dest, temp);
+ process_dest += 4;
+ }
+
+ if (copy_to_user(dest, buf, nb_blocks * DES_BLOCK_SIZE))
+ return false;
+ }
+
+ /*Save the accelerator registers into the operation state */
+ tf_des_save_registers(DES_CTRL, des_state);
+
+ dprintk(KERN_INFO "tf_des_update: Done\n");
+ return true;
+}
+
+/*------------------------------------------------------------------------- */
+/*
+ *Static function, perform DES encryption/decryption using the DMA for data
+ *transfer.
+ *
+ *inputs: src : pointer of the input data to process
+ * nb_blocks : number of block to process
+ * dma_use : PUBLIC_CRYPTO_DMA_USE_IRQ (use irq to monitor end of DMA)
+ *output: dest : pointer of the output data (can be eq to src)
+ */
+static bool tf_des_update_dma(u8 *src, u8 *dest, u32 nb_blocks)
+{
+ /*
+ *Note: The DMA only sees physical addresses !
+ */
+
+ int dma_ch0;
+ int dma_ch1;
+ struct omap_dma_channel_params ch0_parameters;
+ struct omap_dma_channel_params ch1_parameters;
+ u32 length = nb_blocks * DES_BLOCK_SIZE;
+ u32 length_loop = 0;
+ u32 nb_blocksLoop = 0;
+ struct tf_device *dev = tf_get_device();
+
+ dprintk(KERN_INFO
+ "tf_des_update_dma: In=0x%08x, Out=0x%08x, Len=%u\n",
+ (unsigned int)src, (unsigned int)dest,
+ (unsigned int)length);
+
+ /*lock the DMA */
+ mutex_lock(&dev->sm.dma_mutex);
+
+ if (tf_dma_request(&dma_ch0) != PUBLIC_CRYPTO_OPERATION_SUCCESS) {
+ mutex_unlock(&dev->sm.dma_mutex);
+ return false;
+ }
+ if (tf_dma_request(&dma_ch1) != PUBLIC_CRYPTO_OPERATION_SUCCESS) {
+ omap_free_dma(dma_ch0);
+ mutex_unlock(&dev->sm.dma_mutex);
+ return false;
+ }
+
+ while (length > 0) {
+
+ /*
+ * At this time, we are sure that the DMAchannels are available
+ * and not used by other public crypto operation
+ */
+
+ /*DMA used for Input and Output */
+ OUTREG32(&des_reg->DES_SYSCONFIG,
+ INREG32(&des_reg->DES_SYSCONFIG)
+ | DES_SYSCONFIG_DMA_REQ_OUT_EN_BIT
+ | DES_SYSCONFIG_DMA_REQ_IN_EN_BIT);
+
+ /* Check length */
+ if (length <= dev->dma_buffer_length)
+ length_loop = length;
+ else
+ length_loop = dev->dma_buffer_length;
+
+ /* The length is always a multiple of the block size */
+ nb_blocksLoop = length_loop / DES_BLOCK_SIZE;
+
+ /*
+ * Copy the data from the user input buffer into a preallocated
+ * buffer which has correct properties from efficient DMA
+ * transfers.
+ */
+ if (copy_from_user(dev->dma_buffer, src, length_loop)) {
+ omap_free_dma(dma_ch0);
+ omap_free_dma(dma_ch1);
+ mutex_unlock(&dev->sm.dma_mutex);
+ return false;
+ }
+
+ /* DMA1: Mem -> DES */
+ tf_dma_set_channel_common_params(&ch0_parameters,
+ nb_blocksLoop,
+ DMA_CEN_Elts_per_Frame_DES,
+ DES_REGS_HW_ADDR + 0x28,
+ dev->dma_buffer_phys,
+ OMAP44XX_DMA_DES_P_DATA_IN_REQ);
+
+ ch0_parameters.src_amode = OMAP_DMA_AMODE_POST_INC;
+ ch0_parameters.dst_amode = OMAP_DMA_AMODE_CONSTANT;
+ ch0_parameters.src_or_dst_synch = OMAP_DMA_DST_SYNC;
+
+ dprintk(KERN_INFO
+ "tf_des_update_dma: omap_set_dma_params(ch0)\n");
+ omap_set_dma_params(dma_ch0, &ch0_parameters);
+
+ /* DMA2: DES -> Mem */
+ tf_dma_set_channel_common_params(&ch1_parameters,
+ nb_blocksLoop,
+ DMA_CEN_Elts_per_Frame_DES,
+ dev->dma_buffer_phys,
+ DES_REGS_HW_ADDR + 0x28,
+ OMAP44XX_DMA_DES_P_DATA_OUT_REQ);
+
+ ch1_parameters.src_amode = OMAP_DMA_AMODE_CONSTANT;
+ ch1_parameters.dst_amode = OMAP_DMA_AMODE_POST_INC;
+ ch1_parameters.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+
+ dprintk(KERN_INFO "tf_des_update_dma: "
+ "omap_set_dma_params(ch1)\n");
+ omap_set_dma_params(dma_ch1, &ch1_parameters);
+
+ wmb();
+
+ dprintk(KERN_INFO
+ "tf_des_update_dma: Start DMA channel %d\n",
+ (unsigned int)dma_ch0);
+ tf_dma_start(dma_ch0, OMAP_DMA_BLOCK_IRQ);
+
+ dprintk(KERN_INFO
+ "tf_des_update_dma: Start DMA channel %d\n",
+ (unsigned int)dma_ch1);
+ tf_dma_start(dma_ch1, OMAP_DMA_BLOCK_IRQ);
+ tf_dma_wait(2);
+
+ /* Unset DMA synchronisation requests */
+ OUTREG32(&des_reg->DES_SYSCONFIG,
+ INREG32(&des_reg->DES_SYSCONFIG)
+ & (~DES_SYSCONFIG_DMA_REQ_OUT_EN_BIT)
+ & (~DES_SYSCONFIG_DMA_REQ_IN_EN_BIT));
+
+ omap_clear_dma(dma_ch0);
+ omap_clear_dma(dma_ch1);
+
+ /*
+ * The dma transfer is complete
+ */
+
+ /*The DMA output is in the preallocated aligned buffer
+ *and needs to be copied to the output buffer.*/
+ if (copy_to_user(dest, dev->dma_buffer, length_loop)) {
+ omap_free_dma(dma_ch0);
+ omap_free_dma(dma_ch1);
+ mutex_unlock(&dev->sm.dma_mutex);
+ return false;
+ }
+
+ src += length_loop;
+ dest += length_loop;
+ length -= length_loop;
+ }
+
+ /* For safety reasons, let's clean the working buffer */
+ memset(dev->dma_buffer, 0, length_loop);
+
+ /* Release the DMA */
+ omap_free_dma(dma_ch0);
+ omap_free_dma(dma_ch1);
+
+ mutex_unlock(&dev->sm.dma_mutex);
+
+ dprintk(KERN_INFO "tf_des_update_dma: Success\n");
+
+ return true;
+}