File Index
Files and directories
Sign in
FILE

sfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/ccp/sfs.c C
  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
 20static DEFINE_MUTEX(sfs_ioctl_mutex);
 21
 22static struct sfs_misc_dev *misc_dev;
 23
 24static 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
 44static 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
 56static 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
105static 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
180static const struct file_operations sfs_fops = {
181	.owner	= THIS_MODULE,
182	.unlocked_ioctl = sfs_ioctl,
183};
184
185static void sfs_exit(struct kref *ref)
186{
187	misc_deregister(&misc_dev->misc);
188	kfree(misc_dev);
189	misc_dev = NULL;
190}
191
192void 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() */
213static 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
251int 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
300cleanup_mem_attr:
301	set_memory_wb((unsigned long)sfs_dev->command_buf, SFS_NUM_PAGES_CMDBUF);
302
303cleanup_cmd_buf:
304	snp_free_hv_fixed_pages(page);
305
306cleanup_dev:
307	psp->sfs_data = NULL;
308	devm_kfree(dev, sfs_dev);
309
310	return ret;
311}
~/ Read-only file preview.