diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-02-23 06:51:19 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-03-08 06:33:38 -0500 |
commit | 6bb69c9b69c315200ddc2bc79aee14c0184cf5b2 (patch) | |
tree | c7023298fd90cabf3532b45afa31c03e71fdd604 | |
parent | 50c9e6f3a69dfa458ecb671bcbd11e2eea6db0c1 (diff) |
KVM: MMU: simplify last_pte_bitmap
Branch-free code is fun and everybody knows how much Avi loves it,
but last_pte_bitmap takes it a bit to the extreme. Since the code
is simply doing a range check, like
(level == 1 ||
((gpte & PT_PAGE_SIZE_MASK) && level < N)
we can make it branch-free without storing the entire truth table;
it is enough to cache N.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 8 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 50 |
2 files changed, 28 insertions, 30 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1c3e390993a2..d110dc44d6c2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -347,12 +347,8 @@ struct kvm_mmu { | |||
347 | 347 | ||
348 | struct rsvd_bits_validate guest_rsvd_check; | 348 | struct rsvd_bits_validate guest_rsvd_check; |
349 | 349 | ||
350 | /* | 350 | /* Can have large pages at levels 2..last_nonleaf_level-1. */ |
351 | * Bitmap: bit set = last pte in walk | 351 | u8 last_nonleaf_level; |
352 | * index[0:1]: level (zero-based) | ||
353 | * index[2]: pte.ps | ||
354 | */ | ||
355 | u8 last_pte_bitmap; | ||
356 | 352 | ||
357 | bool nx; | 353 | bool nx; |
358 | 354 | ||
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 754d2c4f6f99..2463de0b935c 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -3632,13 +3632,24 @@ static bool sync_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn, | |||
3632 | return false; | 3632 | return false; |
3633 | } | 3633 | } |
3634 | 3634 | ||
3635 | static inline bool is_last_gpte(struct kvm_mmu *mmu, unsigned level, unsigned gpte) | 3635 | static inline bool is_last_gpte(struct kvm_mmu *mmu, |
3636 | unsigned level, unsigned gpte) | ||
3636 | { | 3637 | { |
3637 | unsigned index; | 3638 | /* |
3639 | * PT_PAGE_TABLE_LEVEL always terminates. The RHS has bit 7 set | ||
3640 | * iff level <= PT_PAGE_TABLE_LEVEL, which for our purpose means | ||
3641 | * level == PT_PAGE_TABLE_LEVEL; set PT_PAGE_SIZE_MASK in gpte then. | ||
3642 | */ | ||
3643 | gpte |= level - PT_PAGE_TABLE_LEVEL - 1; | ||
3638 | 3644 | ||
3639 | index = level - 1; | 3645 | /* |
3640 | index |= (gpte & PT_PAGE_SIZE_MASK) >> (PT_PAGE_SIZE_SHIFT - 2); | 3646 | * The RHS has bit 7 set iff level < mmu->last_nonleaf_level. |
3641 | return mmu->last_pte_bitmap & (1 << index); | 3647 | * If it is clear, there are no large pages at this level, so clear |
3648 | * PT_PAGE_SIZE_MASK in gpte if that is the case. | ||
3649 | */ | ||
3650 | gpte &= level - mmu->last_nonleaf_level; | ||
3651 | |||
3652 | return gpte & PT_PAGE_SIZE_MASK; | ||
3642 | } | 3653 | } |
3643 | 3654 | ||
3644 | #define PTTYPE_EPT 18 /* arbitrary */ | 3655 | #define PTTYPE_EPT 18 /* arbitrary */ |
@@ -3910,22 +3921,13 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu, | |||
3910 | } | 3921 | } |
3911 | } | 3922 | } |
3912 | 3923 | ||
3913 | static void update_last_pte_bitmap(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu) | 3924 | static void update_last_nonleaf_level(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu) |
3914 | { | 3925 | { |
3915 | u8 map; | 3926 | unsigned root_level = mmu->root_level; |
3916 | unsigned level, root_level = mmu->root_level; | 3927 | |
3917 | const unsigned ps_set_index = 1 << 2; /* bit 2 of index: ps */ | 3928 | mmu->last_nonleaf_level = root_level; |
3918 | 3929 | if (root_level == PT32_ROOT_LEVEL && is_pse(vcpu)) | |
3919 | if (root_level == PT32E_ROOT_LEVEL) | 3930 | mmu->last_nonleaf_level++; |
3920 | --root_level; | ||
3921 | /* PT_PAGE_TABLE_LEVEL always terminates */ | ||
3922 | map = 1 | (1 << ps_set_index); | ||
3923 | for (level = PT_DIRECTORY_LEVEL; level <= root_level; ++level) { | ||
3924 | if (level <= PT_PDPE_LEVEL | ||
3925 | && (mmu->root_level >= PT32E_ROOT_LEVEL || is_pse(vcpu))) | ||
3926 | map |= 1 << (ps_set_index | (level - 1)); | ||
3927 | } | ||
3928 | mmu->last_pte_bitmap = map; | ||
3929 | } | 3931 | } |
3930 | 3932 | ||
3931 | static void paging64_init_context_common(struct kvm_vcpu *vcpu, | 3933 | static void paging64_init_context_common(struct kvm_vcpu *vcpu, |
@@ -3937,7 +3939,7 @@ static void paging64_init_context_common(struct kvm_vcpu *vcpu, | |||
3937 | 3939 | ||
3938 | reset_rsvds_bits_mask(vcpu, context); | 3940 | reset_rsvds_bits_mask(vcpu, context); |
3939 | update_permission_bitmask(vcpu, context, false); | 3941 | update_permission_bitmask(vcpu, context, false); |
3940 | update_last_pte_bitmap(vcpu, context); | 3942 | update_last_nonleaf_level(vcpu, context); |
3941 | 3943 | ||
3942 | MMU_WARN_ON(!is_pae(vcpu)); | 3944 | MMU_WARN_ON(!is_pae(vcpu)); |
3943 | context->page_fault = paging64_page_fault; | 3945 | context->page_fault = paging64_page_fault; |
@@ -3964,7 +3966,7 @@ static void paging32_init_context(struct kvm_vcpu *vcpu, | |||
3964 | 3966 | ||
3965 | reset_rsvds_bits_mask(vcpu, context); | 3967 | reset_rsvds_bits_mask(vcpu, context); |
3966 | update_permission_bitmask(vcpu, context, false); | 3968 | update_permission_bitmask(vcpu, context, false); |
3967 | update_last_pte_bitmap(vcpu, context); | 3969 | update_last_nonleaf_level(vcpu, context); |
3968 | 3970 | ||
3969 | context->page_fault = paging32_page_fault; | 3971 | context->page_fault = paging32_page_fault; |
3970 | context->gva_to_gpa = paging32_gva_to_gpa; | 3972 | context->gva_to_gpa = paging32_gva_to_gpa; |
@@ -4022,7 +4024,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) | |||
4022 | } | 4024 | } |
4023 | 4025 | ||
4024 | update_permission_bitmask(vcpu, context, false); | 4026 | update_permission_bitmask(vcpu, context, false); |
4025 | update_last_pte_bitmap(vcpu, context); | 4027 | update_last_nonleaf_level(vcpu, context); |
4026 | reset_tdp_shadow_zero_bits_mask(vcpu, context); | 4028 | reset_tdp_shadow_zero_bits_mask(vcpu, context); |
4027 | } | 4029 | } |
4028 | 4030 | ||
@@ -4128,7 +4130,7 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu) | |||
4128 | } | 4130 | } |
4129 | 4131 | ||
4130 | update_permission_bitmask(vcpu, g_context, false); | 4132 | update_permission_bitmask(vcpu, g_context, false); |
4131 | update_last_pte_bitmap(vcpu, g_context); | 4133 | update_last_nonleaf_level(vcpu, g_context); |
4132 | } | 4134 | } |
4133 | 4135 | ||
4134 | static void init_kvm_mmu(struct kvm_vcpu *vcpu) | 4136 | static void init_kvm_mmu(struct kvm_vcpu *vcpu) |