]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/firmware/xilinx/zynqmp-secure.c
zynqmp-secure: Fix for crash seen with secure image loading
[zynq/linux.git] / drivers / firmware / xilinx / zynqmp-secure.c
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
19 static u8 key[ZYNQMP_AES_KEY_SIZE] = {0};
20 static dma_addr_t dma_addr;
21 static u8 *keyptr;
22 static size_t dma_size;
23 static char *kbuf;
24
25 static const struct zynqmp_eemi_ops *eemi_ops;
26
27 static 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 (!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
84 static 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
91 static 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
100 static 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
116 static DEVICE_ATTR_RW(key);
117 static DEVICE_ATTR_WO(secure_load);
118 static DEVICE_ATTR_WO(secure_load_done);
119
120 static 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
127 ATTRIBUTE_GROUPS(securefw);
128
129 static 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
156 static int securefw_remove(struct platform_device *pdev)
157 {
158         sysfs_remove_groups(&pdev->dev.kobj, securefw_groups);
159         return 0;
160 }
161
162 static struct platform_driver securefw_driver = {
163         .driver = {
164                 .name = "securefw",
165         },
166         .probe = securefw_probe,
167         .remove = securefw_remove,
168 };
169
170 static struct platform_device *securefw_dev_reg;
171
172 static 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
190 static void __exit zynqmp_secure_exit(void)
191 {
192         platform_device_unregister(securefw_dev_reg);
193         platform_driver_unregister(&securefw_driver);
194 }
195
196 module_init(zynqmp_secure_init);
197 module_exit(zynqmp_secure_exit);