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

KVM: x86: Move Hyper-V partition assist page out of Hyper-V emulation context

Hyper-V partition assist page is used when KVM runs on top of Hyper-V and
is not used for Windows/Hyper-V guests on KVM, this means that 'hv_pa_pg'
placement in 'struct kvm_hv' is unfortunate. As a preparation to making
Hyper-V emulation optional, move 'hv_pa_pg' to 'struct kvm_arch' and put it
under CONFIG_HYPERV.

While on it, introduce hv_get_partition_assist_page() helper to allocate
partition assist page. Move the comment explaining why we use a single page
for all vCPUs from VMX and expand it a bit.

No functional change intended.

Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Tested-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Link: https://lore.kernel.org/r/20231205103630.1391318-3-vkuznets@redhat.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

authored by

Vitaly Kuznetsov and committed by
Sean Christopherson
cfef5af3 87562052

+30 -20
+1 -1
arch/x86/include/asm/kvm_host.h
··· 1125 1125 */ 1126 1126 unsigned int synic_auto_eoi_used; 1127 1127 1128 - struct hv_partition_assist_pg *hv_pa_pg; 1129 1128 struct kvm_hv_syndbg hv_syndbg; 1130 1129 }; 1131 1130 ··· 1446 1447 #if IS_ENABLED(CONFIG_HYPERV) 1447 1448 hpa_t hv_root_tdp; 1448 1449 spinlock_t hv_root_tdp_lock; 1450 + struct hv_partition_assist_pg *hv_pa_pg; 1449 1451 #endif 1450 1452 /* 1451 1453 * VM-scope maximum vCPU ID. Used to determine the size of structures
+20
arch/x86/kvm/kvm_onhyperv.h
··· 10 10 int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages); 11 11 int hv_flush_remote_tlbs(struct kvm *kvm); 12 12 void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp); 13 + static inline hpa_t hv_get_partition_assist_page(struct kvm_vcpu *vcpu) 14 + { 15 + /* 16 + * Partition assist page is something which Hyper-V running in L0 17 + * requires from KVM running in L1 before direct TLB flush for L2 18 + * guests can be enabled. KVM doesn't currently use the page but to 19 + * comply with TLFS it still needs to be allocated. For now, this 20 + * is a single page shared among all vCPUs. 21 + */ 22 + struct hv_partition_assist_pg **p_hv_pa_pg = 23 + &vcpu->kvm->arch.hv_pa_pg; 24 + 25 + if (!*p_hv_pa_pg) 26 + *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT); 27 + 28 + if (!*p_hv_pa_pg) 29 + return INVALID_PAGE; 30 + 31 + return __pa(*p_hv_pa_pg); 32 + } 13 33 #else /* !CONFIG_HYPERV */ 14 34 static inline int hv_flush_remote_tlbs(struct kvm *kvm) 15 35 {
+3 -7
arch/x86/kvm/svm/svm_onhyperv.c
··· 18 18 int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) 19 19 { 20 20 struct hv_vmcb_enlightenments *hve; 21 - struct hv_partition_assist_pg **p_hv_pa_pg = 22 - &to_kvm_hv(vcpu->kvm)->hv_pa_pg; 21 + hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu); 23 22 24 - if (!*p_hv_pa_pg) 25 - *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL); 26 - 27 - if (!*p_hv_pa_pg) 23 + if (partition_assist_page == INVALID_PAGE) 28 24 return -ENOMEM; 29 25 30 26 hve = &to_svm(vcpu)->vmcb->control.hv_enlightenments; 31 27 32 - hve->partition_assist_page = __pa(*p_hv_pa_pg); 28 + hve->partition_assist_page = partition_assist_page; 33 29 hve->hv_vm_id = (unsigned long)vcpu->kvm; 34 30 if (!hve->hv_enlightenments_control.nested_flush_hypercall) { 35 31 hve->hv_enlightenments_control.nested_flush_hypercall = 1;
+3 -11
arch/x86/kvm/vmx/vmx.c
··· 523 523 static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) 524 524 { 525 525 struct hv_enlightened_vmcs *evmcs; 526 - struct hv_partition_assist_pg **p_hv_pa_pg = 527 - &to_kvm_hv(vcpu->kvm)->hv_pa_pg; 528 - /* 529 - * Synthetic VM-Exit is not enabled in current code and so All 530 - * evmcs in singe VM shares same assist page. 531 - */ 532 - if (!*p_hv_pa_pg) 533 - *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT); 526 + hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu); 534 527 535 - if (!*p_hv_pa_pg) 528 + if (partition_assist_page == INVALID_PAGE) 536 529 return -ENOMEM; 537 530 538 531 evmcs = (struct hv_enlightened_vmcs *)to_vmx(vcpu)->loaded_vmcs->vmcs; 539 532 540 - evmcs->partition_assist_page = 541 - __pa(*p_hv_pa_pg); 533 + evmcs->partition_assist_page = partition_assist_page; 542 534 evmcs->hv_vm_id = (unsigned long)vcpu->kvm; 543 535 evmcs->hv_enlightenments_control.nested_flush_hypercall = 1; 544 536
+3 -1
arch/x86/kvm/x86.c
··· 12438 12438 12439 12439 void kvm_arch_free_vm(struct kvm *kvm) 12440 12440 { 12441 - kfree(to_kvm_hv(kvm)->hv_pa_pg); 12441 + #if IS_ENABLED(CONFIG_HYPERV) 12442 + kfree(kvm->arch.hv_pa_pg); 12443 + #endif 12442 12444 __kvm_arch_free_vm(kvm); 12443 12445 } 12444 12446