Skip to content

Commit 6a39bbc

Browse files
Xiao Guangrongbonzini
authored andcommitted
KVM: MTRR: do not map huge page for non-consistent range
Based on Intel's SDM, mapping huge page which do not have consistent memory cache for each 4k page will cause undefined behavior In order to avoiding this kind of undefined behavior, we force to use 4k pages under this case Signed-off-by: Xiao Guangrong <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent fa61213 commit 6a39bbc

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

arch/x86/kvm/mmu.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3446,6 +3446,16 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
34463446
return false;
34473447
}
34483448

3449+
static bool
3450+
check_hugepage_cache_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
3451+
{
3452+
int page_num = KVM_PAGES_PER_HPAGE(level);
3453+
3454+
gfn &= ~(page_num - 1);
3455+
3456+
return kvm_mtrr_check_gfn_range_consistency(vcpu, gfn, page_num);
3457+
}
3458+
34493459
static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
34503460
bool prefault)
34513461
{
@@ -3471,9 +3481,17 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
34713481
if (r)
34723482
return r;
34733483

3474-
force_pt_level = mapping_level_dirty_bitmap(vcpu, gfn);
3484+
if (mapping_level_dirty_bitmap(vcpu, gfn) ||
3485+
!check_hugepage_cache_consistency(vcpu, gfn, PT_DIRECTORY_LEVEL))
3486+
force_pt_level = 1;
3487+
else
3488+
force_pt_level = 0;
3489+
34753490
if (likely(!force_pt_level)) {
34763491
level = mapping_level(vcpu, gfn);
3492+
if (level > PT_DIRECTORY_LEVEL &&
3493+
!check_hugepage_cache_consistency(vcpu, gfn, level))
3494+
level = PT_DIRECTORY_LEVEL;
34773495
gfn &= ~(KVM_PAGES_PER_HPAGE(level) - 1);
34783496
} else
34793497
level = PT_PAGE_TABLE_LEVEL;

arch/x86/kvm/mtrr.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,3 +668,32 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
668668
return type;
669669
}
670670
EXPORT_SYMBOL_GPL(kvm_mtrr_get_guest_memory_type);
671+
672+
bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
673+
int page_num)
674+
{
675+
struct kvm_mtrr *mtrr_state = &vcpu->arch.mtrr_state;
676+
struct mtrr_iter iter;
677+
u64 start, end;
678+
int type = -1;
679+
680+
start = gfn_to_gpa(gfn);
681+
end = gfn_to_gpa(gfn + page_num);
682+
mtrr_for_each_mem_type(&iter, mtrr_state, start, end) {
683+
if (type == -1) {
684+
type = iter.mem_type;
685+
continue;
686+
}
687+
688+
if (type != iter.mem_type)
689+
return false;
690+
}
691+
692+
if (!iter.partial_map)
693+
return true;
694+
695+
if (type == -1)
696+
return true;
697+
698+
return type == mtrr_default_type(mtrr_state);
699+
}

arch/x86/kvm/x86.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
167167
bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data);
168168
int kvm_mtrr_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data);
169169
int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
170+
bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
171+
int page_num);
170172

171173
#define KVM_SUPPORTED_XCR0 (XSTATE_FP | XSTATE_SSE | XSTATE_YMM \
172174
| XSTATE_BNDREGS | XSTATE_BNDCSR \

0 commit comments

Comments
 (0)