interrupt-parent = <&intc>;
ranges;
+ caam_sm: caam-sm@00100000 {
+ compatible = "fsl,imx6q-caam-sm";
+ reg = <0x00100000 0x3fff>;
+ };
+
dma_apbh: dma-apbh@00110000 {
compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh";
reg = <0x00110000 0x2000>;
clocks = <&clks IMX6QDL_CLK_APBH_DMA>;
};
+ irq_sec_vio: caam_secvio {
+ compatible = "fsl,imx6q-caam-secvio";
+ interrupts = <0 20 0x04>;
+ secvio_src = <0x8000001d>;
+ };
+
gpmi: gpmi-nand@00112000 {
compatible = "fsl,imx6q-gpmi-nand";
#address-cells = <1>;
fsl,anatop = <&anatop>;
};
+ caam_snvs: caam-snvs@020cc000 {
+ compatible = "fsl,imx6q-caam-snvs";
+ reg = <0x020cc000 0x4000>;
+ };
+
snvs@020cc000 {
compatible = "fsl,sec-v4.0-mon", "simple-bus";
#address-cells = <1>;
caam RNG. This test is several minutes long and executes
just before the RNG is registered with the hw_random API.
+config CRYPTO_DEV_FSL_CAAM_SM
+ tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
+ default n
+ help
+ Enables use of a prototype kernel-level Keystore API with CAAM
+ Secure Memory for insertion/extraction of bus-protected secrets.
+
+config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE
+ int "Size of each keystore slot in Secure Memory"
+ depends on CRYPTO_DEV_FSL_CAAM_SM
+ range 5 9
+ default 7
+ help
+ Select size of allocation units to divide Secure Memory pages into
+ (the size of a "slot" as referenced inside the API code).
+ Established as powers of two.
+ Examples:
+ 5 => 32 bytes
+ 6 => 64 bytes
+ 7 => 128 bytes
+ 8 => 256 bytes
+ 9 => 512 bytes
+
+config CRYPTO_DEV_FSL_CAAM_SM_TEST
+ tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)"
+ depends on CRYPTO_DEV_FSL_CAAM_SM
+ default n
+ help
+ Example thread to exercise the Keystore API and to verify that
+ stored and recovered secrets can be used for general purpose
+ encryption/decryption.
+
+config CRYPTO_DEV_FSL_CAAM_SECVIO
+ tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
+ depends on CRYPTO_DEV_FSL_CAAM
+ default n
+ help
+ Enables installation of an interrupt handler with registrable
+ handler functions which can be specified to act on the consequences
+ of a security violation.
+
config CRYPTO_DEV_FSL_CAAM_DEBUG
bool "Enable debug output in CAAM driver"
depends on CRYPTO_DEV_FSL_CAAM
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
caam-objs := ctrl.o
caam_jr-objs := jr.o key_gen.o error.o
#include "desc_constr.h"
#include "error.h"
#include "ctrl.h"
+#include "sm.h"
/*
* Descriptor to instantiate RNG State Handle 0 in normal mode and
struct device_node *nprop, *np;
struct caam_ctrl __iomem *ctrl;
struct caam_full __iomem *topregs;
+ struct snvs_full __iomem *snvsregs;
struct caam_drv_private *ctrlpriv;
#ifdef CONFIG_DEBUG_FS
struct caam_perfmon *perfmon;
/* Get the IRQ of the controller (for security violations only) */
ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
+ /* Get SNVS register Page */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-snvs");
+
+ if (!np)
+ return -ENODEV;
+
+ snvsregs = of_iomap(np, 0);
+ ctrlpriv->snvs = snvsregs;
+ /* Get CAAM-SM node and of_iomap() and save */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+
+ if (!np)
+ return -ENODEV;
+
+ ctrlpriv->sm_base = of_iomap(np, 0);
+ ctrlpriv->sm_size = 0x3fff;
+
/*
* ARM targets tend to have clock control subsystems that can
* enable/disable clocking to our device. Turn clocking on to proceed
struct caam_drv_private {
struct device *dev;
+ struct device *smdev;
+ struct device *secviodev;
struct platform_device **jrpdev; /* Alloc'ed array per sub-device */
struct platform_device *pdev;
struct caam_deco **deco; /* DECO/CCB views */
struct caam_assurance *ac;
struct caam_queue_if *qi; /* QI control region */
+ struct snvs_full __iomem *snvs; /* SNVS HP+LP register space */
+ dma_addr_t __iomem *sm_base; /* Secure memory storage base */
+ u32 sm_size;
/*
* Detected geometry block. Filled in from device tree if powerpc,
--- /dev/null
+
+/*
+ * CAAM/SEC 4.x Security Violation Handler
+ * Copyright (C) 2015 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#include "compat.h"
+#include "intern.h"
+#include "secvio.h"
+#include "regs.h"
+
+/*
+ * These names are associated with each violation handler.
+ * The source names were taken from MX6, and are based on recommendations
+ * for most common SoCs.
+ */
+static const u8 *violation_src_name[] = {
+ "CAAM Security Violation",
+ "JTAG Alarm",
+ "Watchdog",
+ "(reserved)",
+ "External Boot",
+ "Tamper Detect",
+};
+
+/* Top-level security violation interrupt */
+static irqreturn_t caam_secvio_interrupt(int irq, void *snvsdev)
+{
+ struct device *dev = snvsdev;
+ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev);
+ u32 irqstate;
+
+ /* Check the HP secvio status register */
+ irqstate = rd_reg32(&svpriv->svregs->hp.secvio_status) |
+ HP_SECVIOST_SECVIOMASK;
+
+ if (!irqstate)
+ return IRQ_NONE;
+
+ /* Mask out one or more causes for deferred service */
+ clrbits32(&svpriv->svregs->hp.secvio_int_ctl, irqstate);
+
+ /* Now ACK causes */
+ setbits32(&svpriv->svregs->hp.secvio_status, irqstate);
+
+ /* And run deferred service */
+ preempt_disable();
+ tasklet_schedule(&svpriv->irqtask[smp_processor_id()]);
+ preempt_enable();
+
+ return IRQ_HANDLED;
+}
+
+/* Deferred service handler. Tasklet arg is simply the SNVS dev */
+static void caam_secvio_dispatch(unsigned long indev)
+{
+ struct device *dev = (struct device *)indev;
+ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev);
+ unsigned long flags, cause;
+ int i;
+
+
+ /*
+ * Capture the interrupt cause, using masked interrupts as
+ * identification. This only works if all are enabled; if
+ * this changes in the future, a "cause queue" will have to
+ * be built
+ */
+ cause = rd_reg32(&svpriv->svregs->hp.secvio_int_ctl) &
+ (HP_SECVIO_INTEN_SRC5 | HP_SECVIO_INTEN_SRC4 |
+ HP_SECVIO_INTEN_SRC3 | HP_SECVIO_INTEN_SRC2 |
+ HP_SECVIO_INTEN_SRC1 | HP_SECVIO_INTEN_SRC0);
+
+ /* Look through causes, call each handler if exists */
+ for (i = 0; i < MAX_SECVIO_SOURCES; i++)
+ if (cause & (1 << i)) {
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[i].handler(dev, i,
+ svpriv->intsrc[i].ext);
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+ };
+
+ /* Re-enable now-serviced interrupts */
+ setbits32(&svpriv->svregs->hp.secvio_int_ctl, cause);
+}
+
+/*
+ * Default cause handler, used in lieu of an application-defined handler.
+ * All it does at this time is print a console message. It could force a halt.
+ */
+static void caam_secvio_default(struct device *dev, u32 cause, void *ext)
+{
+ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev);
+
+ dev_err(dev, "Unhandled Security Violation Interrupt %d = %s\n",
+ cause, svpriv->intsrc[cause].intname);
+}
+
+/*
+ * Install an application-defined handler for a specified cause
+ * Arguments:
+ * - dev points to SNVS-owning device
+ * - cause interrupt source cause
+ * - handler application-defined handler, gets called with dev
+ * source cause, and locally-defined handler argument
+ * - cause_description points to a string to override the default cause
+ * name, this can be used as an alternate for error
+ * messages and such. If left NULL, the default
+ * description string is used.
+ * - ext pointer to any extra data needed by the handler.
+ */
+int caam_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+ void (*handler)(struct device *dev, u32 cause,
+ void *ext),
+ u8 *cause_description, void *ext)
+{
+ unsigned long flags;
+ struct caam_drv_private_secvio *svpriv;
+
+ svpriv = dev_get_drvdata(dev);
+
+ if ((handler == NULL) || (cause > SECVIO_CAUSE_SOURCE_5))
+ return -EINVAL;
+
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[cause].handler = handler;
+ if (cause_description != NULL)
+ svpriv->intsrc[cause].intname = cause_description;
+ if (ext != NULL)
+ svpriv->intsrc[cause].ext = ext;
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(caam_secvio_install_handler);
+
+/*
+ * Remove an application-defined handler for a specified cause (and, by
+ * implication, restore the "default".
+ * Arguments:
+ * - dev points to SNVS-owning device
+ * - cause interrupt source cause
+ */
+int caam_secvio_remove_handler(struct device *dev, enum secvio_cause cause)
+{
+ unsigned long flags;
+ struct caam_drv_private_secvio *svpriv;
+
+ svpriv = dev_get_drvdata(dev);
+
+ if (cause > SECVIO_CAUSE_SOURCE_5)
+ return -EINVAL;
+
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[cause].intname = violation_src_name[cause];
+ svpriv->intsrc[cause].handler = caam_secvio_default;
+ svpriv->intsrc[cause].ext = NULL;
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(caam_secvio_remove_handler);
+
+int caam_secvio_startup(struct platform_device *pdev)
+{
+ struct device *ctrldev, *svdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_secvio *svpriv;
+ struct platform_device *svpdev;
+ struct device_node *np;
+ const void *prop;
+ int i, error, secvio_inten_src;
+
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+ /*
+ * Set up the private block for secure memory
+ * Only one instance is possible
+ */
+ svpriv = kzalloc(sizeof(struct caam_drv_private_secvio), GFP_KERNEL);
+ if (svpriv == NULL) {
+ dev_err(ctrldev, "can't alloc private mem for secvio\n");
+ return -ENOMEM;
+ }
+ svpriv->parentdev = ctrldev;
+
+ /* Create the security violation dev */
+#ifdef CONFIG_OF
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio");
+ if (!np)
+ return -ENODEV;
+
+ ctrlpriv->secvio_irq = of_irq_to_resource(np, 0, NULL);
+
+ prop = of_get_property(np, "secvio_src", NULL);
+ if (prop)
+ secvio_inten_src = of_read_ulong(prop, 1);
+ else
+ secvio_inten_src = HP_SECVIO_INTEN_ALL;
+
+ printk(KERN_ERR "secvio_inten_src = %x\n", secvio_inten_src);
+
+ svpdev = of_platform_device_create(np, NULL, ctrldev);
+ if (!svpdev)
+ return -ENODEV;
+
+#else
+ svpdev = platform_device_register_data(ctrldev, "caam_secvio", 0,
+ svpriv,
+ sizeof(struct caam_drv_private_secvio));
+
+ secvio_inten_src = HP_SECVIO_INTEN_ALL;
+#endif
+ if (svpdev == NULL) {
+ kfree(svpriv);
+ return -EINVAL;
+ }
+ svdev = &svpdev->dev;
+ dev_set_drvdata(svdev, svpriv);
+ ctrlpriv->secviodev = svdev;
+ svpriv->svregs = ctrlpriv->snvs;
+
+ /*
+ * Now we have all the dev data set up. Init interrupt
+ * source descriptions
+ */
+ for (i = 0; i < MAX_SECVIO_SOURCES; i++) {
+ svpriv->intsrc[i].intname = violation_src_name[i];
+ svpriv->intsrc[i].handler = caam_secvio_default;
+ }
+
+ /* Connect main handler */
+ for_each_possible_cpu(i)
+ tasklet_init(&svpriv->irqtask[i], caam_secvio_dispatch,
+ (unsigned long)svdev);
+
+ error = request_irq(ctrlpriv->secvio_irq, caam_secvio_interrupt,
+ IRQF_SHARED, "caam_secvio", svdev);
+ if (error) {
+ dev_err(svdev, "can't connect secvio interrupt\n");
+ irq_dispose_mapping(ctrlpriv->secvio_irq);
+ ctrlpriv->secvio_irq = 0;
+ return -EINVAL;
+ }
+
+ /* Enable all sources */
+ wr_reg32(&svpriv->svregs->hp.secvio_int_ctl, secvio_inten_src);
+
+ dev_info(svdev, "security violation service handlers armed\n");
+
+ return 0;
+}
+
+void caam_secvio_shutdown(struct platform_device *pdev)
+{
+ struct device *ctrldev, *svdev;
+ struct caam_drv_private *priv;
+ struct caam_drv_private_secvio *svpriv;
+ int i;
+
+ ctrldev = &pdev->dev;
+ priv = dev_get_drvdata(ctrldev);
+ svdev = priv->secviodev;
+ svpriv = dev_get_drvdata(svdev);
+
+ /* Shut off all sources */
+
+ wr_reg32(&svpriv->svregs->hp.secvio_int_ctl, 0);
+
+ /* Remove tasklets and release interrupt */
+ for_each_possible_cpu(i)
+ tasklet_kill(&svpriv->irqtask[i]);
+
+ free_irq(priv->secvio_irq, svdev);
+
+ kfree(svpriv);
+}
+
+
+#ifdef CONFIG_OF
+static void __exit caam_secvio_exit(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ of_node_get(dev_node);
+
+ caam_secvio_shutdown(pdev);
+
+}
+
+static int __init caam_secvio_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL,
+ "arm,imx6-caam-secvio");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ of_node_put(dev_node);
+
+ return caam_secvio_startup(pdev);
+}
+
+module_init(caam_secvio_init);
+module_exit(caam_secvio_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM/SNVS Security Violation Handler");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+#endif
--- /dev/null
+
+/*
+ * CAAM Security Violation Handler
+ * Copyright (C) 2015 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#ifndef SECVIO_H
+#define SECVIO_H
+
+#include "snvsregs.h"
+
+
+/*
+ * Defines the published interfaces to install/remove application-specified
+ * handlers for catching violations
+ */
+
+#define MAX_SECVIO_SOURCES 6
+
+/* these are the untranslated causes */
+enum secvio_cause {
+ SECVIO_CAUSE_SOURCE_0,
+ SECVIO_CAUSE_SOURCE_1,
+ SECVIO_CAUSE_SOURCE_2,
+ SECVIO_CAUSE_SOURCE_3,
+ SECVIO_CAUSE_SOURCE_4,
+ SECVIO_CAUSE_SOURCE_5
+};
+
+/* These are common "recommended" cause definitions for most devices */
+#define SECVIO_CAUSE_CAAM_VIOLATION SECVIO_CAUSE_SOURCE_0
+#define SECVIO_CAUSE JTAG_ALARM SECVIO_CAUSE_SOURCE_1
+#define SECVIO_CAUSE_WATCHDOG SECVIO_CAUSE_SOURCE_2
+#define SECVIO_CAUSE_EXTERNAL_BOOT SECVIO_CAUSE_SOURCE_4
+#define SECVIO_CAUSE_TAMPER_DETECT SECVIO_CAUSE_SOURCE_5
+
+int caam_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+ void (*handler)(struct device *dev, u32 cause,
+ void *ext),
+ u8 *cause_description, void *ext);
+int caam_secvio_remove_handler(struct device *dev, enum secvio_cause cause);
+
+/*
+ * Private data definitions for the secvio "driver"
+ */
+
+struct secvio_int_src {
+ const u8 *intname; /* Points to a descriptive name for source */
+ void *ext; /* Extended data to pass to the handler */
+ void (*handler)(struct device *dev, u32 cause, void *ext);
+};
+
+struct caam_drv_private_secvio {
+ struct device *parentdev; /* points back to the controller */
+ spinlock_t svlock ____cacheline_aligned;
+ struct tasklet_struct irqtask[NR_CPUS];
+ struct snvs_full __iomem *svregs; /* both HP and LP domains */
+
+ /* Registered handlers for each violation */
+ struct secvio_int_src intsrc[MAX_SECVIO_SOURCES];
+
+};
+
+#endif /* SECVIO_H */
--- /dev/null
+
+/*
+ * CAAM Secure Memory/Keywrap API Definitions
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
+ */
+
+#ifndef SM_H
+#define SM_H
+
+
+/* Storage access permissions */
+#define SM_PERM_READ 0x01
+#define SM_PERM_WRITE 0x02
+#define SM_PERM_BLOB 0x03
+
+
+/* Keystore maintenance functions */
+void sm_init_keystore(struct device *dev);
+u32 sm_detect_keystore_units(struct device *dev);
+int sm_establish_keystore(struct device *dev, u32 unit);
+void sm_release_keystore(struct device *dev, u32 unit);
+void caam_sm_shutdown(struct platform_device *pdev);
+int caam_sm_example_init(struct platform_device *pdev);
+
+/* Keystore accessor functions */
+extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size,
+ u32 *slot);
+extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot);
+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_slot_encapsulate(struct device *dev, u32 unit,
+ u32 inslot, u32 outslot, u16 secretlen,
+ u8 *keymod, u16 keymodlen);
+extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit,
+ u32 inslot, u32 outslot, u16 secretlen,
+ u8 *keymod, u16 keymodlen);
+
+/* Data structure to hold per-slot information */
+struct keystore_data_slot_info {
+ u8 allocated; /* Track slot assignments */
+ u32 key_length; /* Size of the key */
+};
+
+/* Data structure to hold keystore information */
+struct keystore_data {
+ void *base_address; /* Base of the Secure Partition */
+ u32 slot_count; /* Number of slots in the keystore */
+ struct keystore_data_slot_info *slot; /* Per-slot information */
+};
+
+/* store the detected attributes of a secure memory page */
+struct sm_page_descriptor {
+ u16 phys_pagenum; /* may be discontiguous */
+ u16 own_part; /* Owning partition */
+ void *pg_base; /* Calculated virtual address */
+ struct keystore_data *ksdata;
+};
+
+struct caam_drv_private_sm {
+ struct device *parentdev; /* this ends up as the controller */
+ struct device *smringdev; /* ring that owns this instance */
+ spinlock_t kslock ____cacheline_aligned;
+
+ /* Default parameters for geometry */
+ u32 max_pages; /* maximum pages this instance can support */
+ u32 top_partition; /* highest partition number in this instance */
+ u32 top_page; /* highest page number in this instance */
+ u32 page_size; /* page size */
+ u32 slot_size; /* selected size of each storage block */
+
+ /* Partition/Page Allocation Map */
+ u32 localpages; /* Number of pages we can access */
+ struct sm_page_descriptor *pagedesc; /* Allocated per-page */
+
+ /* Installed handlers for keystore access */
+ int (*data_init)(struct device *dev, u32 unit);
+ void (*data_cleanup)(struct device *dev, u32 unit);
+ 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);
+ 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);
+};
+
+#endif /* SM_H */
--- /dev/null
+
+/*
+ * CAAM Secure Memory Storage Interface
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
+ *
+ * Loosely based on the SHW Keystore API for SCC/SCC2
+ * Experimental implementation and NOT intended for upstream use. Expect
+ * this interface to be amended significantly in the future once it becomes
+ * integrated into live applications.
+ *
+ * Known issues:
+ *
+ * - Executes one instance of an secure memory "driver". This is tied to the
+ * fact that job rings can't run as standalone instances in the present
+ * configuration.
+ *
+ * - It does not expose a userspace interface. The value of a userspace
+ * interface for access to secrets is a point for further architectural
+ * discussion.
+ *
+ * - Partition/permission management is not part of this interface. It
+ * depends on some level of "knowledge" agreed upon between bootloader,
+ * provisioning applications, and OS-hosted software (which uses this
+ * driver).
+ *
+ * - No means of identifying the location or purpose of secrets managed by
+ * this interface exists; "slot location" and format of a given secret
+ * needs to be agreed upon between bootloader, provisioner, and OS-hosted
+ * application.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "jr.h"
+#include "desc.h"
+#include "intern.h"
+#include "error.h"
+#include "sm.h"
+
+#ifdef SM_DEBUG_CONT
+void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ u32 i, *smdata;
+
+ dev_info(dev, "physical page %d content at 0x%08x\n",
+ pgdesc->phys_pagenum, pgdesc->pg_base);
+ smdata = pgdesc->pg_base;
+ for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4)
+ dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2],
+ smdata[i+3]);
+}
+#endif
+
+/*
+ * Construct a secure memory blob encapsulation job descriptor
+ *
+ * - desc pointer to hold new (to be allocated) pointer to the generated
+ * descriptor for later use. Calling thread can kfree the
+ * 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
+ *
+ * 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)
+{
+ u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+ u16 dsize, idx;
+
+ 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);
+
+ tmpdesc[idx++] = (u32)keymod;
+
+ /* Encapsulate to 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));
+
+ tmpdesc[idx++] = (u32)outbuf;
+ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB |
+ OP_PCL_BLOB_PTXT_SECMEM;
+ if (auth)
+ tmpdesc[idx] |= OP_PCL_BLOB_EKT;
+
+ 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 secure memory 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
+ * 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
+ *
+ * Note: this uses 32-bit pointers at present
+ */
+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)
+{
+ u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+ u16 dsize, idx;
+
+ 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);
+
+ tmpdesc[idx++] = (u32)keymod;
+
+ /* Compensate BKEK + MAC tag */
+ tmpdesc[idx++] = CMD_SEQ_IN_PTR | (blobsz + 32 + 16);
+
+ tmpdesc[idx++] = (u32)blobbuf;
+ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | blobsz;
+ 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] |= OP_PCL_BLOB_EKT;
+
+ 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;
+}
+
+/*
+ * Pseudo-synchronous ring access functions for carrying out key
+ * encapsulation and decapsulation
+ */
+
+struct sm_key_job_result {
+ int error;
+ struct completion completion;
+};
+
+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 */
+}
+
+static int sm_key_job(struct device *ksdev, u32 *jobdesc)
+{
+ struct sm_key_job_result testres;
+ struct caam_drv_private_sm *kspriv;
+ int rtn = 0;
+
+ kspriv = dev_get_drvdata(ksdev);
+
+ init_completion(&testres.completion);
+
+ rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done,
+ &testres);
+ if (!rtn) {
+ wait_for_completion_interruptible(&testres.completion);
+ rtn = testres.error;
+ }
+ return rtn;
+}
+
+/*
+ * Following section establishes the default methods for keystore access
+ * They are NOT intended for use external to this module
+ *
+ * In the present version, these are the only means for the higher-level
+ * interface to deal with the mechanics of accessing the phyiscal keystore
+ */
+
+
+int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+ u32 i;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size);
+#endif
+
+ if (size > smpriv->slot_size)
+ return -EKEYREJECTED;
+
+ for (i = 0; i < ksdata->slot_count; i++) {
+ if (ksdata->slot[i].allocated == 0) {
+ ksdata->slot[i].allocated = 1;
+ (*slot) = i;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_alloc(): new slot %d allocated\n",
+ *slot);
+#endif
+ return 0;
+ }
+ }
+
+ return -ENOSPC;
+}
+EXPORT_SYMBOL(slot_alloc);
+
+int slot_dealloc(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;
+ u8 __iomem *slotdata;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot);
+#endif
+ if (slot >= ksdata->slot_count)
+ return -EINVAL;
+ slotdata = ksdata->base_address + slot * smpriv->slot_size;
+
+ if (ksdata->slot[slot].allocated == 1) {
+ /* Forcibly overwrite the data from the keystore */
+ memset(ksdata->base_address + slot * smpriv->slot_size, 0,
+ smpriv->slot_size);
+
+ ksdata->slot[slot].allocated = 0;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_dealloc(): slot %d released\n", slot);
+#endif
+ return 0;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(slot_dealloc);
+
+void *slot_get_address(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_address(): slot %d is 0x%08x\n", slot,
+ (u32)ksdata->base_address + slot * smpriv->slot_size);
+#endif
+
+ return ksdata->base_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);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+ /*
+ * There could potentially be more than one secure partition object
+ * associated with this keystore. For now, there is just one.
+ */
+
+ (void)slot;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n",
+ slot, (u32)ksdata->base_address);
+#endif
+
+ return (u32)(ksdata->base_address);
+}
+
+u32 slot_get_offset(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 -EINVAL;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot,
+ slot * smpriv->slot_size);
+#endif
+
+ return slot * smpriv->slot_size;
+}
+
+u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot,
+ smpriv->slot_size);
+#endif
+ /* All slots are the same size in the default implementation */
+ return smpriv->slot_size;
+}
+
+
+
+int kso_init_data(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ struct keystore_data *keystore_data = NULL;
+ u32 slot_count;
+ u32 keystore_data_size;
+
+ /*
+ * Calculate the required size of the keystore data structure, based
+ * on the number of keys that can fit in the partition.
+ */
+ slot_count = smpriv->page_size / smpriv->slot_size;
+#ifdef SM_DEBUG
+ dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count);
+#endif
+
+ keystore_data_size = sizeof(struct keystore_data) +
+ slot_count *
+ sizeof(struct keystore_data_slot_info);
+
+ keystore_data = kzalloc(keystore_data_size, GFP_KERNEL);
+
+ if (keystore_data == NULL) {
+ retval = -ENOSPC;
+ goto out;
+ }
+
+#ifdef SM_DEBUG
+ dev_info(dev, "kso_init_data: keystore data size = %d\n",
+ keystore_data_size);
+#endif
+
+ /*
+ * Place the slot information structure directly after the keystore data
+ * structure.
+ */
+ keystore_data->slot = (struct keystore_data_slot_info *)
+ (keystore_data + 1);
+ keystore_data->slot_count = slot_count;
+
+ smpriv->pagedesc[unit].ksdata = keystore_data;
+ smpriv->pagedesc[unit].ksdata->base_address =
+ smpriv->pagedesc[unit].pg_base;
+
+ retval = 0;
+
+out:
+ if (retval != 0)
+ if (keystore_data != NULL)
+ kfree(keystore_data);
+
+
+ return retval;
+}
+
+void kso_cleanup_data(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *keystore_data = NULL;
+
+ if (smpriv->pagedesc[unit].ksdata != NULL)
+ keystore_data = smpriv->pagedesc[unit].ksdata;
+
+ /* Release the allocated keystore management data */
+ kfree(smpriv->pagedesc[unit].ksdata);
+
+ return;
+}
+
+
+
+/*
+ * Keystore management section
+ */
+
+void sm_init_keystore(struct device *dev)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+ smpriv->data_init = kso_init_data;
+ smpriv->data_cleanup = kso_cleanup_data;
+ smpriv->slot_alloc = slot_alloc;
+ smpriv->slot_dealloc = slot_dealloc;
+ smpriv->slot_get_address = slot_get_address;
+ smpriv->slot_get_base = slot_get_base;
+ smpriv->slot_get_offset = slot_get_offset;
+ smpriv->slot_get_slot_size = slot_get_slot_size;
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_init_keystore(): handlers installed\n");
+#endif
+}
+EXPORT_SYMBOL(sm_init_keystore);
+
+/* Return available pages/units */
+u32 sm_detect_keystore_units(struct device *dev)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+ return smpriv->localpages;
+}
+EXPORT_SYMBOL(sm_detect_keystore_units);
+
+/*
+ * Do any keystore specific initializations
+ */
+int sm_establish_keystore(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit);
+#endif
+
+ if (smpriv->data_init == NULL)
+ return -EINVAL;
+
+ /* Call the data_init function for any user setup */
+ return smpriv->data_init(dev, unit);
+}
+EXPORT_SYMBOL(sm_establish_keystore);
+
+void sm_release_keystore(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit);
+#endif
+ if ((smpriv != NULL) && (smpriv->data_cleanup != NULL))
+ smpriv->data_cleanup(dev, unit);
+
+ return;
+}
+EXPORT_SYMBOL(sm_release_keystore);
+
+/*
+ * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to
+ * the keystore
+ */
+int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+
+ spin_lock(&smpriv->kslock);
+
+ if ((smpriv->slot_alloc == NULL) ||
+ (smpriv->pagedesc[unit].ksdata == NULL))
+ goto out;
+
+ retval = smpriv->slot_alloc(dev, unit, size, slot);
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_alloc);
+
+int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+
+ spin_lock(&smpriv->kslock);
+
+ if ((smpriv->slot_alloc == NULL) ||
+ (smpriv->pagedesc[unit].ksdata == NULL))
+ goto out;
+
+ retval = smpriv->slot_dealloc(dev, unit, slot);
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_dealloc);
+
+int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
+ const u8 *key_data, u32 key_length)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ u32 slot_size;
+ u32 i;
+ u8 __iomem *slot_location;
+
+ spin_lock(&smpriv->kslock);
+
+ slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+ if (key_length > slot_size) {
+ retval = -EFBIG;
+ goto out;
+ }
+
+ slot_location = smpriv->slot_get_address(dev, unit, slot);
+
+ for (i = 0; i < key_length; i++)
+ slot_location[i] = key_data[i];
+
+ retval = 0;
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_load);
+
+int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
+ u32 key_length, u8 *key_data)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ u8 __iomem *slot_addr;
+ u32 slot_size;
+
+ spin_lock(&smpriv->kslock);
+
+ slot_addr = smpriv->slot_get_address(dev, unit, slot);
+ slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+ if (key_length > slot_size) {
+ retval = -EKEYREJECTED;
+ goto out;
+ }
+
+ memcpy(key_data, slot_addr, key_length);
+ retval = 0;
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+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)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = 0;
+ u32 slot_length, 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 addresses of both keystore slots */
+ inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot);
+ outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot);
+
+ /* 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 encapsulation job descriptor */
+ dsize = blob_encap_desc(&encapdesc, keymod_dma, keymodlen,
+ __pa(inpslotaddr), __pa(outslotaddr),
+ secretlen, 0);
+ if (!dsize) {
+ dev_err(dev, "can't alloc an encap descriptor\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ jstat = sm_key_job(dev, encapdesc);
+
+ dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
+ kfree(encapdesc);
+
+out:
+ return retval;
+
+}
+EXPORT_SYMBOL(sm_keystore_slot_encapsulate);
+
+int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, u32 inslot,
+ u32 outslot, u16 secretlen, u8 *keymod,
+ u16 keymodlen)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = 0;
+ u32 slot_length, 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);
+
+ /* 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);
+ if (!dsize) {
+ dev_err(dev, "can't alloc a decap descriptor\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ jstat = sm_key_job(dev, decapdesc);
+
+ dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE);
+ kfree(decapdesc);
+
+out:
+ return retval;
+
+}
+EXPORT_SYMBOL(sm_keystore_slot_decapsulate);
+
+
+/*
+ * Initialization/shutdown subsystem
+ * Assumes statically-invoked startup/shutdown from the controller driver
+ * for the present time, to be reworked when a device tree becomes
+ * available. This code will not modularize in present form.
+ *
+ * Also, simply uses ring 0 for execution at the present
+ */
+
+int caam_sm_startup(struct platform_device *pdev)
+{
+ struct device *ctrldev, *smdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_sm *smpriv;
+ struct caam_drv_private_jr *jrpriv; /* need this for reg page */
+ struct platform_device *sm_pdev;
+ struct sm_page_descriptor *lpagedesc;
+ u32 page, pgstat, lpagect, detectedpage;
+
+ struct device_node *np;
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+
+ /*
+ * Set up the private block for secure memory
+ * Only one instance is possible
+ */
+ smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL);
+ if (smpriv == NULL) {
+ dev_err(ctrldev, "can't alloc private mem for secure memory\n");
+ return -ENOMEM;
+ }
+ smpriv->parentdev = ctrldev; /* copy of parent dev is handy */
+
+ /* Create the dev */
+#ifdef CONFIG_OF
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+ sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev);
+#else
+ sm_pdev = platform_device_register_data(ctrldev, "caam_sm", 0,
+ smpriv,
+ sizeof(struct caam_drv_private_sm));
+#endif
+ if (sm_pdev == NULL) {
+ kfree(smpriv);
+ return -EINVAL;
+ }
+ smdev = &sm_pdev->dev;
+ dev_set_drvdata(smdev, smpriv);
+ ctrlpriv->smdev = smdev;
+
+ /*
+ * Collect configuration limit data for reference
+ * This batch comes from the partition data/vid registers in perfmon
+ */
+ smpriv->max_pages = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart)
+ & SMPART_MAX_NUMPG_MASK) >>
+ SMPART_MAX_NUMPG_SHIFT) + 1;
+ smpriv->top_partition = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart)
+ & SMPART_MAX_PNUM_MASK) >>
+ SMPART_MAX_PNUM_SHIFT) + 1;
+ smpriv->top_page = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart)
+ & SMPART_MAX_PG_MASK) >> SMPART_MAX_PG_SHIFT) + 1;
+ smpriv->page_size = 1024 << ((rd_reg32(&ctrlpriv->ctrl->perfmon.smvid)
+ & SMVID_PG_SIZE_MASK) >> SMVID_PG_SIZE_SHIFT);
+ smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE;
+
+#ifdef SM_DEBUG
+ dev_info(smdev, "max pages = %d, top partition = %d\n",
+ smpriv->max_pages, smpriv->top_partition);
+ dev_info(smdev, "top page = %d, page size = %d (total = %d)\n",
+ smpriv->top_page, smpriv->page_size,
+ smpriv->top_page * smpriv->page_size);
+ dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size);
+#endif
+
+ /*
+ * Now probe for partitions/pages to which we have access. Note that
+ * these have likely been set up by a bootloader or platform
+ * provisioning application, so we have to assume that we "inherit"
+ * a configuration and work within the constraints of what it might be.
+ *
+ * Assume use of the zeroth ring in the present iteration (until
+ * we can divorce the controller and ring drivers, and then assign
+ * an SM instance to any ring instance).
+ */
+ smpriv->smringdev = caam_jr_alloc();
+ jrpriv = dev_get_drvdata(smpriv->smringdev);
+ lpagect = 0;
+ lpagedesc = kzalloc(sizeof(struct sm_page_descriptor)
+ * smpriv->max_pages, GFP_KERNEL);
+ if (lpagedesc == NULL) {
+ kfree(smpriv);
+ return -ENOMEM;
+ }
+
+ for (page = 0; page < smpriv->max_pages; page++) {
+ wr_reg32(&jrpriv->rregs->sm_cmd,
+ ((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) |
+ (SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK));
+ pgstat = rd_reg32(&jrpriv->rregs->sm_status);
+ if (((pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT)
+ == SMCS_PGOWN_OWNED) { /* our page? */
+ lpagedesc[page].phys_pagenum =
+ (pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT;
+ lpagedesc[page].own_part =
+ (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK;
+ lpagedesc[page].pg_base = ctrlpriv->sm_base +
+ ((smpriv->page_size * page) / sizeof(u32));
+ lpagect++;
+#ifdef SM_DEBUG
+ dev_info(smdev,
+ "physical page %d, owning partition = %d\n",
+ lpagedesc[page].phys_pagenum,
+ lpagedesc[page].own_part);
+#endif
+ }
+ }
+
+ smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect,
+ GFP_KERNEL);
+ if (smpriv->pagedesc == NULL) {
+ kfree(lpagedesc);
+ kfree(smpriv);
+ return -ENOMEM;
+ }
+ smpriv->localpages = lpagect;
+
+ detectedpage = 0;
+ for (page = 0; page < smpriv->max_pages; page++) {
+ if (lpagedesc[page].pg_base != NULL) { /* e.g. live entry */
+ memcpy(&smpriv->pagedesc[detectedpage],
+ &lpagedesc[page],
+ sizeof(struct sm_page_descriptor));
+#ifdef SM_DEBUG_CONT
+ sm_show_page(smdev, &smpriv->pagedesc[detectedpage]);
+#endif
+ detectedpage++;
+ }
+ }
+
+ kfree(lpagedesc);
+
+ sm_init_keystore(smdev);
+
+ return 0;
+}
+
+void caam_sm_shutdown(struct platform_device *pdev)
+{
+ struct device *ctrldev, *smdev;
+ struct caam_drv_private *priv;
+ struct caam_drv_private_sm *smpriv;
+
+ ctrldev = &pdev->dev;
+ priv = dev_get_drvdata(ctrldev);
+ smdev = priv->smdev;
+ smpriv = dev_get_drvdata(smdev);
+
+ kfree(smpriv->pagedesc);
+ kfree(smpriv);
+}
+EXPORT_SYMBOL(caam_sm_shutdown);
+#ifdef CONFIG_OF
+static void __exit caam_sm_exit(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ of_node_put(dev_node);
+
+ caam_sm_shutdown(pdev);
+
+ return;
+}
+
+static int __init caam_sm_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ of_node_get(dev_node);
+
+ caam_sm_startup(pdev);
+
+ return 0;
+}
+
+module_init(caam_sm_init);
+module_exit(caam_sm_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+#endif
--- /dev/null
+/*
+ * Secure Memory / Keystore Exemplification Module
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved
+ *
+ * Serves as a functional example, and as a self-contained unit test for
+ * the functionality contained in sm_store.c.
+ *
+ * The example function, caam_sm_example_init(), runs a thread that:
+ *
+ * - initializes a set of fixed keys
+ * - stores one copy in clear buffers
+ * - stores them again in secure memory
+ * - extracts stored keys back out for use
+ * - intializes 3 data buffers for a test:
+ * (1) containing cleartext
+ * (2) to hold ciphertext encrypted with an extracted black key
+ * (3) to hold extracted cleartext decrypted with an equivalent clear key
+ *
+ * The function then builds simple job descriptors that reference the key
+ * material and buffers as initialized, and executes an encryption job
+ * with a black key, and a decryption job using a the same key held in the
+ * clear. The output of the decryption job is compared to the original
+ * cleartext; if they don't compare correctly, one can assume a key problem
+ * exists, where the function will exit with an error.
+ *
+ * This module can use a substantial amount of refactoring, which may occur
+ * after the API gets some mileage. Furthermore, expect this module to
+ * eventually disappear once the API is integrated into "real" software.
+ */
+
+#include "compat.h"
+#include "intern.h"
+#include "desc.h"
+#include "error.h"
+#include "jr.h"
+#include "sm.h"
+
+static u8 skeymod[] = {
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+};
+static u8 symkey[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+};
+
+static u8 symdata[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static int mk_job_desc(u32 *desc, dma_addr_t key, u16 keysz, dma_addr_t indata,
+ dma_addr_t outdata, u16 sz, u32 cipherdir, u32 keymode)
+{
+ desc[1] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK) | keymode;
+ desc[2] = (u32)key;
+ desc[3] = CMD_OPERATION | OP_TYPE_CLASS1_ALG | OP_ALG_AAI_ECB |
+ cipherdir;
+ desc[4] = CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 |
+ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1 | sz;
+ desc[5] = (u32)indata;
+ desc[6] = CMD_FIFO_STORE | FIFOST_TYPE_MESSAGE_DATA | sz;
+ desc[7] = (u32)outdata;
+
+ desc[0] = CMD_DESC_HDR | HDR_ONE | (8 & HDR_DESCLEN_MASK);
+ return 8 * sizeof(u32);
+}
+
+struct exec_test_result {
+ int error;
+ struct completion completion;
+};
+
+void exec_test_done(struct device *dev, u32 *desc, u32 err, void *context)
+{
+ struct exec_test_result *res = context;
+
+ if (err) {
+ char tmp[CAAM_ERROR_STR_MAX];
+ dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
+ }
+
+ res->error = err;
+ complete(&res->completion);
+}
+
+static int exec_test_job(struct device *ksdev, u32 *jobdesc)
+{
+ struct exec_test_result testres;
+ struct caam_drv_private_sm *kspriv;
+ int rtn = 0;
+
+ kspriv = dev_get_drvdata(ksdev);
+
+ init_completion(&testres.completion);
+
+ rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, exec_test_done,
+ &testres);
+ if (!rtn) {
+ wait_for_completion_interruptible(&testres.completion);
+ rtn = testres.error;
+ }
+ return rtn;
+}
+
+
+int caam_sm_example_init(struct platform_device *pdev)
+{
+ struct device *ctrldev, *ksdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_sm *kspriv;
+ u32 unit, units, jdescsz;
+ int stat, jstat, rtnval = 0;
+ u8 __iomem *syminp, *symint, *symout = NULL;
+ dma_addr_t syminp_dma, symint_dma, symout_dma;
+ u8 __iomem *black_key_des, *black_key_aes128;
+ u8 __iomem *black_key_aes256;
+ dma_addr_t black_key_des_dma, black_key_aes128_dma;
+ dma_addr_t black_key_aes256_dma;
+ u8 __iomem *clear_key_des, *clear_key_aes128, *clear_key_aes256;
+ dma_addr_t clear_key_des_dma, clear_key_aes128_dma;
+ dma_addr_t clear_key_aes256_dma;
+ u32 __iomem *jdesc;
+ u32 keyslot_des, keyslot_aes128, keyslot_aes256 = 0;
+
+ jdesc = NULL;
+ black_key_des = black_key_aes128 = black_key_aes256 = NULL;
+ clear_key_des = clear_key_aes128 = clear_key_aes256 = NULL;
+
+ /* We can lose this cruft once we can get a pdev by name */
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+ ksdev = ctrlpriv->smdev;
+ kspriv = dev_get_drvdata(ksdev);
+ if (kspriv == NULL)
+ return -ENODEV;
+
+ /* Now that we have the dev for the single SM instance, connect */
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test_init() running\n");
+#endif
+ /* Probe to see what keystores are available to us */
+ units = sm_detect_keystore_units(ksdev);
+ if (!units)
+ dev_err(ksdev, "caam_sm_test: no keystore units available\n");
+
+ /*
+ * MX6 bootloader stores some stuff in unit 0, so let's
+ * use 1 or above
+ */
+ if (units < 2) {
+ dev_err(ksdev, "caam_sm_test: insufficient keystore units\n");
+ return -ENODEV;
+ }
+ unit = 1;
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: %d keystore units available\n", units);
+#endif
+
+ /* Initialize/Establish Keystore */
+ sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */
+
+ /*
+ * Top of main test thread
+ */
+
+ /* Allocate test data blocks (input, intermediate, output) */
+ syminp = kmalloc(256, GFP_KERNEL | GFP_DMA);
+ symint = kmalloc(256, GFP_KERNEL | GFP_DMA);
+ symout = kmalloc(256, GFP_KERNEL | GFP_DMA);
+ if ((syminp == NULL) || (symint == NULL) || (symout == NULL)) {
+ rtnval = -ENOMEM;
+ dev_err(ksdev, "caam_sm_test: can't get test data buffers\n");
+ goto freemem;
+ }
+
+ /* Allocate storage for 3 black keys: encapsulated 8, 16, 32 */
+ black_key_des = kmalloc(16, GFP_KERNEL | GFP_DMA); /* padded to 16... */
+ black_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA);
+ black_key_aes256 = kmalloc(16, GFP_KERNEL | GFP_DMA);
+ if ((black_key_des == NULL) || (black_key_aes128 == NULL) ||
+ (black_key_aes256 == NULL)) {
+ rtnval = -ENOMEM;
+ dev_err(ksdev, "caam_sm_test: can't black key buffers\n");
+ goto freemem;
+ }
+
+ clear_key_des = kmalloc(8, GFP_KERNEL | GFP_DMA);
+ clear_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA);
+ clear_key_aes256 = kmalloc(32, GFP_KERNEL | GFP_DMA);
+ if ((clear_key_des == NULL) || (clear_key_aes128 == NULL) ||
+ (clear_key_aes256 == NULL)) {
+ rtnval = -ENOMEM;
+ dev_err(ksdev, "caam_sm_test: can't get clear key buffers\n");
+ goto freemem;
+ }
+
+ /* Allocate storage for job descriptor */
+ jdesc = kmalloc(8 * sizeof(u32), GFP_KERNEL | GFP_DMA);
+ if (jdesc == NULL) {
+ rtnval = -ENOMEM;
+ dev_err(ksdev, "caam_sm_test: can't get descriptor buffers\n");
+ goto freemem;
+ }
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: all buffers allocated\n");
+#endif
+
+ /* Load up input data block, clear outputs */
+ memcpy(syminp, symdata, 256);
+ memset(symint, 0, 256);
+ memset(symout, 0, 256);
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[0], syminp[1], syminp[2], syminp[3],
+ syminp[4], syminp[5], syminp[6], syminp[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[0], symout[1], symout[2], symout[3],
+ symout[4], symout[5], symout[6], symout[7]);
+
+ dev_info(ksdev, "caam_sm_test: data buffers initialized\n");
+#endif
+
+ /* Load up clear keys */
+ memcpy(clear_key_des, symkey, 8);
+ memcpy(clear_key_aes128, symkey, 16);
+ memcpy(clear_key_aes256, symkey, 32);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: all clear keys loaded\n");
+#endif
+
+ /*
+ * Place clear keys in keystore.
+ * All the interesting stuff happens here.
+ */
+ /* 8 bit DES key */
+ stat = sm_keystore_slot_alloc(ksdev, unit, 8, &keyslot_des);
+ if (stat)
+ goto freemem;
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: 8 byte key slot in %d\n", keyslot_des);
+#endif
+ stat = sm_keystore_slot_load(ksdev, unit, keyslot_des, clear_key_des,
+ 8);
+ if (stat) {
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: can't load 8 byte key in %d\n",
+ keyslot_des);
+#endif
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ goto freemem;
+ }
+
+ /* 16 bit AES key */
+ stat = sm_keystore_slot_alloc(ksdev, unit, 16, &keyslot_aes128);
+ if (stat) {
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ goto freemem;
+ }
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: 16 byte key slot in %d\n",
+ keyslot_aes128);
+#endif
+ stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes128,
+ clear_key_aes128, 16);
+ if (stat) {
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: can't load 16 byte key in %d\n",
+ keyslot_aes128);
+#endif
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ goto freemem;
+ }
+
+ /* 32 bit AES key */
+ stat = sm_keystore_slot_alloc(ksdev, unit, 32, &keyslot_aes256);
+ if (stat) {
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ goto freemem;
+ }
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: 32 byte key slot in %d\n",
+ keyslot_aes256);
+#endif
+ stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes256,
+ clear_key_aes256, 32);
+ if (stat) {
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: can't load 32 byte key in %d\n",
+ keyslot_aes128);
+#endif
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ goto freemem;
+ }
+
+ /* Encapsulate all keys as SM blobs */
+ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_des,
+ keyslot_des, 8, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't encapsulate DES key\n");
+ goto freekeys;
+ }
+
+ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes128,
+ keyslot_aes128, 16, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't encapsulate AES128 key\n");
+ goto freekeys;
+ }
+
+ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes256,
+ keyslot_aes256, 32, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't encapsulate AES256 key\n");
+ goto freekeys;
+ }
+
+ /* Now decapsulate as black key blobs */
+ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_des,
+ keyslot_des, 8, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't decapsulate DES key\n");
+ goto freekeys;
+ }
+
+ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes128,
+ keyslot_aes128, 16, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n");
+ goto freekeys;
+ }
+
+ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes256,
+ keyslot_aes256, 32, skeymod, 8);
+ if (stat) {
+ dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n");
+ goto freekeys;
+ }
+
+ /* Extract 8/16/32 byte black keys */
+ sm_keystore_slot_read(ksdev, unit, keyslot_des, 8, black_key_des);
+ sm_keystore_slot_read(ksdev, unit, keyslot_aes128, 16,
+ black_key_aes128);
+ sm_keystore_slot_read(ksdev, unit, keyslot_aes256, 32,
+ black_key_aes256);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: all black keys extracted\n");
+#endif
+
+ /* DES encrypt using 8 byte black key */
+ black_key_des_dma = dma_map_single(ksdev, black_key_des, 8,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE);
+ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, black_key_des_dma, 8, syminp_dma,
+ symint_dma, 256,
+ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_DES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "input block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[0], syminp[1], syminp[2], syminp[3],
+ syminp[4], syminp[5], syminp[6], syminp[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[8], syminp[9], syminp[10], syminp[11],
+ syminp[12], syminp[13], syminp[14], syminp[15]);
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "caam_sm_test: encrypt cycle with 8 byte key\n");
+#endif
+
+ /* DES decrypt using 8 byte clear key */
+ clear_key_des_dma = dma_map_single(ksdev, clear_key_des, 8,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, clear_key_des_dma, 8, symint_dma,
+ symout_dma, 256,
+ OP_ALG_DECRYPT | OP_ALG_ALGSEL_DES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "decrypted block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[0], symout[1], symout[2], symout[3],
+ symout[4], symout[5], symout[6], symout[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[8], symout[9], symout[10], symout[11],
+ symout[12], symout[13], symout[14], symout[15]);
+ dev_info(ksdev, "caam_sm_test: decrypt cycle with 8 byte key\n");
+#endif
+
+ /* Check result */
+ if (memcmp(symout, syminp, 256)) {
+ dev_info(ksdev, "caam_sm_test: 8-byte key test mismatch\n");
+ rtnval = -1;
+ goto freekeys;
+ } else
+ dev_info(ksdev, "caam_sm_test: 8-byte key test match OK\n");
+
+ /* AES-128 encrypt using 16 byte black key */
+ black_key_aes128_dma = dma_map_single(ksdev, black_key_aes128, 16,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, black_key_aes128_dma, 16,
+ DMA_TO_DEVICE);
+ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, black_key_aes128_dma, 16, syminp_dma,
+ symint_dma, 256,
+ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, black_key_aes128_dma, 16, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "input block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[0], syminp[1], syminp[2], syminp[3],
+ syminp[4], syminp[5], syminp[6], syminp[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[8], syminp[9], syminp[10], syminp[11],
+ syminp[12], syminp[13], syminp[14], syminp[15]);
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "caam_sm_test: encrypt cycle with 16 byte key\n");
+#endif
+
+ /* AES-128 decrypt using 16 byte clear key */
+ clear_key_aes128_dma = dma_map_single(ksdev, clear_key_aes128, 16,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, clear_key_aes128_dma, 16,
+ DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, clear_key_aes128_dma, 16, symint_dma,
+ symout_dma, 256,
+ OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, clear_key_aes128_dma, 16, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "decrypted block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[0], symout[1], symout[2], symout[3],
+ symout[4], symout[5], symout[6], symout[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[8], symout[9], symout[10], symout[11],
+ symout[12], symout[13], symout[14], symout[15]);
+ dev_info(ksdev, "caam_sm_test: decrypt cycle with 16 byte key\n");
+#endif
+
+ /* Check result */
+ if (memcmp(symout, syminp, 256)) {
+ dev_info(ksdev, "caam_sm_test: 16-byte key test mismatch\n");
+ rtnval = -1;
+ goto freekeys;
+ } else
+ dev_info(ksdev, "caam_sm_test: 16-byte key test match OK\n");
+
+ /* AES-256 encrypt using 32 byte black key */
+ black_key_aes256_dma = dma_map_single(ksdev, black_key_aes256, 32,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, black_key_aes256_dma, 32,
+ DMA_TO_DEVICE);
+ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, black_key_aes256_dma, 32, syminp_dma,
+ symint_dma, 256,
+ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, black_key_aes256_dma, 32, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "input block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[0], syminp[1], syminp[2], syminp[3],
+ syminp[4], syminp[5], syminp[6], syminp[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ syminp[8], syminp[9], syminp[10], syminp[11],
+ syminp[12], syminp[13], syminp[14], syminp[15]);
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "caam_sm_test: encrypt cycle with 32 byte key\n");
+#endif
+
+ /* AES-256 decrypt using 32-byte black key */
+ clear_key_aes256_dma = dma_map_single(ksdev, clear_key_aes256, 32,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, clear_key_aes256_dma, 32,
+ DMA_TO_DEVICE);
+ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE);
+ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE);
+
+ jdescsz = mk_job_desc(jdesc, clear_key_aes256_dma, 32, symint_dma,
+ symout_dma, 256,
+ OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "jobdesc:\n");
+ dev_info(ksdev, "0x%08x\n", jdesc[0]);
+ dev_info(ksdev, "0x%08x\n", jdesc[1]);
+ dev_info(ksdev, "0x%08x\n", jdesc[2]);
+ dev_info(ksdev, "0x%08x\n", jdesc[3]);
+ dev_info(ksdev, "0x%08x\n", jdesc[4]);
+ dev_info(ksdev, "0x%08x\n", jdesc[5]);
+ dev_info(ksdev, "0x%08x\n", jdesc[6]);
+ dev_info(ksdev, "0x%08x\n", jdesc[7]);
+#endif
+
+ jstat = exec_test_job(ksdev, jdesc);
+
+ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE);
+ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE);
+ dma_unmap_single(ksdev, clear_key_aes256_dma, 32, DMA_TO_DEVICE);
+
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "intermediate block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[0], symint[1], symint[2], symint[3],
+ symint[4], symint[5], symint[6], symint[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symint[8], symint[9], symint[10], symint[11],
+ symint[12], symint[13], symint[14], symint[15]);
+ dev_info(ksdev, "decrypted block:\n");
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[0], symout[1], symout[2], symout[3],
+ symout[4], symout[5], symout[6], symout[7]);
+ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \
+ "0x%02x 0x%02x 0x%02x 0x%02x\n",
+ symout[8], symout[9], symout[10], symout[11],
+ symout[12], symout[13], symout[14], symout[15]);
+ dev_info(ksdev, "caam_sm_test: decrypt cycle with 32 byte key\n");
+#endif
+
+ /* Check result */
+ if (memcmp(symout, syminp, 256)) {
+ dev_info(ksdev, "caam_sm_test: 32-byte key test mismatch\n");
+ rtnval = -1;
+ goto freekeys;
+ } else
+ dev_info(ksdev, "caam_sm_test: 32-byte key test match OK\n");
+
+
+ /* Remove 8/16/32 byte keys from keystore */
+freekeys:
+ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_des);
+ if (stat)
+ dev_info(ksdev, "caam_sm_test: can't release slot %d\n",
+ keyslot_des);
+
+ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128);
+ if (stat)
+ dev_info(ksdev, "caam_sm_test: can't release slot %d\n",
+ keyslot_aes128);
+
+ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256);
+ if (stat)
+ dev_info(ksdev, "caam_sm_test: can't release slot %d\n",
+ keyslot_aes256);
+
+
+ /* Free resources */
+freemem:
+#ifdef SM_TEST_DETAIL
+ dev_info(ksdev, "caam_sm_test: cleaning up\n");
+#endif
+ kfree(syminp);
+ kfree(symint);
+ kfree(symout);
+ kfree(clear_key_des);
+ kfree(clear_key_aes128);
+ kfree(clear_key_aes256);
+ kfree(black_key_des);
+ kfree(black_key_aes128);
+ kfree(black_key_aes256);
+ kfree(jdesc);
+
+ /* Disconnect from keystore and leave */
+ sm_release_keystore(ksdev, unit);
+
+ return rtnval;
+}
+EXPORT_SYMBOL(caam_sm_example_init);
+
+void caam_sm_example_shutdown(void)
+{
+ /* unused in present version */
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ of_node_get(dev_node);
+
+}
+
+static int __init caam_sm_test_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ of_node_put(dev_node);
+
+ caam_sm_example_init(pdev);
+
+ return 0;
+}
+
+
+/* Module-based initialization needs to wait for dev tree */
+#ifdef CONFIG_OF
+module_init(caam_sm_test_init);
+module_exit(caam_sm_example_shutdown);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM Keystore Usage Example");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+#endif
--- /dev/null
+/*
+ * SNVS hardware register-level view
+ *
+ * Copyright (C) 2015 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#ifndef SNVSREGS_H
+#define SNVSREGS_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * SNVS High Power Domain
+ * Includes security violations, HA counter, RTC, alarm
+ */
+struct snvs_hp {
+ u32 lock;
+ u32 cmd;
+ u32 ctl;
+ u32 secvio_int_en; /* Security Violation Interrupt Enable */
+ u32 secvio_int_ctl; /* Security Violation Interrupt Control */
+ u32 status;
+ u32 secvio_status; /* Security Violation Status */
+ u32 ha_counteriv; /* High Assurance Counter IV */
+ u32 ha_counter; /* High Assurance Counter */
+ u32 rtc_msb; /* Real Time Clock/Counter MSB */
+ u32 rtc_lsb; /* Real Time Counter LSB */
+ u32 time_alarm_msb; /* Time Alarm MSB */
+ u32 time_alarm_lsb; /* Time Alarm LSB */
+};
+
+#define HP_LOCK_HAC_LCK 0x00040000
+#define HP_LOCK_HPSICR_LCK 0x00020000
+#define HP_LOCK_HPSVCR_LCK 0x00010000
+#define HP_LOCK_MKEYSEL_LCK 0x00000200
+#define HP_LOCK_TAMPCFG_LCK 0x00000100
+#define HP_LOCK_TAMPFLT_LCK 0x00000080
+#define HP_LOCK_SECVIO_LCK 0x00000040
+#define HP_LOCK_GENP_LCK 0x00000020
+#define HP_LOCK_MONOCTR_LCK 0x00000010
+#define HP_LOCK_CALIB_LCK 0x00000008
+#define HP_LOCK_SRTC_LCK 0x00000004
+#define HP_LOCK_ZMK_RD_LCK 0x00000002
+#define HP_LOCK_ZMK_WT_LCK 0x00000001
+
+#define HP_CMD_NONPRIV_AXS 0x80000000
+#define HP_CMD_HAC_STOP 0x00080000
+#define HP_CMD_HAC_CLEAR 0x00040000
+#define HP_CMD_HAC_LOAD 0x00020000
+#define HP_CMD_HAC_CFG_EN 0x00010000
+#define HP_CMD_SNVS_MSTR_KEY 0x00002000
+#define HP_CMD_PROG_ZMK 0x00001000
+#define HP_CMD_SW_LPSV 0x00000400
+#define HP_CMD_SW_FSV 0x00000200
+#define HP_CMD_SW_SV 0x00000100
+#define HP_CMD_LP_SWR_DIS 0x00000020
+#define HP_CMD_LP_SWR 0x00000010
+#define HP_CMD_SSM_SFNS_DIS 0x00000004
+#define HP_CMD_SSM_ST_DIS 0x00000002
+#define HP_CMD_SMM_ST 0x00000001
+
+#define HP_CTL_TIME_SYNC 0x00010000
+#define HP_CTL_CAL_VAL_SHIFT 10
+#define HP_CTL_CAL_VAL_MASK (0x1f << HP_CTL_CALIB_SHIFT)
+#define HP_CTL_CALIB_EN 0x00000100
+#define HP_CTL_PI_FREQ_SHIFT 4
+#define HP_CTL_PI_FREQ_MASK (0xf << HP_CTL_PI_FREQ_SHIFT)
+#define HP_CTL_PI_EN 0x00000008
+#define HP_CTL_TIMEALARM_EN 0x00000002
+#define HP_CTL_RTC_EN 0x00000001
+
+#define HP_SECVIO_INTEN_EN 0x10000000
+#define HP_SECVIO_INTEN_SRC5 0x00000020
+#define HP_SECVIO_INTEN_SRC4 0x00000010
+#define HP_SECVIO_INTEN_SRC3 0x00000008
+#define HP_SECVIO_INTEN_SRC2 0x00000004
+#define HP_SECVIO_INTEN_SRC1 0x00000002
+#define HP_SECVIO_INTEN_SRC0 0x00000001
+#define HP_SECVIO_INTEN_ALL 0x8000003f
+
+#define HP_SECVIO_ICTL_CFG_SHIFT 30
+#define HP_SECVIO_ICTL_CFG_MASK (0x3 << HP_SECVIO_ICTL_CFG_SHIFT)
+#define HP_SECVIO_ICTL_CFG5_SHIFT 5
+#define HP_SECVIO_ICTL_CFG5_MASK (0x3 << HP_SECVIO_ICTL_CFG5_SHIFT)
+#define HP_SECVIO_ICTL_CFG_DISABLE 0
+#define HP_SECVIO_ICTL_CFG_NONFATAL 1
+#define HP_SECVIO_ICTL_CFG_FATAL 2
+#define HP_SECVIO_ICTL_CFG4_FATAL 0x00000010
+#define HP_SECVIO_ICTL_CFG3_FATAL 0x00000008
+#define HP_SECVIO_ICTL_CFG2_FATAL 0x00000004
+#define HP_SECVIO_ICTL_CFG1_FATAL 0x00000002
+#define HP_SECVIO_ICTL_CFG0_FATAL 0x00000001
+
+#define HP_STATUS_ZMK_ZERO 0x80000000
+#define HP_STATUS_OTPMK_ZERO 0x08000000
+#define HP_STATUS_OTPMK_SYN_SHIFT 16
+#define HP_STATUS_OTPMK_SYN_MASK (0x1ff << HP_STATUS_OTPMK_SYN_SHIFT)
+#define HP_STATUS_SSM_ST_SHIFT 8
+#define HP_STATUS_SSM_ST_MASK (0xf << HP_STATUS_SSM_ST_SHIFT)
+#define HP_STATUS_SSM_ST_INIT 0
+#define HP_STATUS_SSM_ST_HARDFAIL 1
+#define HP_STATUS_SSM_ST_SOFTFAIL 3
+#define HP_STATUS_SSM_ST_INITINT 8
+#define HP_STATUS_SSM_ST_CHECK 9
+#define HP_STATUS_SSM_ST_NONSECURE 11
+#define HP_STATUS_SSM_ST_TRUSTED 13
+#define HP_STATUS_SSM_ST_SECURE 15
+
+#define HP_SECVIOST_ZMK_ECC_FAIL 0x08000000 /* write to clear */
+#define HP_SECVIOST_ZMK_SYN_SHIFT 16
+#define HP_SECVIOST_ZMK_SYN_MASK (0x1ff << HP_SECVIOST_ZMK_SYN_SHIFT)
+#define HP_SECVIOST_SECVIO5 0x00000020
+#define HP_SECVIOST_SECVIO4 0x00000010
+#define HP_SECVIOST_SECVIO3 0x00000008
+#define HP_SECVIOST_SECVIO2 0x00000004
+#define HP_SECVIOST_SECVIO1 0x00000002
+#define HP_SECVIOST_SECVIO0 0x00000001
+#define HP_SECVIOST_SECVIOMASK 0x0000003f
+
+/*
+ * SNVS Low Power Domain
+ * Includes glitch detector, SRTC, alarm, monotonic counter, ZMK
+ */
+struct snvs_lp {
+ u32 lock;
+ u32 ctl;
+ u32 mstr_key_ctl; /* Master Key Control */
+ u32 secvio_ctl; /* Security Violation Control */
+ u32 tamper_filt_cfg; /* Tamper Glitch Filters Configuration */
+ u32 tamper_det_cfg; /* Tamper Detectors Configuration */
+ u32 status;
+ u32 srtc_msb; /* Secure Real Time Clock/Counter MSB */
+ u32 srtc_lsb; /* Secure Real Time Clock/Counter LSB */
+ u32 time_alarm; /* Time Alarm */
+ u32 smc_msb; /* Secure Monotonic Counter MSB */
+ u32 smc_lsb; /* Secure Monotonic Counter LSB */
+ u32 pwr_glitch_det; /* Power Glitch Detector */
+ u32 gen_purpose;
+ u32 zmk[8]; /* Zeroizable Master Key */
+};
+
+#define LP_LOCK_MKEYSEL_LCK 0x00000200
+#define LP_LOCK_TAMPDET_LCK 0x00000100
+#define LP_LOCK_TAMPFLT_LCK 0x00000080
+#define LP_LOCK_SECVIO_LCK 0x00000040
+#define LP_LOCK_GENP_LCK 0x00000020
+#define LP_LOCK_MONOCTR_LCK 0x00000010
+#define LP_LOCK_CALIB_LCK 0x00000008
+#define LP_LOCK_SRTC_LCK 0x00000004
+#define LP_LOCK_ZMK_RD_LCK 0x00000002
+#define LP_LOCK_ZMK_WT_LCK 0x00000001
+
+#define LP_CTL_CAL_VAL_SHIFT 10
+#define LP_CTL_CAL_VAL_MASK (0x1f << LP_CTL_CAL_VAL_SHIFT)
+#define LP_CTL_CALIB_EN 0x00000100
+#define LP_CTL_SRTC_INVAL_EN 0x00000010
+#define LP_CTL_WAKE_INT_EN 0x00000008
+#define LP_CTL_MONOCTR_EN 0x00000004
+#define LP_CTL_TIMEALARM_EN 0x00000002
+#define LP_CTL_SRTC_EN 0x00000001
+
+#define LP_MKEYCTL_ZMKECC_SHIFT 8
+#define LP_MKEYCTL_ZMKECC_MASK (0xff << LP_MKEYCTL_ZMKECC_SHIFT)
+#define LP_MKEYCTL_ZMKECC_EN 0x00000010
+#define LP_MKEYCTL_ZMKECC_VAL 0x00000008
+#define LP_MKEYCTL_ZMKECC_PROG 0x00000004
+#define LP_MKEYCTL_MKSEL_SHIFT 0
+#define LP_MKEYCTL_MKSEL_MASK (3 << LP_MKEYCTL_MKSEL_SHIFT)
+#define LP_MKEYCTL_MK_OTP 0
+#define LP_MKEYCTL_MK_ZMK 2
+#define LP_MKEYCTL_MK_COMB 3
+
+#define LP_SECVIO_CTL_SRC5 0x20
+#define LP_SECVIO_CTL_SRC4 0x10
+#define LP_SECVIO_CTL_SRC3 0x08
+#define LP_SECVIO_CTL_SRC2 0x04
+#define LP_SECVIO_CTL_SRC1 0x02
+#define LP_SECVIO_CTL_SRC0 0x01
+
+#define LP_TAMPFILT_EXT2_EN 0x80000000
+#define LP_TAMPFILT_EXT2_SHIFT 24
+#define LP_TAMPFILT_EXT2_MASK (0x1f << LP_TAMPFILT_EXT2_SHIFT)
+#define LP_TAMPFILT_EXT1_EN 0x00800000
+#define LP_TAMPFILT_EXT1_SHIFT 16
+#define LP_TAMPFILT_EXT1_MASK (0x1f << LP_TAMPFILT_EXT1_SHIFT)
+#define LP_TAMPFILT_WM_EN 0x00000080
+#define LP_TAMPFILT_WM_SHIFT 0
+#define LP_TAMPFILT_WM_MASK (0x1f << LP_TAMPFILT_WM_SHIFT)
+
+#define LP_TAMPDET_OSC_BPS 0x10000000
+#define LP_TAMPDET_VRC_SHIFT 24
+#define LP_TAMPDET_VRC_MASK (3 << LP_TAMPFILT_VRC_SHIFT)
+#define LP_TAMPDET_HTDC_SHIFT 20
+#define LP_TAMPDET_HTDC_MASK (3 << LP_TAMPFILT_HTDC_SHIFT)
+#define LP_TAMPDET_LTDC_SHIFT 16
+#define LP_TAMPDET_LTDC_MASK (3 << LP_TAMPFILT_LTDC_SHIFT)
+#define LP_TAMPDET_POR_OBS 0x00008000
+#define LP_TAMPDET_PFD_OBS 0x00004000
+#define LP_TAMPDET_ET2_EN 0x00000400
+#define LP_TAMPDET_ET1_EN 0x00000200
+#define LP_TAMPDET_WMT2_EN 0x00000100
+#define LP_TAMPDET_WMT1_EN 0x00000080
+#define LP_TAMPDET_VT_EN 0x00000040
+#define LP_TAMPDET_TT_EN 0x00000020
+#define LP_TAMPDET_CT_EN 0x00000010
+#define LP_TAMPDET_MCR_EN 0x00000004
+#define LP_TAMPDET_SRTCR_EN 0x00000002
+
+#define LP_STATUS_SECURE
+#define LP_STATUS_NONSECURE
+#define LP_STATUS_SCANEXIT 0x00100000 /* all write 1 clear here on */
+#define LP_STATUS_EXT_SECVIO 0x00010000
+#define LP_STATUS_ET2 0x00000400
+#define LP_STATUS_ET1 0x00000200
+#define LP_STATUS_WMT2 0x00000100
+#define LP_STATUS_WMT1 0x00000080
+#define LP_STATUS_VTD 0x00000040
+#define LP_STATUS_TTD 0x00000020
+#define LP_STATUS_CTD 0x00000010
+#define LP_STATUS_PGD 0x00000008
+#define LP_STATUS_MCR 0x00000004
+#define LP_STATUS_SRTCR 0x00000002
+#define LP_STATUS_LPTA 0x00000001
+
+/* Full SNVS register page, including version/options */
+struct snvs_full {
+ struct snvs_hp hp;
+ struct snvs_lp lp;
+ u32 rsvd[731]; /* deadspace 0x08c-0xbf7 */
+
+ /* Version / Revision / Option ID space - end of register page */
+ u32 vid; /* 0xbf8 HP Version ID (VID 1) */
+ u32 opt_rev; /* 0xbfc HP Options / Revision (VID 2) */
+};
+
+#endif /* SNVSREGS_H */