xref: /linux/drivers/virt/coco/sev-guest/sev-guest.c (revision f96a974170b749e3a56844e25b31d46a7233b6f6)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AMD Secure Encrypted Virtualization (SEV) guest driver interface
4  *
5  * Copyright (C) 2021-2024 Advanced Micro Devices, Inc.
6  *
7  * Author: Brijesh Singh <brijesh.singh@amd.com>
8  */
9 
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/mutex.h>
14 #include <linux/io.h>
15 #include <linux/platform_device.h>
16 #include <linux/miscdevice.h>
17 #include <linux/set_memory.h>
18 #include <linux/fs.h>
19 #include <linux/tsm.h>
20 #include <crypto/gcm.h>
21 #include <linux/psp-sev.h>
22 #include <linux/sockptr.h>
23 #include <linux/cleanup.h>
24 #include <linux/uuid.h>
25 #include <linux/configfs.h>
26 #include <uapi/linux/sev-guest.h>
27 #include <uapi/linux/psp-sev.h>
28 
29 #include <asm/svm.h>
30 #include <asm/sev.h>
31 
32 #define DEVICE_NAME	"sev-guest"
33 
34 #define SVSM_MAX_RETRIES		3
35 
36 struct snp_guest_dev {
37 	struct device *dev;
38 	struct miscdevice misc;
39 
40 	struct snp_msg_desc *msg_desc;
41 
42 	union {
43 		struct snp_report_req report;
44 		struct snp_derived_key_req derived_key;
45 		struct snp_ext_report_req ext_report;
46 	} req;
47 };
48 
49 /*
50  * The VMPCK ID represents the key used by the SNP guest to communicate with the
51  * SEV firmware in the AMD Secure Processor (ASP, aka PSP). By default, the key
52  * used will be the key associated with the VMPL at which the guest is running.
53  * Should the default key be wiped (see snp_disable_vmpck()), this parameter
54  * allows for using one of the remaining VMPCKs.
55  */
56 static int vmpck_id = -1;
57 module_param(vmpck_id, int, 0444);
58 MODULE_PARM_DESC(vmpck_id, "The VMPCK ID to use when communicating with the PSP.");
59 
60 static inline struct snp_guest_dev *to_snp_dev(struct file *file)
61 {
62 	struct miscdevice *dev = file->private_data;
63 
64 	return container_of(dev, struct snp_guest_dev, misc);
65 }
66 
67 struct snp_req_resp {
68 	sockptr_t req_data;
69 	sockptr_t resp_data;
70 };
71 
72 static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
73 {
74 	struct snp_report_req *report_req = &snp_dev->req.report;
75 	struct snp_msg_desc *mdesc = snp_dev->msg_desc;
76 	struct snp_report_resp *report_resp;
77 	struct snp_guest_req req = {};
78 	int rc, resp_len;
79 
80 	if (!arg->req_data || !arg->resp_data)
81 		return -EINVAL;
82 
83 	if (copy_from_user(report_req, (void __user *)arg->req_data, sizeof(*report_req)))
84 		return -EFAULT;
85 
86 	/*
87 	 * The intermediate response buffer is used while decrypting the
88 	 * response payload. Make sure that it has enough space to cover the
89 	 * authtag.
90 	 */
91 	resp_len = sizeof(report_resp->data) + mdesc->ctx->authsize;
92 	report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
93 	if (!report_resp)
94 		return -ENOMEM;
95 
96 	req.msg_version = arg->msg_version;
97 	req.msg_type = SNP_MSG_REPORT_REQ;
98 	req.vmpck_id = mdesc->vmpck_id;
99 	req.req_buf = report_req;
100 	req.req_sz = sizeof(*report_req);
101 	req.resp_buf = report_resp->data;
102 	req.resp_sz = resp_len;
103 	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
104 
105 	rc = snp_send_guest_request(mdesc, &req, arg);
106 	if (rc)
107 		goto e_free;
108 
109 	if (copy_to_user((void __user *)arg->resp_data, report_resp, sizeof(*report_resp)))
110 		rc = -EFAULT;
111 
112 e_free:
113 	kfree(report_resp);
114 	return rc;
115 }
116 
117 static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
118 {
119 	struct snp_derived_key_req *derived_key_req = &snp_dev->req.derived_key;
120 	struct snp_derived_key_resp derived_key_resp = {0};
121 	struct snp_msg_desc *mdesc = snp_dev->msg_desc;
122 	struct snp_guest_req req = {};
123 	int rc, resp_len;
124 	/* Response data is 64 bytes and max authsize for GCM is 16 bytes. */
125 	u8 buf[64 + 16];
126 
127 	if (!arg->req_data || !arg->resp_data)
128 		return -EINVAL;
129 
130 	/*
131 	 * The intermediate response buffer is used while decrypting the
132 	 * response payload. Make sure that it has enough space to cover the
133 	 * authtag.
134 	 */
135 	resp_len = sizeof(derived_key_resp.data) + mdesc->ctx->authsize;
136 	if (sizeof(buf) < resp_len)
137 		return -ENOMEM;
138 
139 	if (copy_from_user(derived_key_req, (void __user *)arg->req_data,
140 			   sizeof(*derived_key_req)))
141 		return -EFAULT;
142 
143 	req.msg_version = arg->msg_version;
144 	req.msg_type = SNP_MSG_KEY_REQ;
145 	req.vmpck_id = mdesc->vmpck_id;
146 	req.req_buf = derived_key_req;
147 	req.req_sz = sizeof(*derived_key_req);
148 	req.resp_buf = buf;
149 	req.resp_sz = resp_len;
150 	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
151 
152 	rc = snp_send_guest_request(mdesc, &req, arg);
153 	if (rc)
154 		return rc;
155 
156 	memcpy(derived_key_resp.data, buf, sizeof(derived_key_resp.data));
157 	if (copy_to_user((void __user *)arg->resp_data, &derived_key_resp,
158 			 sizeof(derived_key_resp)))
159 		rc = -EFAULT;
160 
161 	/* The response buffer contains the sensitive data, explicitly clear it. */
162 	memzero_explicit(buf, sizeof(buf));
163 	memzero_explicit(&derived_key_resp, sizeof(derived_key_resp));
164 	return rc;
165 }
166 
167 static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg,
168 			  struct snp_req_resp *io)
169 
170 {
171 	struct snp_ext_report_req *report_req = &snp_dev->req.ext_report;
172 	struct snp_msg_desc *mdesc = snp_dev->msg_desc;
173 	struct snp_report_resp *report_resp;
174 	struct snp_guest_req req = {};
175 	int ret, npages = 0, resp_len;
176 	sockptr_t certs_address;
177 
178 	if (sockptr_is_null(io->req_data) || sockptr_is_null(io->resp_data))
179 		return -EINVAL;
180 
181 	if (copy_from_sockptr(report_req, io->req_data, sizeof(*report_req)))
182 		return -EFAULT;
183 
184 	/* caller does not want certificate data */
185 	if (!report_req->certs_len || !report_req->certs_address)
186 		goto cmd;
187 
188 	if (report_req->certs_len > SEV_FW_BLOB_MAX_SIZE ||
189 	    !IS_ALIGNED(report_req->certs_len, PAGE_SIZE))
190 		return -EINVAL;
191 
192 	if (sockptr_is_kernel(io->resp_data)) {
193 		certs_address = KERNEL_SOCKPTR((void *)report_req->certs_address);
194 	} else {
195 		certs_address = USER_SOCKPTR((void __user *)report_req->certs_address);
196 		if (!access_ok(certs_address.user, report_req->certs_len))
197 			return -EFAULT;
198 	}
199 
200 	/*
201 	 * Initialize the intermediate buffer with all zeros. This buffer
202 	 * is used in the guest request message to get the certs blob from
203 	 * the host. If host does not supply any certs in it, then copy
204 	 * zeros to indicate that certificate data was not provided.
205 	 */
206 	memset(mdesc->certs_data, 0, report_req->certs_len);
207 	npages = report_req->certs_len >> PAGE_SHIFT;
208 cmd:
209 	/*
210 	 * The intermediate response buffer is used while decrypting the
211 	 * response payload. Make sure that it has enough space to cover the
212 	 * authtag.
213 	 */
214 	resp_len = sizeof(report_resp->data) + mdesc->ctx->authsize;
215 	report_resp = kzalloc(resp_len, GFP_KERNEL_ACCOUNT);
216 	if (!report_resp)
217 		return -ENOMEM;
218 
219 	mdesc->input.data_npages = npages;
220 
221 	req.msg_version = arg->msg_version;
222 	req.msg_type = SNP_MSG_REPORT_REQ;
223 	req.vmpck_id = mdesc->vmpck_id;
224 	req.req_buf = &report_req->data;
225 	req.req_sz = sizeof(report_req->data);
226 	req.resp_buf = report_resp->data;
227 	req.resp_sz = resp_len;
228 	req.exit_code = SVM_VMGEXIT_EXT_GUEST_REQUEST;
229 
230 	ret = snp_send_guest_request(mdesc, &req, arg);
231 
232 	/* If certs length is invalid then copy the returned length */
233 	if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) {
234 		report_req->certs_len = mdesc->input.data_npages << PAGE_SHIFT;
235 
236 		if (copy_to_sockptr(io->req_data, report_req, sizeof(*report_req)))
237 			ret = -EFAULT;
238 	}
239 
240 	if (ret)
241 		goto e_free;
242 
243 	if (npages && copy_to_sockptr(certs_address, mdesc->certs_data, report_req->certs_len)) {
244 		ret = -EFAULT;
245 		goto e_free;
246 	}
247 
248 	if (copy_to_sockptr(io->resp_data, report_resp, sizeof(*report_resp)))
249 		ret = -EFAULT;
250 
251 e_free:
252 	kfree(report_resp);
253 	return ret;
254 }
255 
256 static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
257 {
258 	struct snp_guest_dev *snp_dev = to_snp_dev(file);
259 	void __user *argp = (void __user *)arg;
260 	struct snp_guest_request_ioctl input;
261 	struct snp_req_resp io;
262 	int ret = -ENOTTY;
263 
264 	if (copy_from_user(&input, argp, sizeof(input)))
265 		return -EFAULT;
266 
267 	input.exitinfo2 = 0xff;
268 
269 	/* Message version must be non-zero */
270 	if (!input.msg_version)
271 		return -EINVAL;
272 
273 	switch (ioctl) {
274 	case SNP_GET_REPORT:
275 		ret = get_report(snp_dev, &input);
276 		break;
277 	case SNP_GET_DERIVED_KEY:
278 		ret = get_derived_key(snp_dev, &input);
279 		break;
280 	case SNP_GET_EXT_REPORT:
281 		/*
282 		 * As get_ext_report() may be called from the ioctl() path and a
283 		 * kernel internal path (configfs-tsm), decorate the passed
284 		 * buffers as user pointers.
285 		 */
286 		io.req_data = USER_SOCKPTR((void __user *)input.req_data);
287 		io.resp_data = USER_SOCKPTR((void __user *)input.resp_data);
288 		ret = get_ext_report(snp_dev, &input, &io);
289 		break;
290 	default:
291 		break;
292 	}
293 
294 	if (input.exitinfo2 && copy_to_user(argp, &input, sizeof(input)))
295 		return -EFAULT;
296 
297 	return ret;
298 }
299 
300 static const struct file_operations snp_guest_fops = {
301 	.owner	= THIS_MODULE,
302 	.unlocked_ioctl = snp_guest_ioctl,
303 };
304 
305 struct snp_msg_report_resp_hdr {
306 	u32 status;
307 	u32 report_size;
308 	u8 rsvd[24];
309 };
310 
311 struct snp_msg_cert_entry {
312 	guid_t guid;
313 	u32 offset;
314 	u32 length;
315 };
316 
317 static int sev_svsm_report_new(struct tsm_report *report, void *data)
318 {
319 	unsigned int rep_len, man_len, certs_len;
320 	struct tsm_desc *desc = &report->desc;
321 	struct svsm_attest_call ac = {};
322 	unsigned int retry_count;
323 	void *rep, *man, *certs;
324 	struct svsm_call call;
325 	unsigned int size;
326 	bool try_again;
327 	void *buffer;
328 	u64 call_id;
329 	int ret;
330 
331 	/*
332 	 * Allocate pages for the request:
333 	 * - Report blob (4K)
334 	 * - Manifest blob (4K)
335 	 * - Certificate blob (16K)
336 	 *
337 	 * Above addresses must be 4K aligned
338 	 */
339 	rep_len = SZ_4K;
340 	man_len = SZ_4K;
341 	certs_len = SEV_FW_BLOB_MAX_SIZE;
342 
343 	if (guid_is_null(&desc->service_guid)) {
344 		call_id = SVSM_ATTEST_CALL(SVSM_ATTEST_SERVICES);
345 	} else {
346 		export_guid(ac.service_guid, &desc->service_guid);
347 		ac.service_manifest_ver = desc->service_manifest_version;
348 
349 		call_id = SVSM_ATTEST_CALL(SVSM_ATTEST_SINGLE_SERVICE);
350 	}
351 
352 	retry_count = 0;
353 
354 retry:
355 	memset(&call, 0, sizeof(call));
356 
357 	size = rep_len + man_len + certs_len;
358 	buffer = alloc_pages_exact(size, __GFP_ZERO);
359 	if (!buffer)
360 		return -ENOMEM;
361 
362 	rep = buffer;
363 	ac.report_buf.pa = __pa(rep);
364 	ac.report_buf.len = rep_len;
365 
366 	man = rep + rep_len;
367 	ac.manifest_buf.pa = __pa(man);
368 	ac.manifest_buf.len = man_len;
369 
370 	certs = man + man_len;
371 	ac.certificates_buf.pa = __pa(certs);
372 	ac.certificates_buf.len = certs_len;
373 
374 	ac.nonce.pa = __pa(desc->inblob);
375 	ac.nonce.len = desc->inblob_len;
376 
377 	ret = snp_issue_svsm_attest_req(call_id, &call, &ac);
378 	if (ret) {
379 		free_pages_exact(buffer, size);
380 
381 		switch (call.rax_out) {
382 		case SVSM_ERR_INVALID_PARAMETER:
383 			try_again = false;
384 
385 			if (ac.report_buf.len > rep_len) {
386 				rep_len = PAGE_ALIGN(ac.report_buf.len);
387 				try_again = true;
388 			}
389 
390 			if (ac.manifest_buf.len > man_len) {
391 				man_len = PAGE_ALIGN(ac.manifest_buf.len);
392 				try_again = true;
393 			}
394 
395 			if (ac.certificates_buf.len > certs_len) {
396 				certs_len = PAGE_ALIGN(ac.certificates_buf.len);
397 				try_again = true;
398 			}
399 
400 			/* If one of the buffers wasn't large enough, retry the request */
401 			if (try_again && retry_count < SVSM_MAX_RETRIES) {
402 				retry_count++;
403 				goto retry;
404 			}
405 
406 			return -EINVAL;
407 		default:
408 			pr_err_ratelimited("SVSM attestation request failed (%d / 0x%llx)\n",
409 					   ret, call.rax_out);
410 			return -EINVAL;
411 		}
412 	}
413 
414 	/*
415 	 * Allocate all the blob memory buffers at once so that the cleanup is
416 	 * done for errors that occur after the first allocation (i.e. before
417 	 * using no_free_ptr()).
418 	 */
419 	rep_len = ac.report_buf.len;
420 	void *rbuf __free(kvfree) = kvzalloc(rep_len, GFP_KERNEL);
421 
422 	man_len = ac.manifest_buf.len;
423 	void *mbuf __free(kvfree) = kvzalloc(man_len, GFP_KERNEL);
424 
425 	certs_len = ac.certificates_buf.len;
426 	void *cbuf __free(kvfree) = certs_len ? kvzalloc(certs_len, GFP_KERNEL) : NULL;
427 
428 	if (!rbuf || !mbuf || (certs_len && !cbuf)) {
429 		free_pages_exact(buffer, size);
430 		return -ENOMEM;
431 	}
432 
433 	memcpy(rbuf, rep, rep_len);
434 	report->outblob = no_free_ptr(rbuf);
435 	report->outblob_len = rep_len;
436 
437 	memcpy(mbuf, man, man_len);
438 	report->manifestblob = no_free_ptr(mbuf);
439 	report->manifestblob_len = man_len;
440 
441 	if (certs_len) {
442 		memcpy(cbuf, certs, certs_len);
443 		report->auxblob = no_free_ptr(cbuf);
444 		report->auxblob_len = certs_len;
445 	}
446 
447 	free_pages_exact(buffer, size);
448 
449 	return 0;
450 }
451 
452 static int sev_report_new(struct tsm_report *report, void *data)
453 {
454 	struct snp_msg_cert_entry *cert_table;
455 	struct tsm_desc *desc = &report->desc;
456 	struct snp_guest_dev *snp_dev = data;
457 	struct snp_msg_report_resp_hdr hdr;
458 	const u32 report_size = SZ_4K;
459 	const u32 ext_size = SEV_FW_BLOB_MAX_SIZE;
460 	u32 certs_size, i, size = report_size + ext_size;
461 	int ret;
462 
463 	if (desc->inblob_len != SNP_REPORT_USER_DATA_SIZE)
464 		return -EINVAL;
465 
466 	if (desc->service_provider) {
467 		if (strcmp(desc->service_provider, "svsm"))
468 			return -EINVAL;
469 
470 		return sev_svsm_report_new(report, data);
471 	}
472 
473 	void *buf __free(kvfree) = kvzalloc(size, GFP_KERNEL);
474 	if (!buf)
475 		return -ENOMEM;
476 
477 	cert_table = buf + report_size;
478 	struct snp_ext_report_req ext_req = {
479 		.data = { .vmpl = desc->privlevel },
480 		.certs_address = (__u64)cert_table,
481 		.certs_len = ext_size,
482 	};
483 	memcpy(&ext_req.data.user_data, desc->inblob, desc->inblob_len);
484 
485 	struct snp_guest_request_ioctl input = {
486 		.msg_version = 1,
487 		.req_data = (__u64)&ext_req,
488 		.resp_data = (__u64)buf,
489 		.exitinfo2 = 0xff,
490 	};
491 	struct snp_req_resp io = {
492 		.req_data = KERNEL_SOCKPTR(&ext_req),
493 		.resp_data = KERNEL_SOCKPTR(buf),
494 	};
495 
496 	ret = get_ext_report(snp_dev, &input, &io);
497 	if (ret)
498 		return ret;
499 
500 	memcpy(&hdr, buf, sizeof(hdr));
501 	if (hdr.status == SEV_RET_INVALID_PARAM)
502 		return -EINVAL;
503 	if (hdr.status == SEV_RET_INVALID_KEY)
504 		return -EINVAL;
505 	if (hdr.status)
506 		return -ENXIO;
507 	if ((hdr.report_size + sizeof(hdr)) > report_size)
508 		return -ENOMEM;
509 
510 	void *rbuf __free(kvfree) = kvzalloc(hdr.report_size, GFP_KERNEL);
511 	if (!rbuf)
512 		return -ENOMEM;
513 
514 	memcpy(rbuf, buf + sizeof(hdr), hdr.report_size);
515 	report->outblob = no_free_ptr(rbuf);
516 	report->outblob_len = hdr.report_size;
517 
518 	certs_size = 0;
519 	for (i = 0; i < ext_size / sizeof(struct snp_msg_cert_entry); i++) {
520 		struct snp_msg_cert_entry *ent = &cert_table[i];
521 
522 		if (guid_is_null(&ent->guid) && !ent->offset && !ent->length)
523 			break;
524 		certs_size = max(certs_size, ent->offset + ent->length);
525 	}
526 
527 	/* Suspicious that the response populated entries without populating size */
528 	if (!certs_size && i)
529 		dev_warn_ratelimited(snp_dev->dev, "certificate slots conveyed without size\n");
530 
531 	/* No certs to report */
532 	if (!certs_size)
533 		return 0;
534 
535 	/* Suspicious that the certificate blob size contract was violated
536 	 */
537 	if (certs_size > ext_size) {
538 		dev_warn_ratelimited(snp_dev->dev, "certificate data truncated\n");
539 		certs_size = ext_size;
540 	}
541 
542 	void *cbuf __free(kvfree) = kvzalloc(certs_size, GFP_KERNEL);
543 	if (!cbuf)
544 		return -ENOMEM;
545 
546 	memcpy(cbuf, cert_table, certs_size);
547 	report->auxblob = no_free_ptr(cbuf);
548 	report->auxblob_len = certs_size;
549 
550 	return 0;
551 }
552 
553 static bool sev_report_attr_visible(int n)
554 {
555 	switch (n) {
556 	case TSM_REPORT_GENERATION:
557 	case TSM_REPORT_PROVIDER:
558 	case TSM_REPORT_PRIVLEVEL:
559 	case TSM_REPORT_PRIVLEVEL_FLOOR:
560 		return true;
561 	case TSM_REPORT_SERVICE_PROVIDER:
562 	case TSM_REPORT_SERVICE_GUID:
563 	case TSM_REPORT_SERVICE_MANIFEST_VER:
564 		return snp_vmpl;
565 	}
566 
567 	return false;
568 }
569 
570 static bool sev_report_bin_attr_visible(int n)
571 {
572 	switch (n) {
573 	case TSM_REPORT_INBLOB:
574 	case TSM_REPORT_OUTBLOB:
575 	case TSM_REPORT_AUXBLOB:
576 		return true;
577 	case TSM_REPORT_MANIFESTBLOB:
578 		return snp_vmpl;
579 	}
580 
581 	return false;
582 }
583 
584 static struct tsm_ops sev_tsm_ops = {
585 	.name = KBUILD_MODNAME,
586 	.report_new = sev_report_new,
587 	.report_attr_visible = sev_report_attr_visible,
588 	.report_bin_attr_visible = sev_report_bin_attr_visible,
589 };
590 
591 static void unregister_sev_tsm(void *data)
592 {
593 	tsm_unregister(&sev_tsm_ops);
594 }
595 
596 static int __init sev_guest_probe(struct platform_device *pdev)
597 {
598 	struct device *dev = &pdev->dev;
599 	struct snp_guest_dev *snp_dev;
600 	struct snp_msg_desc *mdesc;
601 	struct miscdevice *misc;
602 	int ret;
603 
604 	BUILD_BUG_ON(sizeof(struct snp_guest_msg) > PAGE_SIZE);
605 
606 	if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
607 		return -ENODEV;
608 
609 	snp_dev = devm_kzalloc(&pdev->dev, sizeof(struct snp_guest_dev), GFP_KERNEL);
610 	if (!snp_dev)
611 		return -ENOMEM;
612 
613 	mdesc = snp_msg_alloc();
614 	if (IS_ERR_OR_NULL(mdesc))
615 		return -ENOMEM;
616 
617 	ret = snp_msg_init(mdesc, vmpck_id);
618 	if (ret)
619 		goto e_msg_init;
620 
621 	platform_set_drvdata(pdev, snp_dev);
622 	snp_dev->dev = dev;
623 
624 	misc = &snp_dev->misc;
625 	misc->minor = MISC_DYNAMIC_MINOR;
626 	misc->name = DEVICE_NAME;
627 	misc->fops = &snp_guest_fops;
628 
629 	/* Set the privlevel_floor attribute based on the vmpck_id */
630 	sev_tsm_ops.privlevel_floor = mdesc->vmpck_id;
631 
632 	ret = tsm_register(&sev_tsm_ops, snp_dev);
633 	if (ret)
634 		goto e_msg_init;
635 
636 	ret = devm_add_action_or_reset(&pdev->dev, unregister_sev_tsm, NULL);
637 	if (ret)
638 		goto e_msg_init;
639 
640 	ret =  misc_register(misc);
641 	if (ret)
642 		goto e_msg_init;
643 
644 	snp_dev->msg_desc = mdesc;
645 	dev_info(dev, "Initialized SEV guest driver (using VMPCK%d communication key)\n",
646 		 mdesc->vmpck_id);
647 	return 0;
648 
649 e_msg_init:
650 	snp_msg_free(mdesc);
651 
652 	return ret;
653 }
654 
655 static void __exit sev_guest_remove(struct platform_device *pdev)
656 {
657 	struct snp_guest_dev *snp_dev = platform_get_drvdata(pdev);
658 
659 	snp_msg_free(snp_dev->msg_desc);
660 	misc_deregister(&snp_dev->misc);
661 }
662 
663 /*
664  * This driver is meant to be a common SEV guest interface driver and to
665  * support any SEV guest API. As such, even though it has been introduced
666  * with the SEV-SNP support, it is named "sev-guest".
667  *
668  * sev_guest_remove() lives in .exit.text. For drivers registered via
669  * module_platform_driver_probe() this is ok because they cannot get unbound
670  * at runtime. So mark the driver struct with __refdata to prevent modpost
671  * triggering a section mismatch warning.
672  */
673 static struct platform_driver sev_guest_driver __refdata = {
674 	.remove		= __exit_p(sev_guest_remove),
675 	.driver		= {
676 		.name = "sev-guest",
677 	},
678 };
679 
680 module_platform_driver_probe(sev_guest_driver, sev_guest_probe);
681 
682 MODULE_AUTHOR("Brijesh Singh <brijesh.singh@amd.com>");
683 MODULE_LICENSE("GPL");
684 MODULE_VERSION("1.0.0");
685 MODULE_DESCRIPTION("AMD SEV Guest Driver");
686 MODULE_ALIAS("platform:sev-guest");
687