| From f71a53d1180d5ecc346f0c6a23191d837fe2871b Mon Sep 17 00:00:00 2001 |
| From: Sean Christopherson <seanjc@google.com> |
| Date: Tue, 22 Jun 2021 10:56:50 -0700 |
| Subject: Revert "KVM: x86/mmu: Drop kvm_mmu_extended_role.cr4_la57 hack" |
| |
| From: Sean Christopherson <seanjc@google.com> |
| |
| commit f71a53d1180d5ecc346f0c6a23191d837fe2871b upstream. |
| |
| Restore CR4.LA57 to the mmu_role to fix an amusing edge case with nested |
| virtualization. When KVM (L0) is using TDP, CR4.LA57 is not reflected in |
| mmu_role.base.level because that tracks the shadow root level, i.e. TDP |
| level. Normally, this is not an issue because LA57 can't be toggled |
| while long mode is active, i.e. the guest has to first disable paging, |
| then toggle LA57, then re-enable paging, thus ensuring an MMU |
| reinitialization. |
| |
| But if L1 is crafty, it can load a new CR4 on VM-Exit and toggle LA57 |
| without having to bounce through an unpaged section. L1 can also load a |
| new CR3 on exit, i.e. it doesn't even need to play crazy paging games, a |
| single entry PML5 is sufficient. Such shenanigans are only problematic |
| if L0 and L1 use TDP, otherwise L1 and L2 share an MMU that gets |
| reinitialized on nested VM-Enter/VM-Exit due to mmu_role.base.guest_mode. |
| |
| Note, in the L2 case with nested TDP, even though L1 can switch between |
| L2s with different LA57 settings, thus bypassing the paging requirement, |
| in that case KVM's nested_mmu will track LA57 in base.level. |
| |
| This reverts commit 8053f924cad30bf9f9a24e02b6c8ddfabf5202ea. |
| |
| Fixes: 8053f924cad3 ("KVM: x86/mmu: Drop kvm_mmu_extended_role.cr4_la57 hack") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Sean Christopherson <seanjc@google.com> |
| Message-Id: <20210622175739.3610207-6-seanjc@google.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/kvm_host.h | 1 + |
| arch/x86/kvm/mmu/mmu.c | 1 + |
| 2 files changed, 2 insertions(+) |
| |
| --- a/arch/x86/include/asm/kvm_host.h |
| +++ b/arch/x86/include/asm/kvm_host.h |
| @@ -320,6 +320,7 @@ union kvm_mmu_extended_role { |
| unsigned int cr4_pke:1; |
| unsigned int cr4_smap:1; |
| unsigned int cr4_smep:1; |
| + unsigned int cr4_la57:1; |
| unsigned int maxphyaddr:6; |
| }; |
| }; |
| --- a/arch/x86/kvm/mmu/mmu.c |
| +++ b/arch/x86/kvm/mmu/mmu.c |
| @@ -4476,6 +4476,7 @@ static union kvm_mmu_extended_role kvm_c |
| ext.cr4_smap = !!kvm_read_cr4_bits(vcpu, X86_CR4_SMAP); |
| ext.cr4_pse = !!is_pse(vcpu); |
| ext.cr4_pke = !!kvm_read_cr4_bits(vcpu, X86_CR4_PKE); |
| + ext.cr4_la57 = !!kvm_read_cr4_bits(vcpu, X86_CR4_LA57); |
| ext.maxphyaddr = cpuid_maxphyaddr(vcpu); |
| |
| ext.valid = 1; |