Adds support for both Device-key and user-key encrypted bitstream loading to the Xilinx ZynqMP Soc. Signed-off-by: Nava kishore Manne <nava.kishore.manne@xxxxxxx> --- drivers/fpga/zynqmp-fpga.c | 53 ++++++++++++++++++++++++++-- include/linux/firmware/xlnx-zynqmp.h | 2 ++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c index f3434e2c487b..8b0e4b8b5d99 100644 --- a/drivers/fpga/zynqmp-fpga.c +++ b/drivers/fpga/zynqmp-fpga.c @@ -15,16 +15,44 @@ /* Constant Definitions */ #define IXR_FPGA_DONE_MASK BIT(3) +#define ENCRYPTED_KEY_LEN 64 +#define AES_MATCH_STR_LEN 5 + /** * struct zynqmp_fpga_priv - Private data structure + * @aes_key: Pointer Aes key buffer * @dev: Device data structure * @flags: flags which is used to identify the bitfile type */ struct zynqmp_fpga_priv { + const char *aes_key; struct device *dev; u32 flags; }; +static int zynqmp_fpga_parse_aes_key(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t size) +{ + struct zynqmp_fpga_priv *priv = mgr->priv; + const char *str = "Key 0"; + + for (int i = 0; i < size; i++) { + if (!strncmp(str, &buf[i], AES_MATCH_STR_LEN)) { + buf += AES_MATCH_STR_LEN + 1; + while (buf[i] == ' ') + i++; + if (size - i < ENCRYPTED_KEY_LEN) + return -EINVAL; + priv->aes_key = &buf[i]; + + return 0; + } + } + + return -EINVAL; +} + static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t size) @@ -43,25 +71,43 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, struct zynqmp_fpga_priv *priv; dma_addr_t dma_addr; u32 eemi_flags = 0; + size_t dma_size; char *kbuf; int ret; priv = mgr->priv; - kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL); + if (priv->flags & FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM) + dma_size = size + ENCRYPTED_KEY_LEN; + else + dma_size = size; + + kbuf = dma_alloc_coherent(priv->dev, dma_size, &dma_addr, GFP_KERNEL); if (!kbuf) return -ENOMEM; memcpy(kbuf, buf, size); + if (priv->flags & FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM) { + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY; + memcpy(kbuf + size, priv->aes_key, ENCRYPTED_KEY_LEN); + } + wmb(); /* ensure all writes are done before initiate FW call */ if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; - ret = zynqmp_pm_fpga_load(dma_addr, size, eemi_flags); + if (priv->flags & FPGA_MGR_ENCRYPTED_BITSTREAM) + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY; + + if (priv->flags & FPGA_MGR_USRKEY_ENCRYPTED_BITSTREAM) + ret = zynqmp_pm_fpga_load(dma_addr, dma_addr + size, + eemi_flags); + else + ret = zynqmp_pm_fpga_load(dma_addr, size, eemi_flags); - dma_free_coherent(priv->dev, size, kbuf, dma_addr); + dma_free_coherent(priv->dev, dma_size, kbuf, dma_addr); return ret; } @@ -99,6 +145,7 @@ ATTRIBUTE_GROUPS(zynqmp_fpga); static const struct fpga_manager_ops zynqmp_fpga_ops = { .state = zynqmp_fpga_ops_state, + .parse_aes_key = zynqmp_fpga_parse_aes_key, .write_init = zynqmp_fpga_ops_write_init, .write = zynqmp_fpga_ops_write, }; diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index d1ea3898564c..e88f24870a77 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -83,6 +83,8 @@ */ #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0) +#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY BIT(3) +#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY BIT(4) /* FPGA Status Reg */ #define XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET 7U -- 2.25.1