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