Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: SVM: Provide support to launch and run an SEV-ES guest

An SEV-ES guest is started by invoking a new SEV initialization ioctl,
KVM_SEV_ES_INIT. This identifies the guest as an SEV-ES guest, which is
used to drive the appropriate ASID allocation, VMSA encryption, etc.

Before being able to run an SEV-ES vCPU, the vCPU VMSA must be encrypted
and measured. This is done using the LAUNCH_UPDATE_VMSA command after all
calls to LAUNCH_UPDATE_DATA have been performed, but before LAUNCH_MEASURE
has been performed. In order to establish the encrypted VMSA, the current
(traditional) VMSA and the GPRs are synced to the page that will hold the
encrypted VMSA and then LAUNCH_UPDATE_VMSA is invoked. The vCPU is then
marked as having protected guest state.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <e9643245adb809caf3a87c09997926d2f3d6ff41.1607620209.git.thomas.lendacky@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Tom Lendacky and committed by
Paolo Bonzini
ad73109a 16809ecd

+104
+104
arch/x86/kvm/svm/sev.c
··· 201 201 return ret; 202 202 } 203 203 204 + static int sev_es_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp) 205 + { 206 + if (!sev_es) 207 + return -ENOTTY; 208 + 209 + to_kvm_svm(kvm)->sev_info.es_active = true; 210 + 211 + return sev_guest_init(kvm, argp); 212 + } 213 + 204 214 static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error) 205 215 { 206 216 struct sev_data_activate *data; ··· 507 497 sev_unpin_memory(kvm, inpages, npages); 508 498 e_free: 509 499 kfree(data); 500 + return ret; 501 + } 502 + 503 + static int sev_es_sync_vmsa(struct vcpu_svm *svm) 504 + { 505 + struct vmcb_save_area *save = &svm->vmcb->save; 506 + 507 + /* Check some debug related fields before encrypting the VMSA */ 508 + if (svm->vcpu.guest_debug || (save->dr7 & ~DR7_FIXED_1)) 509 + return -EINVAL; 510 + 511 + /* Sync registgers */ 512 + save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX]; 513 + save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX]; 514 + save->rcx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; 515 + save->rdx = svm->vcpu.arch.regs[VCPU_REGS_RDX]; 516 + save->rsp = svm->vcpu.arch.regs[VCPU_REGS_RSP]; 517 + save->rbp = svm->vcpu.arch.regs[VCPU_REGS_RBP]; 518 + save->rsi = svm->vcpu.arch.regs[VCPU_REGS_RSI]; 519 + save->rdi = svm->vcpu.arch.regs[VCPU_REGS_RDI]; 520 + save->r8 = svm->vcpu.arch.regs[VCPU_REGS_R8]; 521 + save->r9 = svm->vcpu.arch.regs[VCPU_REGS_R9]; 522 + save->r10 = svm->vcpu.arch.regs[VCPU_REGS_R10]; 523 + save->r11 = svm->vcpu.arch.regs[VCPU_REGS_R11]; 524 + save->r12 = svm->vcpu.arch.regs[VCPU_REGS_R12]; 525 + save->r13 = svm->vcpu.arch.regs[VCPU_REGS_R13]; 526 + save->r14 = svm->vcpu.arch.regs[VCPU_REGS_R14]; 527 + save->r15 = svm->vcpu.arch.regs[VCPU_REGS_R15]; 528 + save->rip = svm->vcpu.arch.regs[VCPU_REGS_RIP]; 529 + 530 + /* Sync some non-GPR registers before encrypting */ 531 + save->xcr0 = svm->vcpu.arch.xcr0; 532 + save->pkru = svm->vcpu.arch.pkru; 533 + save->xss = svm->vcpu.arch.ia32_xss; 534 + 535 + /* 536 + * SEV-ES will use a VMSA that is pointed to by the VMCB, not 537 + * the traditional VMSA that is part of the VMCB. Copy the 538 + * traditional VMSA as it has been built so far (in prep 539 + * for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state. 540 + */ 541 + memcpy(svm->vmsa, save, sizeof(*save)); 542 + 543 + return 0; 544 + } 545 + 546 + static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp) 547 + { 548 + struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info; 549 + struct sev_data_launch_update_vmsa *vmsa; 550 + int i, ret; 551 + 552 + if (!sev_es_guest(kvm)) 553 + return -ENOTTY; 554 + 555 + vmsa = kzalloc(sizeof(*vmsa), GFP_KERNEL); 556 + if (!vmsa) 557 + return -ENOMEM; 558 + 559 + for (i = 0; i < kvm->created_vcpus; i++) { 560 + struct vcpu_svm *svm = to_svm(kvm->vcpus[i]); 561 + 562 + /* Perform some pre-encryption checks against the VMSA */ 563 + ret = sev_es_sync_vmsa(svm); 564 + if (ret) 565 + goto e_free; 566 + 567 + /* 568 + * The LAUNCH_UPDATE_VMSA command will perform in-place 569 + * encryption of the VMSA memory content (i.e it will write 570 + * the same memory region with the guest's key), so invalidate 571 + * it first. 572 + */ 573 + clflush_cache_range(svm->vmsa, PAGE_SIZE); 574 + 575 + vmsa->handle = sev->handle; 576 + vmsa->address = __sme_pa(svm->vmsa); 577 + vmsa->len = PAGE_SIZE; 578 + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_VMSA, vmsa, 579 + &argp->error); 580 + if (ret) 581 + goto e_free; 582 + 583 + svm->vcpu.arch.guest_state_protected = true; 584 + } 585 + 586 + e_free: 587 + kfree(vmsa); 510 588 return ret; 511 589 } 512 590 ··· 1055 957 case KVM_SEV_INIT: 1056 958 r = sev_guest_init(kvm, &sev_cmd); 1057 959 break; 960 + case KVM_SEV_ES_INIT: 961 + r = sev_es_guest_init(kvm, &sev_cmd); 962 + break; 1058 963 case KVM_SEV_LAUNCH_START: 1059 964 r = sev_launch_start(kvm, &sev_cmd); 1060 965 break; 1061 966 case KVM_SEV_LAUNCH_UPDATE_DATA: 1062 967 r = sev_launch_update_data(kvm, &sev_cmd); 968 + break; 969 + case KVM_SEV_LAUNCH_UPDATE_VMSA: 970 + r = sev_launch_update_vmsa(kvm, &sev_cmd); 1063 971 break; 1064 972 case KVM_SEV_LAUNCH_MEASURE: 1065 973 r = sev_launch_measure(kvm, &sev_cmd);