xref: /linux/drivers/crypto/ccp/sfs.c (revision 22bdd6e68bbe270a916233ec5f34a13ae5e80ed9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AMD Secure Processor Seamless Firmware Servicing support.
4  *
5  * Copyright (C) 2025 Advanced Micro Devices, Inc.
6  *
7  * Author: Ashish Kalra <ashish.kalra@amd.com>
8  */
9 
10 #include <linux/firmware.h>
11 
12 #include "sfs.h"
13 #include "sev-dev.h"
14 
15 #define SFS_DEFAULT_TIMEOUT		(10 * MSEC_PER_SEC)
16 #define SFS_MAX_PAYLOAD_SIZE		(2 * 1024 * 1024)
17 #define SFS_NUM_2MB_PAGES_CMDBUF	(SFS_MAX_PAYLOAD_SIZE / PMD_SIZE)
18 #define SFS_NUM_PAGES_CMDBUF		(SFS_MAX_PAYLOAD_SIZE / PAGE_SIZE)
19 
20 static DEFINE_MUTEX(sfs_ioctl_mutex);
21 
22 static struct sfs_misc_dev *misc_dev;
23 
send_sfs_cmd(struct sfs_device * sfs_dev,int msg)24 static int send_sfs_cmd(struct sfs_device *sfs_dev, int msg)
25 {
26 	int ret;
27 
28 	sfs_dev->command_buf->hdr.status = 0;
29 	sfs_dev->command_buf->hdr.sub_cmd_id = msg;
30 
31 	ret = psp_extended_mailbox_cmd(sfs_dev->psp,
32 				       SFS_DEFAULT_TIMEOUT,
33 				       (struct psp_ext_request *)sfs_dev->command_buf);
34 	if (ret == -EIO) {
35 		dev_dbg(sfs_dev->dev,
36 			 "msg 0x%x failed with PSP error: 0x%x, extended status: 0x%x\n",
37 			 msg, sfs_dev->command_buf->hdr.status,
38 			 *(u32 *)sfs_dev->command_buf->buf);
39 	}
40 
41 	return ret;
42 }
43 
send_sfs_get_fw_versions(struct sfs_device * sfs_dev)44 static int send_sfs_get_fw_versions(struct sfs_device *sfs_dev)
45 {
46 	/*
47 	 * SFS_GET_FW_VERSIONS command needs the output buffer to be
48 	 * initialized to 0xC7 in every byte.
49 	 */
50 	memset(sfs_dev->command_buf->sfs_buffer, 0xc7, PAGE_SIZE);
51 	sfs_dev->command_buf->hdr.payload_size = 2 * PAGE_SIZE;
52 
53 	return send_sfs_cmd(sfs_dev, PSP_SFS_GET_FW_VERSIONS);
54 }
55 
send_sfs_update_package(struct sfs_device * sfs_dev,const char * payload_name)56 static int send_sfs_update_package(struct sfs_device *sfs_dev, const char *payload_name)
57 {
58 	char payload_path[PAYLOAD_NAME_SIZE + sizeof("amd/")];
59 	const struct firmware *firmware;
60 	unsigned long package_size;
61 	int ret;
62 
63 	/* Sanitize userspace provided payload name */
64 	if (!strnchr(payload_name, PAYLOAD_NAME_SIZE, '\0'))
65 		return -EINVAL;
66 
67 	snprintf(payload_path, sizeof(payload_path), "amd/%s", payload_name);
68 
69 	ret = firmware_request_nowarn(&firmware, payload_path, sfs_dev->dev);
70 	if (ret < 0) {
71 		dev_warn_ratelimited(sfs_dev->dev, "firmware request failed for %s (%d)\n",
72 				     payload_path, ret);
73 		return -ENOENT;
74 	}
75 
76 	/*
77 	 * SFS Update Package command's input buffer contains TEE_EXT_CMD_BUFFER
78 	 * followed by the Update Package and it should be 64KB aligned.
79 	 */
80 	package_size = ALIGN(firmware->size + PAGE_SIZE, 0x10000U);
81 
82 	/*
83 	 * SFS command buffer is a pre-allocated 2MB buffer, fail update package
84 	 * if SFS payload is larger than the pre-allocated command buffer.
85 	 */
86 	if (package_size > SFS_MAX_PAYLOAD_SIZE) {
87 		dev_warn_ratelimited(sfs_dev->dev,
88 			 "SFS payload size %ld larger than maximum supported payload size of %u\n",
89 			 package_size, SFS_MAX_PAYLOAD_SIZE);
90 		release_firmware(firmware);
91 		return -E2BIG;
92 	}
93 
94 	/*
95 	 * Copy firmware data to a HV_Fixed memory region.
96 	 */
97 	memcpy(sfs_dev->command_buf->sfs_buffer, firmware->data, firmware->size);
98 	sfs_dev->command_buf->hdr.payload_size = package_size;
99 
100 	release_firmware(firmware);
101 
102 	return send_sfs_cmd(sfs_dev, PSP_SFS_UPDATE);
103 }
104 
sfs_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)105 static long sfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
106 {
107 	struct sfs_user_get_fw_versions __user *sfs_get_fw_versions;
108 	struct sfs_user_update_package __user *sfs_update_package;
109 	struct psp_device *psp_master = psp_get_master_device();
110 	char payload_name[PAYLOAD_NAME_SIZE];
111 	struct sfs_device *sfs_dev;
112 	int ret = 0;
113 
114 	if (!psp_master || !psp_master->sfs_data)
115 		return -ENODEV;
116 
117 	sfs_dev = psp_master->sfs_data;
118 
119 	guard(mutex)(&sfs_ioctl_mutex);
120 
121 	switch (cmd) {
122 	case SFSIOCFWVERS:
123 		dev_dbg(sfs_dev->dev, "in SFSIOCFWVERS\n");
124 
125 		sfs_get_fw_versions = (struct sfs_user_get_fw_versions __user *)arg;
126 
127 		ret = send_sfs_get_fw_versions(sfs_dev);
128 		if (ret && ret != -EIO)
129 			return ret;
130 
131 		/*
132 		 * Return SFS status and extended status back to userspace
133 		 * if PSP status indicated success or command error.
134 		 */
135 		if (copy_to_user(&sfs_get_fw_versions->blob, sfs_dev->command_buf->sfs_buffer,
136 				 PAGE_SIZE))
137 			return -EFAULT;
138 		if (copy_to_user(&sfs_get_fw_versions->sfs_status,
139 				 &sfs_dev->command_buf->hdr.status,
140 				 sizeof(sfs_get_fw_versions->sfs_status)))
141 			return -EFAULT;
142 		if (copy_to_user(&sfs_get_fw_versions->sfs_extended_status,
143 				 &sfs_dev->command_buf->buf,
144 				 sizeof(sfs_get_fw_versions->sfs_extended_status)))
145 			return -EFAULT;
146 		break;
147 	case SFSIOCUPDATEPKG:
148 		dev_dbg(sfs_dev->dev, "in SFSIOCUPDATEPKG\n");
149 
150 		sfs_update_package = (struct sfs_user_update_package __user *)arg;
151 
152 		if (copy_from_user(payload_name, sfs_update_package->payload_name,
153 				   PAYLOAD_NAME_SIZE))
154 			return -EFAULT;
155 
156 		ret = send_sfs_update_package(sfs_dev, payload_name);
157 		if (ret && ret != -EIO)
158 			return ret;
159 
160 		/*
161 		 * Return SFS status and extended status back to userspace
162 		 * if PSP status indicated success or command error.
163 		 */
164 		if (copy_to_user(&sfs_update_package->sfs_status,
165 				 &sfs_dev->command_buf->hdr.status,
166 				 sizeof(sfs_update_package->sfs_status)))
167 			return -EFAULT;
168 		if (copy_to_user(&sfs_update_package->sfs_extended_status,
169 				 &sfs_dev->command_buf->buf,
170 				 sizeof(sfs_update_package->sfs_extended_status)))
171 			return -EFAULT;
172 		break;
173 	default:
174 		ret = -EINVAL;
175 	}
176 
177 	return ret;
178 }
179 
180 static const struct file_operations sfs_fops = {
181 	.owner	= THIS_MODULE,
182 	.unlocked_ioctl = sfs_ioctl,
183 };
184 
sfs_exit(struct kref * ref)185 static void sfs_exit(struct kref *ref)
186 {
187 	misc_deregister(&misc_dev->misc);
188 	kfree(misc_dev);
189 	misc_dev = NULL;
190 }
191 
sfs_dev_destroy(struct psp_device * psp)192 void sfs_dev_destroy(struct psp_device *psp)
193 {
194 	struct sfs_device *sfs_dev = psp->sfs_data;
195 
196 	if (!sfs_dev)
197 		return;
198 
199 	/*
200 	 * Change SFS command buffer back to the default "Write-Back" type.
201 	 */
202 	set_memory_wb((unsigned long)sfs_dev->command_buf, SFS_NUM_PAGES_CMDBUF);
203 
204 	snp_free_hv_fixed_pages(sfs_dev->page);
205 
206 	if (sfs_dev->misc)
207 		kref_put(&misc_dev->refcount, sfs_exit);
208 
209 	psp->sfs_data = NULL;
210 }
211 
212 /* Based on sev_misc_init() */
sfs_misc_init(struct sfs_device * sfs)213 static int sfs_misc_init(struct sfs_device *sfs)
214 {
215 	struct device *dev = sfs->dev;
216 	int ret;
217 
218 	/*
219 	 * SFS feature support can be detected on multiple devices but the SFS
220 	 * FW commands must be issued on the master. During probe, we do not
221 	 * know the master hence we create /dev/sfs on the first device probe.
222 	 */
223 	if (!misc_dev) {
224 		struct miscdevice *misc;
225 
226 		misc_dev = kzalloc(sizeof(*misc_dev), GFP_KERNEL);
227 		if (!misc_dev)
228 			return -ENOMEM;
229 
230 		misc = &misc_dev->misc;
231 		misc->minor = MISC_DYNAMIC_MINOR;
232 		misc->name = "sfs";
233 		misc->fops = &sfs_fops;
234 		misc->mode = 0600;
235 
236 		ret = misc_register(misc);
237 		if (ret)
238 			return ret;
239 
240 		kref_init(&misc_dev->refcount);
241 	} else {
242 		kref_get(&misc_dev->refcount);
243 	}
244 
245 	sfs->misc = misc_dev;
246 	dev_dbg(dev, "registered SFS device\n");
247 
248 	return 0;
249 }
250 
sfs_dev_init(struct psp_device * psp)251 int sfs_dev_init(struct psp_device *psp)
252 {
253 	struct device *dev = psp->dev;
254 	struct sfs_device *sfs_dev;
255 	struct page *page;
256 	int ret = -ENOMEM;
257 
258 	sfs_dev = devm_kzalloc(dev, sizeof(*sfs_dev), GFP_KERNEL);
259 	if (!sfs_dev)
260 		return -ENOMEM;
261 
262 	/*
263 	 * Pre-allocate 2MB command buffer for all SFS commands using
264 	 * SNP HV_Fixed page allocator which also transitions the
265 	 * SFS command buffer to HV_Fixed page state if SNP is enabled.
266 	 */
267 	page = snp_alloc_hv_fixed_pages(SFS_NUM_2MB_PAGES_CMDBUF);
268 	if (!page) {
269 		dev_dbg(dev, "Command Buffer HV-Fixed page allocation failed\n");
270 		goto cleanup_dev;
271 	}
272 	sfs_dev->page = page;
273 	sfs_dev->command_buf = page_address(page);
274 
275 	dev_dbg(dev, "Command buffer 0x%px to be marked as HV_Fixed\n", sfs_dev->command_buf);
276 
277 	/*
278 	 * SFS command buffer must be mapped as non-cacheable.
279 	 */
280 	ret = set_memory_uc((unsigned long)sfs_dev->command_buf, SFS_NUM_PAGES_CMDBUF);
281 	if (ret) {
282 		dev_dbg(dev, "Set memory uc failed\n");
283 		goto cleanup_cmd_buf;
284 	}
285 
286 	dev_dbg(dev, "Command buffer 0x%px marked uncacheable\n", sfs_dev->command_buf);
287 
288 	psp->sfs_data = sfs_dev;
289 	sfs_dev->dev = dev;
290 	sfs_dev->psp = psp;
291 
292 	ret = sfs_misc_init(sfs_dev);
293 	if (ret)
294 		goto cleanup_mem_attr;
295 
296 	dev_notice(sfs_dev->dev, "SFS support is available\n");
297 
298 	return 0;
299 
300 cleanup_mem_attr:
301 	set_memory_wb((unsigned long)sfs_dev->command_buf, SFS_NUM_PAGES_CMDBUF);
302 
303 cleanup_cmd_buf:
304 	snp_free_hv_fixed_pages(page);
305 
306 cleanup_dev:
307 	psp->sfs_data = NULL;
308 	devm_kfree(dev, sfs_dev);
309 
310 	return ret;
311 }
312