summaryrefslogtreecommitdiff
path: root/drivers/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/dcp.c151
-rw-r--r--drivers/crypto/dcp.h7
-rw-r--r--drivers/crypto/dcp_bootstream_ioctl.h32
-rw-r--r--drivers/crypto/padlock-aes.c4
4 files changed, 190 insertions, 4 deletions
diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c
index a72d73382778..8b54b127d6d0 100644
--- a/drivers/crypto/dcp.c
+++ b/drivers/crypto/dcp.c
@@ -17,10 +17,16 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/bitops.h>
#include <linux/crypto.h>
#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
#include <crypto/algapi.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
@@ -29,6 +35,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -36,6 +43,13 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include "dcp.h"
+#include "dcp_bootstream_ioctl.h"
+
+/* Following data only used by DCP bootstream interface */
+struct dcpboot_dma_area {
+ struct dcp_hw_packet hw_packet;
+ uint16_t block[16];
+};
struct dcp {
struct device *dev;
@@ -55,6 +69,10 @@ struct dcp {
struct dcp_hash_coherent_block *buf1_desc;
struct dcp_hash_coherent_block *buf2_desc;
struct dcp_hash_coherent_block *user_buf_desc;
+
+ /* Following data only used by DCP bootstream interface */
+ struct dcpboot_dma_area *dcpboot_dma_area;
+ dma_addr_t dcpboot_dma_area_phys;
};
/* cipher flags */
@@ -1245,6 +1263,106 @@ static irqreturn_t dcp_irq(int irq, void *context)
return dcp_common_irq(irq, context);
}
+/* DCP bootstream verification interface: uses OTP key for crypto */
+static int dcp_bootstream_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcpboot_dma_area *da = sdcp->dcpboot_dma_area;
+ void __user *argp = (void __user *)arg;
+ int chan = ROM_DCP_CHAN;
+ unsigned long timeout;
+ struct mutex *mutex;
+ int retVal;
+
+ /* be paranoid */
+ if (sdcp == NULL)
+ return -EBADF;
+
+ if (cmd != DBS_ENC && cmd != DBS_DEC)
+ return -EINVAL;
+
+ /* copy to (aligned) block */
+ if (copy_from_user(da->block, argp, 16))
+ return -EFAULT;
+
+ mutex = &sdcp->op_mutex[chan];
+ mutex_lock(mutex);
+
+ __raw_writel(-1, sdcp->dcp_regs_base +
+ HW_DCP_CHnSTAT_CLR(ROM_DCP_CHAN));
+ __raw_writel(BF(ROM_DCP_CHAN_MASK, DCP_STAT_IRQ),
+ sdcp->dcp_regs_base + HW_DCP_STAT_CLR);
+
+ da->hw_packet.pNext = 0;
+ da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE |
+ BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY |
+ BM_DCP_PACKET1_INTERRUPT |
+ (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0);
+ da->hw_packet.pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) |
+ BF(0, DCP_PACKET2_KEY_SELECT) |
+ BF(BV_DCP_PACKET2_CIPHER_MODE__ECB, DCP_PACKET2_CIPHER_MODE) |
+ BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128, DCP_PACKET2_CIPHER_SELECT);
+ da->hw_packet.pSrc = sdcp->dcpboot_dma_area_phys +
+ offsetof(struct dcpboot_dma_area, block);
+ da->hw_packet.pDst = da->hw_packet.pSrc; /* in-place */
+ da->hw_packet.size = 16;
+ da->hw_packet.pPayload = 0;
+ da->hw_packet.stat = 0;
+
+ /* Load the work packet pointer and bump the channel semaphore */
+ __raw_writel(sdcp->dcpboot_dma_area_phys +
+ offsetof(struct dcpboot_dma_area, hw_packet),
+ sdcp->dcp_regs_base + HW_DCP_CHnCMDPTR(ROM_DCP_CHAN));
+
+ sdcp->wait[chan] = 0;
+ __raw_writel(BF(1, DCP_CHnSEMA_INCREMENT),
+ sdcp->dcp_regs_base + HW_DCP_CHnSEMA(ROM_DCP_CHAN));
+
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0)
+ cpu_relax();
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(sdcp->dev,
+ "Timeout while waiting for operation to complete\n");
+ retVal = -ETIMEDOUT;
+ goto exit;
+ }
+
+ if ((__raw_readl(sdcp->dcp_regs_base + HW_DCP_CHnSTAT(ROM_DCP_CHAN))
+ & 0xff) != 0) {
+ dev_err(sdcp->dev, "Channel stat error 0x%02x\n",
+ __raw_readl(sdcp->dcp_regs_base +
+ HW_DCP_CHnSTAT(ROM_DCP_CHAN)) & 0xff);
+ retVal = -EFAULT;
+ goto exit;
+ }
+
+ if (copy_to_user(argp, da->block, 16)) {
+ retVal = -EFAULT;
+ goto exit;
+ }
+
+ retVal = 0;
+
+exit:
+ mutex_unlock(mutex);
+ return retVal;
+}
+
+static const struct file_operations dcp_bootstream_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dcp_bootstream_ioctl,
+};
+
+static struct miscdevice dcp_bootstream_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dcpboot",
+ .fops = &dcp_bootstream_fops,
+};
+
static int dcp_probe(struct platform_device *pdev)
{
struct dcp *sdcp = NULL;
@@ -1439,9 +1557,29 @@ static int dcp_probe(struct platform_device *pdev)
}
}
+ /* register dcpboot interface to allow apps (such as kobs-ng) to
+ * verify files (such as the bootstream) using the OTP key for crypto */
+ ret = misc_register(&dcp_bootstream_misc);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Unable to register misc device\n");
+ goto err_unregister_sha1;
+ }
+
+ sdcp->dcpboot_dma_area = dma_alloc_coherent(&pdev->dev,
+ sizeof(*sdcp->dcpboot_dma_area), &sdcp->dcpboot_dma_area_phys,
+ GFP_KERNEL);
+ if (sdcp->dcpboot_dma_area == NULL) {
+ dev_err(&pdev->dev,
+ "Unable to allocate DMAable memory \
+ for dcpboot interface\n");
+ goto err_dereg;
+ }
+
dev_notice(&pdev->dev, "DCP crypto enabled.!\n");
return 0;
+err_dereg:
+ misc_deregister(&dcp_bootstream_misc);
err_unregister_sha1:
crypto_unregister_shash(&dcp_sha1_alg);
err_unregister_aes_cbc:
@@ -1487,8 +1625,19 @@ static int dcp_remove(struct platform_device *pdev)
sdcp->user_buf_desc, sdcp->user_buf_desc->my_phys);
}
+ if (sdcp->dcpboot_dma_area) {
+ dma_free_coherent(&pdev->dev, sizeof(*sdcp->dcpboot_dma_area),
+ sdcp->dcpboot_dma_area, sdcp->dcpboot_dma_area_phys);
+ misc_deregister(&dcp_bootstream_misc);
+ }
+
+
crypto_unregister_shash(&dcp_sha1_alg);
- crypto_unregister_shash(&dcp_sha256_alg);
+
+ if (__raw_readl(sdcp->dcp_regs_base + HW_DCP_CAPABILITY1) &
+ BF_DCP_CAPABILITY1_HASH_ALGORITHMS(
+ BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256))
+ crypto_unregister_shash(&dcp_sha256_alg);
crypto_unregister_alg(&dcp_aes_cbc_alg);
crypto_unregister_alg(&dcp_aes_ecb_alg);
diff --git a/drivers/crypto/dcp.h b/drivers/crypto/dcp.h
index 00cd27b479c0..a4db91334d06 100644
--- a/drivers/crypto/dcp.h
+++ b/drivers/crypto/dcp.h
@@ -19,7 +19,12 @@
#define HASH_CHAN 0
#define HASH_MASK (1 << HASH_CHAN)
-#define ALL_MASK (CIPHER_MASK | HASH_MASK)
+/* DCP boostream interface uses this channel (same as the ROM) */
+#define ROM_DCP_CHAN 3
+#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN)
+
+
+#define ALL_MASK (CIPHER_MASK | HASH_MASK | ROM_DCP_CHAN_MASK)
/* Defines the initialization value for the dcp control register */
#define DCP_CTRL_INIT \
diff --git a/drivers/crypto/dcp_bootstream_ioctl.h b/drivers/crypto/dcp_bootstream_ioctl.h
new file mode 100644
index 000000000000..7c0c07d5a72d
--- /dev/null
+++ b/drivers/crypto/dcp_bootstream_ioctl.h
@@ -0,0 +1,32 @@
+/*
+ * Freescale DCP driver for bootstream update. Only handles the OTP KEY
+ * case and can only encrypt/decrypt.
+ *
+ * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
+ *
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef DCP_BOOTSTREAM_IOCTL_H
+#define DCP_BOOTSTREAM_IOCTL_H
+
+/* remember to have included the proper _IO definition
+ * file before hand.
+ * For user space it's <sys/ioctl.h>
+ */
+
+#define DBS_IOCTL_BASE 'd'
+
+#define DBS_ENC _IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16])
+#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16])
+
+#endif
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index a9952b1236b0..84c51e177269 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -236,7 +236,7 @@ static inline void ecb_crypt(const u8 *in, u8 *out, u32 *key,
/* Padlock in ECB mode fetches at least ecb_fetch_bytes of data.
* We could avoid some copying here but it's probably not worth it.
*/
- if (unlikely(((unsigned long)in & PAGE_SIZE) + ecb_fetch_bytes > PAGE_SIZE)) {
+ if (unlikely(((unsigned long)in & ~PAGE_MASK) + ecb_fetch_bytes > PAGE_SIZE)) {
ecb_crypt_copy(in, out, key, cword, count);
return;
}
@@ -248,7 +248,7 @@ static inline u8 *cbc_crypt(const u8 *in, u8 *out, u32 *key,
u8 *iv, struct cword *cword, int count)
{
/* Padlock in CBC mode fetches at least cbc_fetch_bytes of data. */
- if (unlikely(((unsigned long)in & PAGE_SIZE) + cbc_fetch_bytes > PAGE_SIZE))
+ if (unlikely(((unsigned long)in & ~PAGE_MASK) + cbc_fetch_bytes > PAGE_SIZE))
return cbc_crypt_copy(in, out, key, iv, cword, count);
return rep_xcrypt_cbc(in, out, key, iv, cword, count);