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

KVM: SVM: restore host save area from assembly

Allow access to the percpu area via the GS segment base, which is
needed in order to access the saved host spec_ctrl value. In linux-next
FILL_RETURN_BUFFER also needs to access percpu data.

For simplicity, the physical address of the save area is added to struct
svm_cpu_data.

Cc: stable@vger.kernel.org
Fixes: a149180fbcf3 ("x86: Add magic AMD return-thunk")
Reported-by: Nathan Chancellor <nathan@kernel.org>
Analyzed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Reviewed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

+26 -13
+1
arch/x86/kvm/kvm-asm-offsets.c
··· 18 18 OFFSET(SVM_current_vmcb, vcpu_svm, current_vmcb); 19 19 OFFSET(SVM_vmcb01, vcpu_svm, vmcb01); 20 20 OFFSET(KVM_VMCB_pa, kvm_vmcb_info, pa); 21 + OFFSET(SD_save_area_pa, svm_cpu_data, save_area_pa); 21 22 } 22 23 23 24 if (IS_ENABLED(CONFIG_KVM_INTEL)) {
+6 -8
arch/x86/kvm/svm/svm.c
··· 592 592 593 593 wrmsrl(MSR_EFER, efer | EFER_SVME); 594 594 595 - wrmsrl(MSR_VM_HSAVE_PA, __sme_page_pa(sd->save_area)); 595 + wrmsrl(MSR_VM_HSAVE_PA, sd->save_area_pa); 596 596 597 597 if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { 598 598 /* ··· 648 648 649 649 kfree(sd->sev_vmcbs); 650 650 __free_page(sd->save_area); 651 + sd->save_area_pa = 0; 651 652 sd->save_area = NULL; 652 653 } 653 654 ··· 666 665 if (ret) 667 666 goto free_save_area; 668 667 668 + sd->save_area_pa = __sme_page_pa(sd->save_area); 669 669 return 0; 670 670 671 671 free_save_area: ··· 1452 1450 * Save additional host state that will be restored on VMEXIT (sev-es) 1453 1451 * or subsequent vmload of host save area. 1454 1452 */ 1455 - vmsave(__sme_page_pa(sd->save_area)); 1453 + vmsave(sd->save_area_pa); 1456 1454 if (sev_es_guest(vcpu->kvm)) { 1457 1455 struct sev_es_save_area *hostsa; 1458 1456 hostsa = (struct sev_es_save_area *)(page_address(sd->save_area) + 0x400); ··· 3907 3905 3908 3906 guest_state_enter_irqoff(); 3909 3907 3910 - if (sev_es_guest(vcpu->kvm)) { 3908 + if (sev_es_guest(vcpu->kvm)) 3911 3909 __svm_sev_es_vcpu_run(svm); 3912 - } else { 3913 - struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu); 3914 - 3910 + else 3915 3911 __svm_vcpu_run(svm); 3916 - vmload(__sme_page_pa(sd->save_area)); 3917 - } 3918 3912 3919 3913 guest_state_exit_irqoff(); 3920 3914 }
+2
arch/x86/kvm/svm/svm.h
··· 287 287 struct kvm_ldttss_desc *tss_desc; 288 288 289 289 struct page *save_area; 290 + unsigned long save_area_pa; 291 + 290 292 struct vmcb *current_vmcb; 291 293 292 294 /* index = sev_asid, value = vmcb pointer */
-5
arch/x86/kvm/svm/svm_ops.h
··· 61 61 svm_asm1(vmsave, "a" (pa), "memory"); 62 62 } 63 63 64 - static __always_inline void vmload(unsigned long pa) 65 - { 66 - svm_asm1(vmload, "a" (pa), "memory"); 67 - } 68 - 69 64 #endif /* __KVM_X86_SVM_OPS_H */
+17
arch/x86/kvm/svm/vmenter.S
··· 49 49 #endif 50 50 push %_ASM_BX 51 51 52 + /* 53 + * Save variables needed after vmexit on the stack, in inverse 54 + * order compared to when they are needed. 55 + */ 56 + 57 + /* Needed to restore access to percpu variables. */ 58 + __ASM_SIZE(push) PER_CPU_VAR(svm_data + SD_save_area_pa) 59 + 52 60 /* Save @svm. */ 53 61 push %_ASM_ARG1 54 62 ··· 132 124 5: vmsave %_ASM_AX 133 125 6: 134 126 127 + /* Restores GSBASE among other things, allowing access to percpu data. */ 128 + pop %_ASM_AX 129 + 7: vmload %_ASM_AX 130 + 8: 131 + 135 132 #ifdef CONFIG_RETPOLINE 136 133 /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */ 137 134 FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE ··· 200 187 50: cmpb $0, kvm_rebooting 201 188 jne 6b 202 189 ud2 190 + 70: cmpb $0, kvm_rebooting 191 + jne 8b 192 + ud2 203 193 204 194 _ASM_EXTABLE(1b, 10b) 205 195 _ASM_EXTABLE(3b, 30b) 206 196 _ASM_EXTABLE(5b, 50b) 197 + _ASM_EXTABLE(7b, 70b) 207 198 208 199 SYM_FUNC_END(__svm_vcpu_run) 209 200