linux/drivers/firmware/xilinx/zynqmp-secure.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx ZynqMP SecureFw Driver.
   4 * Copyright (c) 2018 Xilinx Inc.
   5 */
   6
   7#include <asm/cacheflush.h>
   8#include <linux/device.h>
   9#include <linux/dma-mapping.h>
  10#include <linux/firmware.h>
  11#include <linux/firmware/xlnx-zynqmp.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/of_device.h>
  16
  17#define ZYNQMP_AES_KEY_SIZE     64
  18
  19static u8 key[ZYNQMP_AES_KEY_SIZE] = {0};
  20static dma_addr_t dma_addr;
  21static u8 *keyptr;
  22static size_t dma_size;
  23static char *kbuf;
  24
  25static const struct zynqmp_eemi_ops *eemi_ops;
  26
  27static ssize_t secure_load_store(struct device *dev,
  28                                 struct device_attribute *attr,
  29                                 const char *buf, size_t count)
  30{
  31        const struct firmware *fw;
  32        char image_name[NAME_MAX];
  33        u64 dst, ret;
  34        int len;
  35
  36        if (IS_ERR(eemi_ops) || !eemi_ops->secure_image)
  37                return -EFAULT;
  38
  39        strncpy(image_name, buf, NAME_MAX);
  40        len = strlen(image_name);
  41        if (image_name[len - 1] == '\n')
  42                image_name[len - 1] = 0;
  43
  44        ret = request_firmware(&fw, image_name, dev);
  45        if (ret) {
  46                dev_err(dev, "Error requesting firmware %s\n", image_name);
  47                return ret;
  48        }
  49        dma_size = fw->size;
  50
  51        if (keyptr)
  52                dma_size = fw->size + ZYNQMP_AES_KEY_SIZE;
  53
  54        kbuf = dma_alloc_coherent(dev, dma_size,
  55                                  &dma_addr, GFP_KERNEL);
  56        if (!kbuf)
  57                return -ENOMEM;
  58
  59        memcpy(kbuf, fw->data, fw->size);
  60
  61        if (keyptr)
  62                memcpy(kbuf + fw->size, key, ZYNQMP_AES_KEY_SIZE);
  63
  64        /* To ensure cache coherency */
  65        __flush_cache_user_range((unsigned long)kbuf,
  66                                 (unsigned long)kbuf + dma_size);
  67        release_firmware(fw);
  68
  69        if (keyptr)
  70                ret = eemi_ops->secure_image(dma_addr, dma_addr + fw->size,
  71                                             &dst);
  72        else
  73                ret = eemi_ops->secure_image(dma_addr, 0, &dst);
  74
  75        if (ret) {
  76                dev_info(dev, "Failed to load secure image \r\n");
  77                return ret;
  78        }
  79        dev_info(dev, "Verified image at 0x%llx\n", dst);
  80
  81        return count;
  82}
  83
  84static ssize_t key_show(struct device *dev,
  85                        struct device_attribute *attr,
  86                        char *buf)
  87{
  88        return snprintf(buf, ZYNQMP_AES_KEY_SIZE + 1, "%s\n", key);
  89}
  90
  91static ssize_t key_store(struct device *dev,
  92                         struct device_attribute *attr,
  93                         const char *buf, size_t count)
  94{
  95        memcpy(key, buf, count);
  96        keyptr = &key[0];
  97        return count;
  98}
  99
 100static ssize_t secure_load_done_store(struct device *dev,
 101                                      struct device_attribute *attr,
 102                                      const char *buf, size_t count)
 103{
 104        int ret;
 105        unsigned int value;
 106
 107        ret = kstrtouint(buf, 10, &value);
 108        if (ret)
 109                return ret;
 110        if (value)
 111                dma_free_coherent(dev, dma_size, kbuf, dma_addr);
 112
 113        return count;
 114}
 115
 116static DEVICE_ATTR_RW(key);
 117static DEVICE_ATTR_WO(secure_load);
 118static DEVICE_ATTR_WO(secure_load_done);
 119
 120static struct attribute *securefw_attrs[] = {
 121        &dev_attr_secure_load_done.attr,
 122        &dev_attr_secure_load.attr,
 123        &dev_attr_key.attr,
 124        NULL,
 125};
 126
 127ATTRIBUTE_GROUPS(securefw);
 128
 129static int securefw_probe(struct platform_device *pdev)
 130{
 131        int ret;
 132        struct platform_device *securefw_pdev;
 133
 134        eemi_ops = zynqmp_pm_get_eemi_ops();
 135        if (IS_ERR(eemi_ops))
 136                return PTR_ERR(eemi_ops);
 137
 138        securefw_pdev = pdev;
 139
 140        securefw_pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 141
 142        ret = of_dma_configure(&securefw_pdev->dev, NULL, true);
 143        if (ret < 0) {
 144                dev_info(&securefw_pdev->dev, "Cannot setup DMA ops\r\n");
 145                return ret;
 146        }
 147
 148        ret = sysfs_create_groups(&securefw_pdev->dev.kobj, securefw_groups);
 149        if (ret)
 150                return ret;
 151
 152        dev_info(&securefw_pdev->dev, "securefw probed\r\n");
 153        return ret;
 154}
 155
 156static int securefw_remove(struct platform_device *pdev)
 157{
 158        sysfs_remove_groups(&pdev->dev.kobj, securefw_groups);
 159        return 0;
 160}
 161
 162static struct platform_driver securefw_driver = {
 163        .driver = {
 164                .name = "securefw",
 165        },
 166        .probe = securefw_probe,
 167        .remove = securefw_remove,
 168};
 169
 170static struct platform_device *securefw_dev_reg;
 171
 172static int __init zynqmp_secure_init(void)
 173{
 174        int ret;
 175
 176        ret = platform_driver_register(&securefw_driver);
 177        if (ret)
 178                return ret;
 179
 180        securefw_dev_reg = platform_device_register_simple("securefw", -1,
 181                                                           NULL, 0);
 182        if (IS_ERR(securefw_dev_reg)) {
 183                ret = PTR_ERR(securefw_dev_reg);
 184                platform_driver_unregister(&securefw_driver);
 185                return ret;
 186        }
 187        return 0;
 188}
 189
 190static void __exit zynqmp_secure_exit(void)
 191{
 192        platform_device_unregister(securefw_dev_reg);
 193        platform_driver_unregister(&securefw_driver);
 194}
 195
 196module_init(zynqmp_secure_init);
 197module_exit(zynqmp_secure_exit);
 198