diff options
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/dcp.c | 151 | ||||
-rw-r--r-- | drivers/crypto/dcp.h | 7 | ||||
-rw-r--r-- | drivers/crypto/dcp_bootstream_ioctl.h | 32 | ||||
-rw-r--r-- | drivers/crypto/padlock-aes.c | 4 |
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); |