]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
MLK-9710-11 Add internal key cover and external blob export/import to prototype SM-API
authorSteve Cornelius <steve.cornelius@freescale.com>
Wed, 24 Jul 2013 03:49:29 +0000 (20:49 -0700)
committerNitin Garg <nitin.garg@freescale.com>
Fri, 16 Jan 2015 03:19:55 +0000 (21:19 -0600)
Extended/amended the prototype SM-API with the following functions:
- Added key covering (blackening) function in-place to a keyslot
- Added export operation to encapsulate data to external memory as a
  secure memory blob (including descriptor capable of secure memory or
  general memory blob generation)
- Removed in-place blob encapsulation
- Added import operation to decapsulate a blob from external memory into
  secure memory (including descriptor capable of general memory or secure
  memory content decapsulation)
- Removed in-place blob decapsulation

[<vicki.milhoan@freescale.com>: Edited to apply to 3.10]
Signed-off-by: Steve Cornelius <steve.cornelius@freescale.com>
Signed-off-by: Victoria Milhoan <vicki.milhoan@freescale.com>
(cherry picked from commit c577769ed0347bb4e3428b5696fb7f209af0a7ad)

drivers/crypto/caam/sm.h
drivers/crypto/caam/sm_store.c

index da14a9481c7db724e431af52d9cc21e71c87c2b0..2f97f69120f6868e2ac75cbe834d2e957d31c214 100644 (file)
 #define SM_PERM_WRITE 0x02
 #define SM_PERM_BLOB 0x03
 
+/* Define treatment of secure memory vs. general memory blobs */
+#define SM_SECMEM 0
+#define SM_GENMEM 1
+
+/* Define treatment of red/black keys */
+#define RED_KEY 0
+#define BLACK_KEY 1
+
+/* Define key encryption/covering options */
+#define KEY_COVER_ECB 0        /* cover key in AES-ECB */
+#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
+
+/*
+ * Round a key size up to an AES blocksize boundary so to allow for
+ * padding out to a full block
+ */
+#define AES_BLOCK_PAD(x) ((x % 16) ? ((x >> 4) + 1) << 4 : x)
+
+#define BLOB_OVERHEAD (16 + 8) /* BKEK + MAC tag storage in any blob */
 
 /* Keystore maintenance functions */
 void sm_init_keystore(struct device *dev);
@@ -30,6 +49,16 @@ extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
                                 const u8 *key_data, u32 key_length);
 extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
                                 u32 key_length, u8 *key_data);
+extern int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+                                u16 key_length, u8 keyauth);
+extern int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot,
+                                  u8 keycolor, u8 keyauth, u8 *outbuf,
+                                  u16 keylen, u8 *keymod);
+extern int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot,
+                                  u8 keycolor, u8 keyauth, u8 *inbuf,
+                                  u16 keylen, u8 *keymod);
+
+/* Prior functions from legacy API, deprecated */
 extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit,
                                        u32 inslot, u32 outslot, u16 secretlen,
                                        u8 *keymod, u16 keymodlen);
@@ -45,7 +74,8 @@ struct keystore_data_slot_info {
 
 /* Data structure to hold keystore information */
 struct keystore_data {
-       void    *base_address;  /* Base of the Secure Partition */
+       void    *base_address;  /* Virtual base of secure memory pages */
+       void    *phys_address;  /* Physical base of secure memory pages */
        u32     slot_count;     /* Number of slots in the keystore */
        struct keystore_data_slot_info *slot; /* Per-slot information */
 };
@@ -55,6 +85,7 @@ struct sm_page_descriptor {
        u16 phys_pagenum;       /* may be discontiguous */
        u16 own_part;           /* Owning partition */
        void *pg_base;          /* Calculated virtual address */
+       void *pg_phys;          /* Calculated physical address */
        struct keystore_data *ksdata;
 };
 
@@ -80,6 +111,7 @@ struct caam_drv_private_sm {
        int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot);
        int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot);
        void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle);
+       void *(*slot_get_physical)(struct device *dev, u32 unit, u32 handle);
        u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle);
        u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle);
        u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle);
index e50e63b2ce075b219783deff1869a042aed7e6c3..007b8753ba84fa06f40a06c9cd718eac117f536b 100644 (file)
@@ -37,6 +37,9 @@
 #include "error.h"
 #include "sm.h"
 
+#define SECMEM_KEYMOD_LEN 8
+#define GENMEM_KEYMOD_LEN 16
+
 #ifdef SM_DEBUG_CONT
 void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
 {
@@ -53,28 +56,33 @@ void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
 }
 #endif
 
+#define INITIAL_DESCSZ 16      /* size of tmp buffer for descriptor const. */
+
 /*
- * Construct a secure memory blob encapsulation job descriptor
+ * Construct a black key conversion job descriptor
+ *
+ * This function constructs a job descriptor capable of performing
+ * a key blackening operation on a plaintext secure memory resident object.
  *
- * - desc      pointer to hold new (to be allocated) pointer to the generated
- *             descriptor for later use. Calling thread can kfree the
+ * - 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 key modifier (contiguous piece).
- * - keymodsz  Size of key modifier in bytes (should normally be 8).
- * - secretbuf Physical pointer (within an accessible secure memory page)
- *             of the secret to be encapsulated.
- * - outbuf    Physical pointer (within an accessible secure memory page)
- *             of the encapsulated output. This will be larger than the
- *             input secret because of the added encapsulation data.
- * - secretsz  Size of input secret, in bytes.
- * - auth      If nonzero, use AES-CCM for encapsulation, else use ECB
+ * - key       physical pointer to the plaintext, which will also hold
+ *             the result. Since encryption occurs in place, caller must
+ *              ensure that the space is large enough to accommodate the
+ *              blackened key
+ * - keysz     size of the plaintext
+ * - auth      if a CCM-covered key is required, use KEY_COVER_CCM, else
+ *             use KEY_COVER_ECB.
+ *
+ * KEY to key1 from @key_addr LENGTH 16 BYTES;
+ * FIFO STORE from key1[ecb] TO @key_addr LENGTH 16 BYTES;
+ *
+ * Note that this variant uses the JDKEK only; it does not accommodate the
+ * trusted key encryption key at this time.
  *
- * Note: this uses 32-bit pointers at present
  */
-#define INITIAL_DESCSZ 16      /* size of tmp buffer for descriptor const. */
-static int blob_encap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz,
-                          dma_addr_t secretbuf, dma_addr_t outbuf,
-                          u16 secretsz, bool auth)
+static int blacken_key_jobdesc(u32 **desc, void *key, u16 keysz, bool auth)
 {
        u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
        u16 dsize, idx;
@@ -82,26 +90,155 @@ static int blob_encap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz,
        memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
        idx = 1;
 
-       /* Load key modifier */
-       tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
-                        ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) |
-                        (keymodsz & LDST_LEN_MASK);
+       /* Load key to class 1 key register */
+       tmpdesc[idx++] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+       tmpdesc[idx++] = (u32)key;
+
+       /* ...and write back out via FIFO store*/
+       tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+
+       /* plus account for ECB/CCM option in FIFO_STORE */
+       if (auth == KEY_COVER_ECB)
+               tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
+       else
+               tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
+
+       idx++;
+       tmpdesc[idx++] = (u32)key;
+
+       /* finish off the job header */
+       tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+       dsize = idx * sizeof(u32);
+
+       /* now allocate execution buffer and coat it with executable */
+       tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+       if (tdesc == NULL)
+               return 0;
+
+       memcpy(tdesc, tmpdesc, dsize);
+       *desc = tdesc;
+
+       return dsize;
+}
+
+/*
+ * 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;
 
-       /* Encapsulate to secure memory */
+       /*
+        * Encapsulation output must include space for blob key encryption
+        * key and MAC tag (32 + 16)
+        */
+       tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + (32 + 16));
+       tmpdesc[idx++] = (u32)outbuf;
+
+       /* Input data, should be somewhere in secure memory */
        tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz;
        tmpdesc[idx++] = (u32)secretbuf;
 
-       /* Add space for BKEK and MAC tag */
-       tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + (32 + 16));
+       /* Set blob encap, then color */
+       tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
 
-       tmpdesc[idx++] = (u32)outbuf;
-       tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB |
-                    OP_PCL_BLOB_PTXT_SECMEM;
-       if (auth)
+       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);
@@ -116,25 +253,71 @@ static int blob_encap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz,
 }
 
 /*
- * Construct a secure memory blob decapsulation job descriptor
+ * Construct a blob decapsulation job descriptor
  *
- * - desc      pointer to hold new (to be allocated) pointer to the generated
- *             descriptor for later use. Calling thread can kfree the
+ * 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 key modifier (contiguous piece).
- * - keymodsz  Size of key modifier in bytes (should normally be 16).
- * - blobbuf   Physical pointer (within an accessible secure memory page)
- *             of the blob to be decapsulated.
- * - outbuf    Physical pointer (within an accessible secure memory page)
- *             of the decapsulated output.
- * - secretsz  Size of input blob, in bytes.
- * - auth      If nonzero, assume AES-CCM for decapsulation, else use ECB
+ * - 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
  *
- * Note: this uses 32-bit pointers at present
+ * 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_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz,
-                          dma_addr_t blobbuf, dma_addr_t outbuf,
-                          u16 blobsz, bool auth)
+
+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;
@@ -143,25 +326,35 @@ static int blob_decap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz,
        idx = 1;
 
        /* Load key modifier */
-       tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY |
-                        ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) |
-                        (keymodsz & LDST_LEN_MASK);
+       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 */
-       tmpdesc[idx++] = CMD_SEQ_IN_PTR | (blobsz + 32 + 16);
-
+       /* Compensate BKEK + MAC tag over size of encapsulated secret */
+       tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + 32 + 16);
        tmpdesc[idx++] = (u32)blobbuf;
-       tmpdesc[idx++] = CMD_SEQ_OUT_PTR | blobsz;
+       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 |
-                    OP_PCL_BLOB_PTXT_SECMEM | OP_PCL_BLOB_BLACK;
-       if (auth)
+       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);
@@ -294,6 +487,22 @@ void *slot_get_address(struct device *dev, u32 unit, u32 slot)
        return ksdata->base_address + slot * smpriv->slot_size;
 }
 
+void *slot_get_physical(struct device *dev, u32 unit, u32 slot)
+{
+       struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+       struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+       if (slot >= ksdata->slot_count)
+               return NULL;
+
+#ifdef SM_DEBUG
+       dev_info(dev, "slot_get_physical(): slot %d is 0x%08x\n", slot,
+                (u32)ksdata->phys_address + slot * smpriv->slot_size);
+#endif
+
+       return ksdata->phys_address + slot * smpriv->slot_size;
+}
+
 u32 slot_get_base(struct device *dev, u32 unit, u32 slot)
 {
        struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
@@ -389,6 +598,8 @@ int kso_init_data(struct device *dev, u32 unit)
        smpriv->pagedesc[unit].ksdata = keystore_data;
        smpriv->pagedesc[unit].ksdata->base_address =
                smpriv->pagedesc[unit].pg_base;
+       smpriv->pagedesc[unit].ksdata->phys_address =
+               smpriv->pagedesc[unit].pg_phys;
 
        retval = 0;
 
@@ -430,6 +641,7 @@ void sm_init_keystore(struct device *dev)
        smpriv->slot_alloc = slot_alloc;
        smpriv->slot_dealloc = slot_dealloc;
        smpriv->slot_get_address = slot_get_address;
+       smpriv->slot_get_physical = slot_get_physical;
        smpriv->slot_get_base = slot_get_base;
        smpriv->slot_get_offset = slot_get_offset;
        smpriv->slot_get_slot_size = slot_get_slot_size;
@@ -580,98 +792,148 @@ out:
 }
 EXPORT_SYMBOL(sm_keystore_slot_read);
 
-int sm_keystore_slot_encapsulate(struct device *dev, u32 unit, u32 inslot,
-                                u32 outslot, u16 secretlen, u8 *keymod,
-                                u16 keymodlen)
+/*
+ * Blacken a clear key in a slot. Operates "in place".
+ * Limited to class 1 keys at the present time
+ */
+int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+                         u16 key_length, u8 keyauth)
 {
        struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
        int retval = 0;
-       u32 slot_length, dsize, jstat;
+       u8 __iomem *slotaddr;
+       void *slotphys;
+       u32 dsize, jstat;
+       u32 __iomem *coverdesc = NULL;
+
+       /* Get the address of the object in the slot */
+       slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+       slotphys = (u8 *)smpriv->slot_get_physical(dev, unit, slot);
+
+       dsize = blacken_key_jobdesc(&coverdesc, slotphys, key_length, keyauth);
+       if (!dsize)
+               return -ENOMEM;
+       jstat = sm_key_job(dev, coverdesc);
+       if (jstat)
+               retval = -EIO;
+
+       kfree(coverdesc);
+       return retval;
+}
+EXPORT_SYMBOL(sm_keystore_cover_key);
+
+/* Export a black/red key to a blob in external memory */
+int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+                           u8 keyauth, u8 *outbuf, u16 keylen, u8 *keymod)
+{
+       struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+       int retval = 0;
+       u8 __iomem *slotaddr, *lkeymod;
+       u8 __iomem *slotphys;
+       dma_addr_t keymod_dma, outbuf_dma;
+       u32 dsize, jstat;
        u32 __iomem *encapdesc = NULL;
-       u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr;
-       dma_addr_t keymod_dma;
 
-       /* Ensure that the full blob  will fit in the key slot */
-       slot_length = smpriv->slot_get_slot_size(dev, unit, outslot);
-       if ((secretlen + 48) > slot_length)
-               goto out;
+       /* Get the base address(es) of the specified slot */
+       slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+       slotphys = smpriv->slot_get_physical(dev, unit, slot);
 
-       /* Get the base addresses of both keystore slots */
-       inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot);
-       outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot);
+       /* Build/map/flush the key modifier */
+       lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+       memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+       keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN,
+                                   DMA_TO_DEVICE);
+       dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN,
+                                  DMA_TO_DEVICE);
 
-       /* Build the key modifier */
-       lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA);
-       memcpy(lkeymod, keymod, keymodlen);
-       keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE);
-       dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
+       outbuf_dma = dma_map_single(dev, outbuf,
+                                   AES_BLOCK_PAD(keylen) + BLOB_OVERHEAD,
+                                   DMA_FROM_DEVICE);
 
        /* Build the encapsulation job descriptor */
-       dsize = blob_encap_desc(&encapdesc, keymod_dma, keymodlen,
-                               __pa(inpslotaddr), __pa(outslotaddr),
-                               secretlen, 0);
+       dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, slotphys, outbuf_dma,
+                                  keylen, keycolor, SM_SECMEM, keyauth);
        if (!dsize) {
-               dev_err(dev, "can't alloc an encap descriptor\n");
+               dev_err(dev, "can't alloc an encapsulation descriptor\n");
                retval = -ENOMEM;
                goto out;
        }
        jstat = sm_key_job(dev, encapdesc);
+       dma_sync_single_for_cpu(dev, outbuf_dma, keylen, DMA_FROM_DEVICE);
 
-       dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
-       kfree(encapdesc);
+       if (jstat)
+               retval = -EIO;
 
 out:
-       return retval;
+       dma_unmap_single(dev, outbuf_dma, AES_BLOCK_PAD(keylen) + BLOB_OVERHEAD,
+                        DMA_FROM_DEVICE);
+       dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+       kfree(encapdesc);
 
+       return retval;
 }
-EXPORT_SYMBOL(sm_keystore_slot_encapsulate);
+EXPORT_SYMBOL(sm_keystore_slot_export);
 
-int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, u32 inslot,
-                                u32 outslot, u16 secretlen, u8 *keymod,
-                                u16 keymodlen)
+/* Import a black/red key from a blob residing in external memory */
+int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+                           u8 keyauth, u8 *inbuf, u16 keylen, u8 *keymod)
 {
        struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
        int retval = 0;
-       u32 slot_length, dsize, jstat;
+       u8 __iomem *slotaddr, *lkeymod;
+       u8 __iomem *slotphys;
+       dma_addr_t keymod_dma, inbuf_dma;
+       u32 dsize, jstat;
        u32 __iomem *decapdesc = NULL;
-       u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr;
-       dma_addr_t keymod_dma;
 
-       /* Ensure that the decap data will fit in the key slot */
-       slot_length = smpriv->slot_get_slot_size(dev, unit, outslot);
-       if (secretlen > slot_length)
-               goto out;
-
-       /* Get the base addresses of both keystore slots */
-       inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot);
-       outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot);
+       /* Get the base address(es) of the specified slot */
+       slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+       slotphys = smpriv->slot_get_physical(dev, unit, slot);
+
+       /* Build/map/flush the key modifier */
+       lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+       memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+       keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN,
+                                   DMA_TO_DEVICE);
+       dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN,
+                                  DMA_TO_DEVICE);
+
+       inbuf_dma = dma_map_single(dev, inbuf,
+                                  AES_BLOCK_PAD(keylen) + BLOB_OVERHEAD,
+                                  DMA_TO_DEVICE);
+       dma_sync_single_for_device(dev, inbuf_dma,
+                                  AES_BLOCK_PAD(keylen) + BLOB_OVERHEAD,
+                                  DMA_TO_DEVICE);
 
-       /* Build the key modifier */
-       lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA);
-       memcpy(lkeymod, keymod, keymodlen);
-       keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE);
-       dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
-
-       /* Build the decapsulation job descriptor */
-       dsize = blob_decap_desc(&decapdesc, keymod_dma, keymodlen,
-                               __pa(inpslotaddr), __pa(outslotaddr),
-                               secretlen, 0);
+       /* Build the encapsulation job descriptor */
+       dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, inbuf_dma, slotphys,
+                                  keylen, keycolor, SM_SECMEM, keyauth);
        if (!dsize) {
-               dev_err(dev, "can't alloc a decap descriptor\n");
+               dev_err(dev, "can't alloc a decapsulation descriptor\n");
                retval = -ENOMEM;
                goto out;
        }
+
        jstat = sm_key_job(dev, decapdesc);
 
-       dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
-       kfree(decapdesc);
+       /*
+        * May want to expand upon error meanings a bit. Any CAAM status
+        * is reported as EIO, but we might want to look for something more
+        * meaningful for something like an ICV error on restore, otherwise
+        * the caller is left guessing.
+        */
+       if (jstat)
+               retval = -EIO;
 
 out:
-       return retval;
+       dma_unmap_single(dev, inbuf_dma, AES_BLOCK_PAD(keylen) + BLOB_OVERHEAD,
+                        DMA_TO_DEVICE);
+       dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+       kfree(decapdesc);
 
+       return retval;
 }
-EXPORT_SYMBOL(sm_keystore_slot_decapsulate);
-
+EXPORT_SYMBOL(sm_keystore_slot_import);
 
 /*
  * Initialization/shutdown subsystem
@@ -782,6 +1044,9 @@ int caam_sm_startup(struct platform_device *pdev)
                                (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK;
                        lpagedesc[page].pg_base = ctrlpriv->sm_base +
                                ((smpriv->page_size * page) / sizeof(u32));
+                       /* FIXME: get base address from platform property... */
+                       lpagedesc[page].pg_phys = (u32 *)0x00100000 +
+                               ((smpriv->page_size * page) / sizeof(u32));
                        lpagect++;
 #ifdef SM_DEBUG
                        dev_info(smdev,