From: David Woodhouse <[email protected]> The TLFS makes HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL separate instances per VTL; KVM kept a single partition-wide copy, so the Windows secure kernel enabling its own hypercall page from VTL1 clobbered VTL0's.
Index both MSRs by the vCPU's plane. The hypercall page contents are still written into guest RAM on enable, now once per plane's page. Signed-off-by: David Woodhouse <[email protected]> Assisted-by: LLM --- arch/x86/include/asm/kvm_host.h | 9 +++++++-- arch/x86/kvm/hyperv.c | 19 ++++++++++--------- arch/x86/kvm/hyperv.h | 3 ++- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 17dfd232ba58..1c4395f73acb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1202,8 +1202,13 @@ enum hv_tsc_page_status { /* Hyper-V emulation context */ struct kvm_hv { struct mutex hv_lock; - u64 hv_guest_os_id; - u64 hv_hypercall; + /* + * GUEST_OS_ID and the hypercall page are per-VTL instances in the + * TLFS; bank them per plane so a higher VTL enabling its own + * hypercall page does not clobber the lower VTL's. + */ + u64 hv_guest_os_id[KVM_MAX_PLANES]; + u64 hv_hypercall[KVM_MAX_PLANES]; bool hv_forward_hcalls; u64 hv_tsc_page; enum hv_tsc_page_status hv_tsc_page_status; diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index e41d101e327a..e703d8999ff0 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1342,7 +1342,7 @@ static void __kvm_hv_xsaves_xsavec_maybe_warn(struct kvm_vcpu *vcpu) if (hv->xsaves_xsavec_checked) return; - if ((hv->hv_guest_os_id & KVM_HV_WIN2016_GUEST_ID_MASK) != + if ((hv->hv_guest_os_id[0] & KVM_HV_WIN2016_GUEST_ID_MASK) != KVM_HV_WIN2016_GUEST_ID) return; @@ -1384,10 +1384,11 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, switch (msr) { case HV_X64_MSR_GUEST_OS_ID: - hv->hv_guest_os_id = data; + hv->hv_guest_os_id[vcpu->plane_level] = data; /* setting guest os id to zero disables hypercall page */ - if (!hv->hv_guest_os_id) - hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE; + if (!hv->hv_guest_os_id[vcpu->plane_level]) + hv->hv_hypercall[vcpu->plane_level] &= + ~HV_X64_MSR_HYPERCALL_ENABLE; break; case HV_X64_MSR_HYPERCALL: { u8 instructions[9]; @@ -1395,10 +1396,10 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, u64 addr; /* if guest os id is not set hypercall should remain disabled */ - if (!hv->hv_guest_os_id) + if (!hv->hv_guest_os_id[vcpu->plane_level]) break; if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) { - hv->hv_hypercall = data; + hv->hv_hypercall[vcpu->plane_level] = data; break; } @@ -1427,7 +1428,7 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, addr = data & HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK; if (kvm_vcpu_write_guest(vcpu, addr, instructions, i)) return 1; - hv->hv_hypercall = data; + hv->hv_hypercall[vcpu->plane_level] = data; break; } case HV_X64_MSR_REFERENCE_TSC: @@ -1640,10 +1641,10 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, switch (msr) { case HV_X64_MSR_GUEST_OS_ID: - data = hv->hv_guest_os_id; + data = hv->hv_guest_os_id[vcpu->plane_level]; break; case HV_X64_MSR_HYPERCALL: - data = hv->hv_hypercall; + data = hv->hv_hypercall[vcpu->plane_level]; break; case HV_X64_MSR_TIME_REF_COUNT: data = get_time_ref_counter(kvm); diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 6301f79fcbae..0593fe4333d3 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -97,7 +97,8 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) { - return vcpu->arch.hyperv_enabled && to_kvm_hv(vcpu->kvm)->hv_guest_os_id; + return vcpu->arch.hyperv_enabled && + to_kvm_hv(vcpu->kvm)->hv_guest_os_id[vcpu->plane_level]; } int kvm_hv_hypercall(struct kvm_vcpu *vcpu); -- 2.50.1

