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