| /* |
| * Key blob driver based on CAAM hardware |
| * |
| * Copyright (C) 2015 Freescale Semiconductor, Inc. |
| */ |
| |
| #include <linux/of_irq.h> |
| #include <linux/of_address.h> |
| |
| #include "compat.h" |
| #include "regs.h" |
| #include "jr.h" |
| #include "desc.h" |
| #include "intern.h" |
| #include "sm.h" |
| #include "caam_keyblob.h" |
| |
| #define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */ |
| |
| /** |
| * struct kb_device - the metadata of the caam key blob device node |
| * @dev: the actual misc device |
| */ |
| struct kb_device { |
| struct miscdevice misc_dev; |
| struct device *jr_dev; |
| }; |
| |
| /* |
| * Pseudo-synchronous ring access functions for carrying out key |
| * encapsulation and decapsulation |
| */ |
| |
| struct sm_key_job_result { |
| int error; |
| struct completion completion; |
| }; |
| |
| |
| static struct kb_device *kb_dev; |
| |
| static struct kb_device *kb_device_create(void); |
| static int kb_device_destroy(struct kb_device *kb_dev); |
| static int kb_open(struct inode *inode, struct file *file); |
| static int kb_release(struct inode *inode, struct file *file); |
| static void sm_key_job_done(struct device *dev, u32 *desc, |
| u32 err, void *context); |
| static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf, |
| int keylen, void __user *kmodbuf, void __user *outbuf); |
| static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf, |
| int bloblen, void __user *kmodbuf, void __user *outbuf); |
| static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
| static int caam_keyblob_probe(struct platform_device *pdev); |
| static int caam_keyblob_remove(struct platform_device *pdev); |
| |
| static int kb_open(struct inode *inode, struct file *file) |
| { |
| struct miscdevice *miscdev = file->private_data; |
| struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); |
| struct device *jr_dev; |
| |
| if (!dev->jr_dev) { |
| jr_dev = caam_jr_alloc(); |
| if (IS_ERR(jr_dev)) { |
| pr_err("Job Ring Device allocation for transform failed\n"); |
| return -ENOMEM; |
| } |
| pr_info("Allocate a job ring device\n"); |
| dev->jr_dev = jr_dev; |
| } |
| else { |
| pr_err("Already created a job ring device"); |
| return -EPERM; |
| } |
| |
| return 0; |
| } |
| |
| static int kb_release(struct inode *inode, struct file *file) |
| { |
| struct miscdevice *miscdev = file->private_data; |
| struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); |
| |
| if (dev && dev->jr_dev) { |
| caam_jr_free(dev->jr_dev); |
| pr_info("Free a job ring device\n"); |
| dev->jr_dev = NULL; |
| } |
| return 0; |
| } |
| |
| static void sm_key_job_done(struct device *dev, u32 *desc, |
| u32 err, void *context) |
| { |
| struct sm_key_job_result *res = context; |
| |
| res->error = err; /* save off the error for postprocessing */ |
| complete(&res->completion); /* mark us complete */ |
| } |
| |
| /* |
| * Construct a blob encapsulation job descriptor |
| * |
| * This function dynamically constructs a blob encapsulation job descriptor |
| * from the following arguments: |
| * |
| * - desc pointer to a pointer to the descriptor generated by this |
| * function. Caller will be responsible to kfree() this |
| * descriptor after execution. |
| * - keymod Physical pointer to a key modifier, which must reside in a |
| * contiguous piece of memory. Modifier will be assumed to be |
| * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long |
| * for a blob of type SM_GENMEM (see blobtype argument). |
| * - secretbuf Physical pointer to a secret, normally a black or red key, |
| * possibly residing within an accessible secure memory page, |
| * of the secret to be encapsulated to an output blob. |
| * - outbuf Physical pointer to the destination buffer to receive the |
| * encapsulated output. This buffer will need to be 48 bytes |
| * larger than the input because of the added encapsulation data. |
| * The generated descriptor will account for the increase in size, |
| * but the caller must also account for this increase in the |
| * buffer allocator. |
| * - secretsz Size of input secret, in bytes. This is limited to 65536 |
| * less the size of blob overhead, since the length embeds into |
| * DECO pointer in/out instructions. |
| * - keycolor Determines if the source data is covered (black key) or |
| * plaintext (red key). RED_KEY or BLACK_KEY are defined in |
| * for this purpose. |
| * - blobtype Determine if encapsulated blob should be a secure memory |
| * blob (SM_SECMEM), with partition data embedded with key |
| * material, or a general memory blob (SM_GENMEM). |
| * - auth If BLACK_KEY source is covered via AES-CCM, specify |
| * KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB). |
| * |
| * Upon completion, desc points to a buffer containing a CAAM job |
| * descriptor which encapsulates data into an externally-storable blob |
| * suitable for use across power cycles. |
| * |
| * This is an example of a black key encapsulation job into a general memory |
| * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note |
| * the output 48 bytes longer than the input: |
| * |
| * [00] B0800008 jobhdr: stidx=0 len=8 |
| * [01] 14400010 ld: ccb2-key len=16 offs=0 |
| * [02] 08144891 ptr->@0x08144891 |
| * [03] F800003A seqoutptr: len=58 |
| * [04] 01000000 out_ptr->@0x01000000 |
| * [05] F000000A seqinptr: len=10 |
| * [06] 09745090 in_ptr->@0x09745090 |
| * [07] 870D0004 operation: encap blob reg=memory, black, format=normal |
| * |
| * This is an example of a red key encapsulation job for storing a red key |
| * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset |
| * in the LOAD instruction; this accounts for blob permission storage: |
| * |
| * [00] B0800008 jobhdr: stidx=0 len=8 |
| * [01] 14400C08 ld: ccb2-key len=8 offs=12 |
| * [02] 087D0784 ptr->@0x087d0784 |
| * [03] F8000050 seqoutptr: len=80 |
| * [04] 09251BB2 out_ptr->@0x09251bb2 |
| * [05] F0000020 seqinptr: len=32 |
| * [06] 40000F31 in_ptr->@0x40000f31 |
| * [07] 870D0008 operation: encap blob reg=memory, red, sec_mem, |
| * format=normal |
| * |
| * Note: this function only generates 32-bit pointers at present, and should |
| * be refactored using a scheme that allows both 32 and 64 bit addressing |
| */ |
| |
| static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod, |
| void *secretbuf, dma_addr_t outbuf, |
| u16 secretsz, u8 keycolor, u8 blobtype, u8 auth) |
| { |
| u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; |
| u16 dsize, idx; |
| |
| memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); |
| idx = 1; |
| |
| /* |
| * Key modifier works differently for secure/general memory blobs |
| * This accounts for the permission/protection data encapsulated |
| * within the blob if a secure memory blob is requested |
| */ |
| if (blobtype == SM_SECMEM) |
| tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | |
| LDST_SRCDST_BYTE_KEY | |
| ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) |
| | (8 & LDST_LEN_MASK); |
| else /* is general memory blob */ |
| tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | |
| LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK); |
| |
| tmpdesc[idx++] = (u32)keymod; |
| |
| /* |
| * Encapsulation output must include space for blob key encryption |
| * key and MAC tag |
| */ |
| tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD); |
| tmpdesc[idx++] = (u32)outbuf; |
| |
| /* Input data, should be somewhere in secure memory */ |
| tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz; |
| tmpdesc[idx++] = (u32)secretbuf; |
| |
| /* Set blob encap, then color */ |
| tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB; |
| |
| if (blobtype == SM_SECMEM) |
| tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM; |
| |
| if (auth == KEY_COVER_CCM) |
| tmpdesc[idx] |= OP_PCL_BLOB_EKT; |
| |
| if (keycolor == BLACK_KEY) |
| tmpdesc[idx] |= OP_PCL_BLOB_BLACK; |
| |
| idx++; |
| tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); |
| dsize = idx * sizeof(u32); |
| |
| tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); |
| if (tdesc == NULL) |
| return 0; |
| |
| memcpy(tdesc, tmpdesc, dsize); |
| *desc = tdesc; |
| return dsize; |
| } |
| |
| /* |
| * Construct a blob decapsulation job descriptor |
| * |
| * This function dynamically constructs a blob decapsulation job descriptor |
| * from the following arguments: |
| * |
| * - desc pointer to a pointer to the descriptor generated by this |
| * function. Caller will be responsible to kfree() this |
| * descriptor after execution. |
| * - keymod Physical pointer to a key modifier, which must reside in a |
| * contiguous piece of memory. Modifier will be assumed to be |
| * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long |
| * for a blob of type SM_GENMEM (see blobtype argument). |
| * - blobbuf Physical pointer (into external memory) of the blob to |
| * be decapsulated. Blob must reside in a contiguous memory |
| * segment. |
| * - outbuf Physical pointer of the decapsulated output, possibly into |
| * a location within a secure memory page. Must be contiguous. |
| * - secretsz Size of encapsulated secret in bytes (not the size of the |
| * input blob). |
| * - keycolor Determines if decapsulated content is encrypted (BLACK_KEY) |
| * or left as plaintext (RED_KEY). |
| * - blobtype Determine if encapsulated blob should be a secure memory |
| * blob (SM_SECMEM), with partition data embedded with key |
| * material, or a general memory blob (SM_GENMEM). |
| * - auth If decapsulation path is specified by BLACK_KEY, then if |
| * AES-CCM is requested for key covering use KEY_COVER_CCM, else |
| * use AES-ECB (KEY_COVER_ECB). |
| * |
| * Upon completion, desc points to a buffer containing a CAAM job descriptor |
| * that decapsulates a key blob from external memory into a black (encrypted) |
| * key or red (plaintext) content. |
| * |
| * This is an example of a black key decapsulation job from a general memory |
| * blob. Notice the 16-byte key modifier in the LOAD instruction. |
| * |
| * [00] B0800008 jobhdr: stidx=0 len=8 |
| * [01] 14400010 ld: ccb2-key len=16 offs=0 |
| * [02] 08A63B7F ptr->@0x08a63b7f |
| * [03] F8000010 seqoutptr: len=16 |
| * [04] 01000000 out_ptr->@0x01000000 |
| * [05] F000003A seqinptr: len=58 |
| * [06] 01000010 in_ptr->@0x01000010 |
| * [07] 860D0004 operation: decap blob reg=memory, black, format=normal |
| * |
| * This is an example of a red key decapsulation job for restoring a red key |
| * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset |
| * in the LOAD instruction: |
| * |
| * [00] B0800008 jobhdr: stidx=0 len=8 |
| * [01] 14400C08 ld: ccb2-key len=8 offs=12 |
| * [02] 01000000 ptr->@0x01000000 |
| * [03] F8000020 seqoutptr: len=32 |
| * [04] 400000E6 out_ptr->@0x400000e6 |
| * [05] F0000050 seqinptr: len=80 |
| * [06] 08F0C0EA in_ptr->@0x08f0c0ea |
| * [07] 860D0008 operation: decap blob reg=memory, red, sec_mem, |
| * format=normal |
| * |
| * Note: this function only generates 32-bit pointers at present, and should |
| * be refactored using a scheme that allows both 32 and 64 bit addressing |
| */ |
| |
| static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf, |
| u8 *outbuf, u16 secretsz, u8 keycolor, |
| u8 blobtype, u8 auth) |
| { |
| u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; |
| u16 dsize, idx; |
| |
| memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); |
| idx = 1; |
| |
| /* Load key modifier */ |
| if (blobtype == SM_SECMEM) |
| tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | |
| LDST_SRCDST_BYTE_KEY | |
| ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) |
| | (8 & LDST_LEN_MASK); |
| else /* is general memory blob */ |
| tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | |
| LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK); |
| |
| tmpdesc[idx++] = (u32)keymod; |
| |
| /* Compensate BKEK + MAC tag over size of encapsulated secret */ |
| tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD); |
| tmpdesc[idx++] = (u32)blobbuf; |
| tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz; |
| tmpdesc[idx++] = (u32)outbuf; |
| |
| /* Decapsulate from secure memory partition to black blob */ |
| tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB; |
| |
| if (blobtype == SM_SECMEM) |
| tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM; |
| |
| if (auth == KEY_COVER_CCM) |
| tmpdesc[idx] |= OP_PCL_BLOB_EKT; |
| |
| if (keycolor == BLACK_KEY) |
| tmpdesc[idx] |= OP_PCL_BLOB_BLACK; |
| |
| idx++; |
| tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); |
| dsize = idx * sizeof(u32); |
| |
| tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); |
| if (tdesc == NULL) |
| return 0; |
| |
| memcpy(tdesc, tmpdesc, dsize); |
| *desc = tdesc; |
| return dsize; |
| } |
| |
| |
| |
| static int gen_mem_encap(struct device *jr_dev, void __user *secretbuf, |
| int keylen, void __user *kmodbuf, void __user *outbuf) |
| { |
| int retval = 0; |
| u32 dsize; |
| u32 __iomem *encapdesc = NULL; |
| dma_addr_t secret_dma = 0, keymod_dma = 0, outbuf_dma = 0; |
| u8 __iomem *lsecret = NULL, *lkeymod = NULL, *loutbuf = NULL; |
| struct sm_key_job_result testres; |
| |
| /* Build/map/flush the scret */ |
| lsecret = kmalloc(keylen, GFP_KERNEL | GFP_DMA); |
| if (!lsecret) { |
| dev_err(jr_dev, "%s: can't alloc for key\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| if (copy_from_user(lsecret, secretbuf, keylen)) { |
| dev_err(jr_dev, "%s: can't Copy for key\n", __func__); |
| retval = -EFAULT; |
| goto out; |
| } |
| secret_dma = dma_map_single(jr_dev, lsecret, keylen, |
| DMA_TO_DEVICE); |
| |
| /* Build/map/flush the key modifier */ |
| lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); |
| if (!lkeymod) { |
| dev_err(jr_dev, "%s: can't alloc for keymod\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) { |
| dev_err(jr_dev, "%s: can't Copy for keymod\n", __func__); |
| retval = -EFAULT; |
| goto out; |
| } |
| keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN, |
| DMA_TO_DEVICE); |
| |
| loutbuf = kmalloc(keylen + BLOB_OVERHEAD, GFP_KERNEL | GFP_DMA); |
| if (!lkeymod) { |
| dev_err(jr_dev, "%s: can't alloc for output\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen + BLOB_OVERHEAD, |
| DMA_FROM_DEVICE); |
| dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, (void *)secret_dma, outbuf_dma, |
| keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB); |
| if (!dsize) { |
| dev_err(jr_dev, "can't alloc an encapsulation descriptor\n"); |
| retval = -ENOMEM; |
| goto out; |
| } |
| init_completion(&testres.completion); |
| |
| retval = caam_jr_enqueue(jr_dev, encapdesc, sm_key_job_done, |
| &testres); |
| if (!retval) { |
| wait_for_completion_interruptible(&testres.completion); |
| dev_info(jr_dev, "job ring return %d\n", testres.error); |
| if (!testres.error) { |
| dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD, |
| DMA_FROM_DEVICE); |
| |
| if (copy_to_user(outbuf, loutbuf, keylen + BLOB_OVERHEAD)) { |
| retval = -EFAULT; |
| dev_err(jr_dev, "can't copy for output\n"); |
| goto out; |
| } |
| } |
| retval = testres.error; |
| } |
| |
| out: |
| if (outbuf_dma) |
| dma_unmap_single(jr_dev, outbuf_dma, keylen + BLOB_OVERHEAD, |
| DMA_FROM_DEVICE); |
| if (keymod_dma) |
| dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN, DMA_TO_DEVICE); |
| if (secret_dma) |
| dma_unmap_single(jr_dev, secret_dma, keylen, DMA_TO_DEVICE); |
| kfree(encapdesc); |
| kfree(lkeymod); |
| kfree(lsecret); |
| kfree(loutbuf); |
| |
| return retval; |
| } |
| |
| static int gen_mem_decap(struct device *jr_dev, void __user *keyblobbuf, |
| int bloblen, void __user *kmodbuf, void __user *outbuf) |
| { |
| int retval = 0; |
| int keylen = bloblen - BLOB_OVERHEAD; |
| u32 dsize; |
| dma_addr_t keyblob_dma = 0, keymod_dma = 0, outbuf_dma = 0; |
| u8 __iomem *lkeyblob = NULL, *lkeymod = NULL, *loutbuf = NULL; |
| struct sm_key_job_result testres; |
| u32 __iomem *decapdesc = NULL; |
| |
| /* Build/map/flush the scret */ |
| lkeyblob = kmalloc(bloblen, GFP_KERNEL | GFP_DMA); |
| if (!lkeyblob) { |
| dev_err(jr_dev, "%s: can't alloc for keylob\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| if (copy_from_user(lkeyblob, keyblobbuf, bloblen)) { |
| dev_err(jr_dev, "%s: can't Copy for keyblob\n", __func__); |
| retval = -EFAULT; |
| goto out; |
| } |
| keyblob_dma = dma_map_single(jr_dev, lkeyblob, bloblen, |
| DMA_TO_DEVICE); |
| |
| /* Build/map/flush the key modifier */ |
| lkeymod = kmalloc(GENMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA); |
| if (!lkeymod) { |
| dev_err(jr_dev, "%s: can't alloc for keymod\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| if (copy_from_user(lkeymod, kmodbuf, GENMEM_KEYMOD_LEN)) { |
| dev_err(jr_dev, "%s: can't Copy for keymod\n", __func__); |
| retval = -EFAULT; |
| goto out; |
| } |
| keymod_dma = dma_map_single(jr_dev, lkeymod, GENMEM_KEYMOD_LEN, |
| DMA_TO_DEVICE); |
| |
| loutbuf = kmalloc(keylen, GFP_KERNEL | GFP_DMA); |
| if (!loutbuf) { |
| dev_err(jr_dev, "%s: can't alloc for outbuf\n", __func__); |
| retval = -ENOMEM; |
| goto out; |
| } |
| outbuf_dma = dma_map_single(jr_dev, loutbuf, keylen, |
| DMA_FROM_DEVICE); |
| |
| /* Build the encapsulation job descriptor */ |
| dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, keyblob_dma, (u8 *)outbuf_dma, |
| keylen, RED_KEY, SM_GENMEM, KEY_COVER_ECB); |
| if (!dsize) { |
| dev_err(jr_dev, "can't alloc a decapsulation descriptor\n"); |
| retval = -ENOMEM; |
| goto out; |
| } |
| |
| init_completion(&testres.completion); |
| |
| retval = caam_jr_enqueue(jr_dev, decapdesc, sm_key_job_done, |
| &testres); |
| if (!retval) { |
| wait_for_completion_interruptible(&testres.completion); |
| dev_info(jr_dev, "job ring return %d\n", testres.error); |
| if (!testres.error) { |
| dma_sync_single_for_cpu(jr_dev, outbuf_dma, keylen, |
| DMA_FROM_DEVICE); |
| |
| if (copy_to_user(outbuf, loutbuf, keylen)) { |
| retval = -EFAULT; |
| goto out; |
| } |
| } |
| retval = testres.error; |
| } |
| |
| out: |
| if (outbuf_dma) |
| dma_unmap_single(jr_dev, outbuf_dma, keylen, |
| DMA_FROM_DEVICE); |
| if (keymod_dma) |
| dma_unmap_single(jr_dev, keymod_dma, GENMEM_KEYMOD_LEN, |
| DMA_TO_DEVICE); |
| if (keyblob_dma) |
| dma_unmap_single(jr_dev, keyblob_dma, bloblen, |
| DMA_TO_DEVICE); |
| kfree(decapdesc); |
| kfree(lkeymod); |
| kfree(lkeyblob); |
| kfree(loutbuf); |
| |
| return retval; |
| } |
| |
| |
| static long kb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| { |
| int retval = 0; |
| struct caam_kb_data kb_data; |
| struct miscdevice *miscdev = file->private_data; |
| struct kb_device *dev = container_of(miscdev, struct kb_device, misc_dev); |
| |
| if (copy_from_user(&kb_data, (void *)arg, sizeof(kb_data))) { |
| retval = -EFAULT; |
| goto err; |
| } |
| |
| if (!kb_data.rawkey || !kb_data.keyblob || |
| (kb_data.rawkey_len + BLOB_OVERHEAD != kb_data.keyblob_len) || |
| (kb_data.keymod_len != GENMEM_KEYMOD_LEN)) { |
| retval = -EINVAL; |
| goto err; |
| } |
| |
| printk(KERN_INFO"%s:rawkey_len %d, keyblob_len %d\n", |
| __func__, kb_data.rawkey_len, kb_data.keyblob_len); |
| |
| switch (cmd) { |
| case CAAM_KB_ENCRYPT: |
| { |
| retval = gen_mem_encap(dev->jr_dev, kb_data.rawkey, kb_data.rawkey_len, |
| kb_data.keymod, kb_data.keyblob); |
| break; |
| } |
| case CAAM_KB_DECRYPT: |
| { |
| retval = gen_mem_decap(dev->jr_dev, kb_data.keyblob, kb_data.keyblob_len, |
| kb_data.keymod, kb_data.rawkey); |
| break; |
| } |
| default: |
| return -ENOTTY; |
| } |
| |
| err: |
| return retval; |
| } |
| |
| static const struct file_operations kb_fops = { |
| .owner = THIS_MODULE, |
| .open = kb_open, |
| .release = kb_release, |
| .unlocked_ioctl = kb_ioctl, |
| }; |
| |
| static struct kb_device *kb_device_create(void) |
| { |
| struct kb_device *idev; |
| int ret; |
| |
| idev = kzalloc(sizeof(struct kb_device), GFP_KERNEL); |
| if (!idev) |
| return ERR_PTR(-ENOMEM); |
| |
| idev->misc_dev.minor = MISC_DYNAMIC_MINOR; |
| idev->misc_dev.name = "caam_kb"; |
| idev->misc_dev.fops = &kb_fops; |
| idev->misc_dev.parent = NULL; |
| ret = misc_register(&idev->misc_dev); |
| if (ret) { |
| pr_err("kb: failed to register misc device.\n"); |
| return ERR_PTR(ret); |
| } |
| |
| return idev; |
| } |
| |
| static int kb_device_destroy(struct kb_device *kb_dev) |
| { |
| if ((kb_dev) && (kb_dev->jr_dev)) { |
| caam_jr_free(kb_dev->jr_dev); |
| kb_dev->jr_dev = NULL; |
| } |
| |
| if (kb_dev) |
| misc_deregister(&kb_dev->misc_dev); |
| |
| return 0; |
| } |
| /* |
| * Probe key blob device |
| */ |
| static int caam_keyblob_probe(struct platform_device *pdev) |
| { |
| int err; |
| |
| dev_dbg(&pdev->dev, "%s enter\n", __func__); |
| kb_dev = kb_device_create(); |
| if (IS_ERR_OR_NULL(kb_dev)) { |
| err = PTR_ERR(kb_dev); |
| goto err; |
| } |
| dev_info(&pdev->dev, "caam keyblob initialized\n"); |
| return 0; |
| err: |
| return err; |
| } |
| |
| /* |
| * Remove key blob device |
| */ |
| static int caam_keyblob_remove(struct platform_device *pdev) |
| { |
| kb_device_destroy(kb_dev); |
| return 0; |
| } |
| |
| static struct of_device_id caam_keyblob_match[] = { |
| { |
| .compatible = "fsl,sec-v4.0-keyblob", |
| }, |
| { |
| .compatible = "fsl,sec4.0-keyblob", |
| }, |
| {}, |
| }; |
| |
| MODULE_DEVICE_TABLE(of, caam_keyblob_match); |
| |
| static struct platform_driver caam_keyblob_driver = { |
| .driver = { |
| .name = "caam_keyblob", |
| .owner = THIS_MODULE, |
| .of_match_table = caam_keyblob_match, |
| }, |
| .probe = caam_keyblob_probe, |
| .remove = caam_keyblob_remove, |
| }; |
| |
| static int __init keyblob_driver_init(void) |
| { |
| return platform_driver_register(&caam_keyblob_driver); |
| } |
| |
| static void __exit keyblob_driver_exit(void) |
| { |
| platform_driver_unregister(&caam_keyblob_driver); |
| } |
| |
| module_init(keyblob_driver_init); |
| module_exit(keyblob_driver_exit); |
| |
| |
| MODULE_LICENSE("Dual BSD/GPL"); |
| MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore"); |
| MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); |