From: David Woodhouse <[email protected]> Registering the VP assist page arms the PV EOI / APIC assist optimisation through a gfn_to_hva cache, and that cache refuses ranges carrying RW memory protections in plane 0's view. The Windows secure kernel places its VTL1 assist page in memory it has protected against VTL0, so the MSR write failed and VTL1 had no assist page at all: no VTL entry reasons, no VTL-return register control, no boot.
Register the page without arming PV EOI when the vCPU is in a plane above 0. KVM then never sets the no-EOI-required bit for that plane, so the guest always performs a real EOI; only the fast path is lost. Signed-off-by: David Woodhouse <[email protected]> Assisted-by: LLM --- arch/x86/kvm/hyperv.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 797c5cbfbbaf..ea80536caa48 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1609,7 +1609,8 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) if (!(data & HV_X64_MSR_VP_ASSIST_PAGE_ENABLE)) { hv_vcpu->hv_vapic = data; - if (kvm_lapic_set_pv_eoi(vcpu, 0, 0)) + if (!vcpu->plane_level && + kvm_lapic_set_pv_eoi(vcpu, 0, 0)) return 1; break; } @@ -1627,9 +1628,24 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) return 1; hv_vcpu->hv_vapic = data; kvm_vcpu_mark_page_dirty(vcpu, gfn); - if (kvm_lapic_set_pv_eoi(vcpu, - gfn_to_gpa(gfn) | KVM_MSR_ENABLED, - sizeof(struct hv_vp_assist_page))) + + /* + * The gfn_to_hva cache behind the PV EOI / APIC assist + * optimization validates against plane 0's memory + * attributes, and a higher plane's VP assist page may + * live on a page the plane protected against plane 0 + * (the Windows secure kernel's does). Don't arm PV EOI + * there: pv_eoi.msr_val stays clear, which keeps + * kvm_hv_assist_page_enabled() false for the plane, so + * every assist-page consumer behind it (PV EOI, nested + * enlightened VMCS, the SVM VP-assist read) is disabled + * and KVM never touches the page's contents. The guest + * always performs a real EOI. + */ + if (!vcpu->plane_level && + kvm_lapic_set_pv_eoi(vcpu, + gfn_to_gpa(gfn) | KVM_MSR_ENABLED, + sizeof(struct hv_vp_assist_page))) return 1; break; } -- 2.50.1

