|
19 | 19 | #include <linux/misc_cgroup.h>
|
20 | 20 | #include <linux/processor.h>
|
21 | 21 | #include <linux/trace_events.h>
|
| 22 | +#include <uapi/linux/sev-guest.h> |
22 | 23 |
|
23 | 24 | #include <asm/pkru.h>
|
24 | 25 | #include <asm/trapnr.h>
|
@@ -326,6 +327,78 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
|
326 | 327 | sev_decommission(handle);
|
327 | 328 | }
|
328 | 329 |
|
| 330 | +/* |
| 331 | + * This sets up bounce buffers/firmware pages to handle SNP Guest Request |
| 332 | + * messages (e.g. attestation requests). See "SNP Guest Request" in the GHCB |
| 333 | + * 2.0 specification for more details. |
| 334 | + * |
| 335 | + * Technically, when an SNP Guest Request is issued, the guest will provide its |
| 336 | + * own request/response pages, which could in theory be passed along directly |
| 337 | + * to firmware rather than using bounce pages. However, these pages would need |
| 338 | + * special care: |
| 339 | + * |
| 340 | + * - Both pages are from shared guest memory, so they need to be protected |
| 341 | + * from migration/etc. occurring while firmware reads/writes to them. At a |
| 342 | + * minimum, this requires elevating the ref counts and potentially needing |
| 343 | + * an explicit pinning of the memory. This places additional restrictions |
| 344 | + * on what type of memory backends userspace can use for shared guest |
| 345 | + * memory since there is some reliance on using refcounted pages. |
| 346 | + * |
| 347 | + * - The response page needs to be switched to Firmware-owned[1] state |
| 348 | + * before the firmware can write to it, which can lead to potential |
| 349 | + * host RMP #PFs if the guest is misbehaved and hands the host a |
| 350 | + * guest page that KVM might write to for other reasons (e.g. virtio |
| 351 | + * buffers/etc.). |
| 352 | + * |
| 353 | + * Both of these issues can be avoided completely by using separately-allocated |
| 354 | + * bounce pages for both the request/response pages and passing those to |
| 355 | + * firmware instead. So that's what is being set up here. |
| 356 | + * |
| 357 | + * Guest requests rely on message sequence numbers to ensure requests are |
| 358 | + * issued to firmware in the order the guest issues them, so concurrent guest |
| 359 | + * requests generally shouldn't happen. But a misbehaved guest could issue |
| 360 | + * concurrent guest requests in theory, so a mutex is used to serialize |
| 361 | + * access to the bounce buffers. |
| 362 | + * |
| 363 | + * [1] See the "Page States" section of the SEV-SNP Firmware ABI for more |
| 364 | + * details on Firmware-owned pages, along with "RMP and VMPL Access Checks" |
| 365 | + * in the APM for details on the related RMP restrictions. |
| 366 | + */ |
| 367 | +static int snp_guest_req_init(struct kvm *kvm) |
| 368 | +{ |
| 369 | + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); |
| 370 | + struct page *req_page; |
| 371 | + |
| 372 | + req_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); |
| 373 | + if (!req_page) |
| 374 | + return -ENOMEM; |
| 375 | + |
| 376 | + sev->guest_resp_buf = snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); |
| 377 | + if (!sev->guest_resp_buf) { |
| 378 | + __free_page(req_page); |
| 379 | + return -EIO; |
| 380 | + } |
| 381 | + |
| 382 | + sev->guest_req_buf = page_address(req_page); |
| 383 | + mutex_init(&sev->guest_req_mutex); |
| 384 | + |
| 385 | + return 0; |
| 386 | +} |
| 387 | + |
| 388 | +static void snp_guest_req_cleanup(struct kvm *kvm) |
| 389 | +{ |
| 390 | + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); |
| 391 | + |
| 392 | + if (sev->guest_resp_buf) |
| 393 | + snp_free_firmware_page(sev->guest_resp_buf); |
| 394 | + |
| 395 | + if (sev->guest_req_buf) |
| 396 | + __free_page(virt_to_page(sev->guest_req_buf)); |
| 397 | + |
| 398 | + sev->guest_req_buf = NULL; |
| 399 | + sev->guest_resp_buf = NULL; |
| 400 | +} |
| 401 | + |
329 | 402 | static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
|
330 | 403 | struct kvm_sev_init *data,
|
331 | 404 | unsigned long vm_type)
|
@@ -376,6 +449,10 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
|
376 | 449 | if (ret)
|
377 | 450 | goto e_free;
|
378 | 451 |
|
| 452 | + /* This needs to happen after SEV/SNP firmware initialization. */ |
| 453 | + if (vm_type == KVM_X86_SNP_VM && snp_guest_req_init(kvm)) |
| 454 | + goto e_free; |
| 455 | + |
379 | 456 | INIT_LIST_HEAD(&sev->regions_list);
|
380 | 457 | INIT_LIST_HEAD(&sev->mirror_vms);
|
381 | 458 | sev->need_init = false;
|
@@ -2834,6 +2911,8 @@ void sev_vm_destroy(struct kvm *kvm)
|
2834 | 2911 | }
|
2835 | 2912 |
|
2836 | 2913 | if (sev_snp_guest(kvm)) {
|
| 2914 | + snp_guest_req_cleanup(kvm); |
| 2915 | + |
2837 | 2916 | /*
|
2838 | 2917 | * Decomission handles unbinding of the ASID. If it fails for
|
2839 | 2918 | * some unexpected reason, just leak the ASID.
|
@@ -3299,6 +3378,13 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
3299 | 3378 | if (!sev_snp_guest(vcpu->kvm) || !kvm_ghcb_sw_scratch_is_valid(svm))
|
3300 | 3379 | goto vmgexit_err;
|
3301 | 3380 | break;
|
| 3381 | + case SVM_VMGEXIT_GUEST_REQUEST: |
| 3382 | + if (!sev_snp_guest(vcpu->kvm) || |
| 3383 | + !PAGE_ALIGNED(control->exit_info_1) || |
| 3384 | + !PAGE_ALIGNED(control->exit_info_2) || |
| 3385 | + control->exit_info_1 == control->exit_info_2) |
| 3386 | + goto vmgexit_err; |
| 3387 | + break; |
3302 | 3388 | default:
|
3303 | 3389 | reason = GHCB_ERR_INVALID_EVENT;
|
3304 | 3390 | goto vmgexit_err;
|
@@ -3917,6 +4003,51 @@ static int sev_snp_ap_creation(struct vcpu_svm *svm)
|
3917 | 4003 | return ret;
|
3918 | 4004 | }
|
3919 | 4005 |
|
| 4006 | +static int snp_handle_guest_req(struct vcpu_svm *svm, gpa_t req_gpa, gpa_t resp_gpa) |
| 4007 | +{ |
| 4008 | + struct sev_data_snp_guest_request data = {0}; |
| 4009 | + struct kvm *kvm = svm->vcpu.kvm; |
| 4010 | + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); |
| 4011 | + sev_ret_code fw_err = 0; |
| 4012 | + int ret; |
| 4013 | + |
| 4014 | + if (!sev_snp_guest(kvm)) |
| 4015 | + return -EINVAL; |
| 4016 | + |
| 4017 | + mutex_lock(&sev->guest_req_mutex); |
| 4018 | + |
| 4019 | + if (kvm_read_guest(kvm, req_gpa, sev->guest_req_buf, PAGE_SIZE)) { |
| 4020 | + ret = -EIO; |
| 4021 | + goto out_unlock; |
| 4022 | + } |
| 4023 | + |
| 4024 | + data.gctx_paddr = __psp_pa(sev->snp_context); |
| 4025 | + data.req_paddr = __psp_pa(sev->guest_req_buf); |
| 4026 | + data.res_paddr = __psp_pa(sev->guest_resp_buf); |
| 4027 | + |
| 4028 | + /* |
| 4029 | + * Firmware failures are propagated on to guest, but any other failure |
| 4030 | + * condition along the way should be reported to userspace. E.g. if |
| 4031 | + * the PSP is dead and commands are timing out. |
| 4032 | + */ |
| 4033 | + ret = sev_issue_cmd(kvm, SEV_CMD_SNP_GUEST_REQUEST, &data, &fw_err); |
| 4034 | + if (ret && !fw_err) |
| 4035 | + goto out_unlock; |
| 4036 | + |
| 4037 | + if (kvm_write_guest(kvm, resp_gpa, sev->guest_resp_buf, PAGE_SIZE)) { |
| 4038 | + ret = -EIO; |
| 4039 | + goto out_unlock; |
| 4040 | + } |
| 4041 | + |
| 4042 | + ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, SNP_GUEST_ERR(0, fw_err)); |
| 4043 | + |
| 4044 | + ret = 1; /* resume guest */ |
| 4045 | + |
| 4046 | +out_unlock: |
| 4047 | + mutex_unlock(&sev->guest_req_mutex); |
| 4048 | + return ret; |
| 4049 | +} |
| 4050 | + |
3920 | 4051 | static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
|
3921 | 4052 | {
|
3922 | 4053 | struct vmcb_control_area *control = &svm->vmcb->control;
|
@@ -4191,6 +4322,9 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
|
4191 | 4322 |
|
4192 | 4323 | ret = 1;
|
4193 | 4324 | break;
|
| 4325 | + case SVM_VMGEXIT_GUEST_REQUEST: |
| 4326 | + ret = snp_handle_guest_req(svm, control->exit_info_1, control->exit_info_2); |
| 4327 | + break; |
4194 | 4328 | case SVM_VMGEXIT_UNSUPPORTED_EVENT:
|
4195 | 4329 | vcpu_unimpl(vcpu,
|
4196 | 4330 | "vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
|
|
0 commit comments