Skip to contentSkip to conversation

VMX EPT misconfigurtion handler

PATCH In review Marcelo Tosatti 3 participants 32 messages Jun 9, 2009 – Jun 14, 2009

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover VMX EPT misconfigurtion handler

Quoted 1 line

From the Intel docs:

An EPT misconfiguration occurs when, in the course of translation a guest-physical address, the logical processor encounters an EPT paging-structure entry that contains an unsupported value.

Handle this event and print useful information for diagnostics.

#1 lore raw

PATCH 1/5 KVM: VMX: more MSR_IA32_VMX_EPT_VPID_CAP capability bits

Required for EPT misconfiguration handler.

arch/x86/include/asm/vmx.h +7 -0
Index: kvm/arch/x86/include/asm/vmx.h
===================================================================
@@ -351,9 +351,16 @@ enum vmcs_field {
 #define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_EPT_EXTENT_CONTEXT			1
 #define VMX_EPT_EXTENT_GLOBAL			2
+
+#define VMX_EPT_EXECUTE_ONLY_BIT		(1ull)
+#define VMX_EPT_PAGE_WALK_4_BIT			(1ull << 6)
+#define VMX_EPTP_UC_BIT				(1ull << 8)
+#define VMX_EPTP_WB_BIT				(1ull << 14)
+#define VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
 #define VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
+
 #define VMX_EPT_DEFAULT_GAW			3
 #define VMX_EPT_MAX_GAW				0x4
 #define VMX_EPT_MT_EPTE_SHIFT			3
arch/x86/kvm/vmx.c +20 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -258,6 +258,26 @@ static inline bool cpu_has_vmx_flexprior
 		cpu_has_vmx_virtualize_apic_accesses();
 }
 
+static inline bool cpu_has_vmx_ept_execute_only(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_uncacheable(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_UC_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_writeback(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_WB_BIT);
+}
+
+static inline bool cpu_has_vmx_ept_2m_page(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT);
+}
+
 static inline int cpu_has_vmx_invept_individual_addr(void)
 {
 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
#2 lore raw

PATCH 2/5 KVM: MMU: make for_each_shadow_entry aware of largepages

In reply to Marcelo Tosatti

This way there is no need to add explicit checks in every for_each_shadow_entry user.

arch/x86/kvm/mmu.c +5 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
 	if (iterator->level < PT_PAGE_TABLE_LEVEL)
 		return false;
+
+	if (iterator->level == PT_PAGE_TABLE_LEVEL)
+		if (is_large_pte(*iterator->sptep))
+			return false;
+
 	iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level);
 	iterator->sptep	= ((u64 *)__va(iterator->shadow_addr)) + iterator->index;
 	return true;
#3 lore raw

Re: [patch 2/5] KVM: MMU: make for_each_shadow_entry aware of largepages

Quoted 10 lines · Marcelo Tosatti

This way there is no need to add explicit checks in every for_each_shadow_entry user.

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c static bool shadow_walk_okay(struct kvm_ · line 1281

Quoted 9 lines
arch/x86/kvm/mmu.c +4 -0
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
 	if (iterator->level < PT_PAGE_TABLE_LEVEL)
 		return false;
+
+	if (iterator->level == PT_PAGE_TABLE_LEVEL)
+		if (is_large_pte(*iterator->sptep))
+			return false;
 
 

s/==/>/?

Signature · 1 line
error compiling committee.c: too many arguments to function
#4 lore raw

Re: [patch 2/5] KVM: MMU: make for_each_shadow_entry aware of largepages

Quoted 6 lines · Avi Kivity
Quoted 5 lines · Marcelo Tosatti

This way there is no need to add explicit checks in every for_each_shadow_entry user.

Quoted 16 lines
Quoted 5 lines

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c static bool shadow_walk_okay(struct kvm_ · line 1281

Quoted 9 lines
arch/x86/kvm/mmu.c +4 -0
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
     if (iterator->level < PT_PAGE_TABLE_LEVEL)
         return false;
+
+    if (iterator->level == PT_PAGE_TABLE_LEVEL)
+        if (is_large_pte(*iterator->sptep))
+            return false;
 
 

s/==/>/?

Ah, it's actually fine. But changing == to >= will make it 1GBpage-ready.

Signature · 1 line
error compiling committee.c: too many arguments to function
#5 lore raw

Re: [patch 2/5] KVM: MMU: make for_each_shadow_entry aware of largepages

Quoted 24 lines · Avi Kivity
Quoted 6 lines · Avi Kivity
Quoted 5 lines · Marcelo Tosatti

This way there is no need to add explicit checks in every for_each_shadow_entry user.

Quoted 16 lines
Quoted 5 lines

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c static bool shadow_walk_okay(struct kvm_ · line 1281

Quoted 9 lines
arch/x86/kvm/mmu.c +4 -0
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
     if (iterator->level < PT_PAGE_TABLE_LEVEL)
         return false;
+
+    if (iterator->level == PT_PAGE_TABLE_LEVEL)
+        if (is_large_pte(*iterator->sptep))
+            return false;
 
 

s/==/>/?

Quoted 1 line

Ah, it's actually fine. But changing == to >= will make it 1GBpage-ready.

Humpf, better check level explicitly before interpreting bit 7, so lets skip this for 1GB pages.

#6 lore raw

Re: [patch 2/5] KVM: MMU: make for_each_shadow_entry aware of largepages

Quoted 14 lines · Marcelo Tosatti
Quoted 14 lines
Quoted 14 lines

arch/x86/kvm/mmu.c static bool shadow_walk_okay(struct kvm_ · line 1282

Quoted 11 lines
arch/x86/kvm/mmu.c +4 -0
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
     if (iterator->level < PT_PAGE_TABLE_LEVEL)
         return false;
+
+    if (iterator->level == PT_PAGE_TABLE_LEVEL)
+        if (is_large_pte(*iterator->sptep))
+            return false;
 
 
 

s/==/>/?

Quoted 6 lines
Quoted 2 lines

Ah, it's actually fine. But changing == to >= will make it 1GBpage-ready.

Humpf, better check level explicitly before interpreting bit 7, so lets skip this for 1GB pages.

Okay. But I'm rewriting shadow_walk_* afterwards.

Signature · 1 line
error compiling committee.c: too many arguments to function
#7 lore raw

PATCH 3/5 KVM: MMU: add kvm_mmu_shadow_walk helper

In reply to Marcelo Tosatti

Required by EPT misconfiguration handler.

arch/x86/kvm/mmu.c +20 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -3013,6 +3013,26 @@ out:
 	return r;
 }
 
+void kvm_mmu_shadow_walk(struct kvm_vcpu *vcpu, u64 addr,
+			 struct mmu_shadow_walk *walk)
+{
+	struct kvm_shadow_walk_iterator iterator;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		int err;
+
+		err = walk->fn(vcpu, iterator.sptep, iterator.level, walk);
+		if (err)
+			break;
+
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
+}
+EXPORT_SYMBOL(kvm_mmu_shadow_walk);
+
 #ifdef AUDIT
 
 static const char *audit_msg;
arch/x86/kvm/mmu.h +8 -0
Index: kvm/arch/x86/kvm/mmu.h
===================================================================
@@ -37,6 +37,14 @@
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
+struct mmu_shadow_walk {
+	int (*fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level,
+		   struct mmu_shadow_walk *walk);
+};
+
+void kvm_mmu_shadow_walk(struct kvm_vcpu *vcpu, u64 addr,
+			 struct mmu_shadow_walk *walk);
+
 static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
 	if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
#8 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 23 lines · Marcelo Tosatti

Required by EPT misconfiguration handler.

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c +11 -0
@@ -3013,6 +3013,26 @@ out:
 	return r;
 }
 
+void kvm_mmu_shadow_walk(struct kvm_vcpu *vcpu, u64 addr,
+			 struct mmu_shadow_walk *walk)
+{
+	struct kvm_shadow_walk_iterator iterator;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		int err;
+
+		err = walk->fn(vcpu, iterator.sptep, iterator.level, walk);
+		if (err)

arch/x86/kvm/mmu.c out: · line 3036

Quoted 10 lines
arch/x86/kvm/mmu.c +9 -0
+			break;
+
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
+}
+EXPORT_SYMBOL(kvm_mmu_shadow_walk);
+
 

Isn't it simpler to invoke for_each_shadow_entry(), instead of defining a callback and calling it?

We had those callbacks once, then switched to for_each.

Signature · 1 line
error compiling committee.c: too many arguments to function
#9 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 37 lines · Avi Kivity
Quoted 22 lines · Marcelo Tosatti

Required by EPT misconfiguration handler.

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c +10 -0
@@ -3013,6 +3013,26 @@ out:
 	return r;
 }
 +void kvm_mmu_shadow_walk(struct kvm_vcpu *vcpu, u64 addr,
+			 struct mmu_shadow_walk *walk)
+{
+	struct kvm_shadow_walk_iterator iterator;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		int err;
+
+		err = walk->fn(vcpu, iterator.sptep, iterator.level, walk);
+		if (err)

arch/x86/kvm/mmu.c out: · line 3035

Quoted 10 lines
arch/x86/kvm/mmu.c +9 -0
+			break;
+
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
+}
+EXPORT_SYMBOL(kvm_mmu_shadow_walk);
+
 

Isn't it simpler to invoke for_each_shadow_entry(), instead of defining a callback and calling it?

Quoted 1 line

We had those callbacks once, then switched to for_each.

The point is its exported to use in a external module (kvm-intel.ko), so you hide the details (such as locking) in the kvm_mmu_shadow_walk helper. Let me know how do you prefer this to be.

#10 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 9 lines · Marcelo Tosatti
Quoted 4 lines

Isn't it simpler to invoke for_each_shadow_entry(), instead of defining a callback and calling it?

We had those callbacks once, then switched to for_each.

The point is its exported to use in a external module (kvm-intel.ko), so you hide the details (such as locking) in the kvm_mmu_shadow_walk helper. Let me know how do you prefer this to be.

Ah, you're right.

I don't think it's worthwhile to add all this just for debugging. You can add a function that dumps the spte chain as well as the features MSR, and we can decode it by hand when we see it. Disadvantage is more work for us when we hit the bug, but at least that function is reusable in other contexts.

Signature · 1 line
error compiling committee.c: too many arguments to function
#11 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 12 lines · Avi Kivity
Quoted 10 lines · Marcelo Tosatti
Quoted 5 lines

Isn't it simpler to invoke for_each_shadow_entry(), instead of defining a callback and calling it?

We had those callbacks once, then switched to for_each.

The point is its exported to use in a external module (kvm-intel.ko), so you hide the details (such as locking) in the kvm_mmu_shadow_walk helper. Let me know how do you prefer this to be.

Quoted 7 lines

Ah, you're right.

I don't think it's worthwhile to add all this just for debugging. You can add a function that dumps the spte chain as well as the features MSR, and we can decode it by hand when we see it. Disadvantage is more work for us when we hit the bug, but at least that function is reusable in other contexts.

The problem is if someone hits the bug who has no possibility of reporting the printks. Nice thing about the WARN_ON's there is you can look up kerneloops.org, match the line number to the kernel version, and narrow down what bits are wrong (you still need reporter to send contents of dmesg for full spte value).

Also the bit-by-bit validity checks (the inspect_spte function in vmx.c) can be used in the mmu audit code (thats the reason for print=0 in the callback parameters), so it is reusable in other contexes.

What you dislike is hardcoding the bits checked in C code? Don't worry about the level stuff, will be handled next.

#12 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 11 lines · Marcelo Tosatti
Quoted 4 lines

Ah, you're right.

I don't think it's worthwhile to add all this just for debugging. You can add a function that dumps the spte chain as well as the features MSR, and we can decode it by hand when we see it. Disadvantage is more work for us when we hit the bug, but at least that function is reusable in other contexts.

The problem is if someone hits the bug who has no possibility of reporting the printks. Nice thing about the WARN_ON's there is you can look up kerneloops.org, match the line number to the kernel version, and narrow down what bits are wrong (you still need reporter to send contents of dmesg for full spte value).

Well, we can KERN_WARNING instead of KERN_DEBUG in that printout.

Quoted 7 lines

Also the bit-by-bit validity checks (the inspect_spte function in vmx.c) can be used in the mmu audit code (thats the reason for print=0 in the callback parameters), so it is reusable in other contexes.

What you dislike is hardcoding the bits checked in C code? Don't worry about the level stuff, will be handled next.

I just don't want to introduce yet another function-callback pair for such a small thing. No objection to the code itself.

Printing out the spte hierarchy seems a good idea in other bug contexts, so at least that function is reusable.

Signature · 1 line
error compiling committee.c: too many arguments to function
#13 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_shadow_walk helper

Quoted 5 lines · Avi Kivity

I just don't want to introduce yet another function-callback pair for such a small thing. No objection to the code itself.

Printing out the spte hierarchy seems a good idea in other bug contexts, so at least that function is reusable.

Here's one that preserves all information but is simple to use:

kvm_mmu_get_spte_hierarchy(vcpu, gva, int *nr_sptes, u64 sptes[4])

So you can later do detailed checks on the sptes, but it doesn't expose yet another generic walker.

Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
#14 lore raw

PATCH 1/5 KVM: VMX: more MSR_IA32_VMX_EPT_VPID_CAP capability bits

Required for EPT misconfiguration handler.

arch/x86/include/asm/vmx.h +7 -0
Index: kvm/arch/x86/include/asm/vmx.h
===================================================================
@@ -352,9 +352,16 @@ enum vmcs_field {
 #define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_EPT_EXTENT_CONTEXT			1
 #define VMX_EPT_EXTENT_GLOBAL			2
+
+#define VMX_EPT_EXECUTE_ONLY_BIT		(1ull)
+#define VMX_EPT_PAGE_WALK_4_BIT			(1ull << 6)
+#define VMX_EPTP_UC_BIT				(1ull << 8)
+#define VMX_EPTP_WB_BIT				(1ull << 14)
+#define VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
 #define VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
+
 #define VMX_EPT_DEFAULT_GAW			3
 #define VMX_EPT_MAX_GAW				0x4
 #define VMX_EPT_MT_EPTE_SHIFT			3
arch/x86/kvm/vmx.c +20 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -270,6 +270,26 @@ static inline bool cpu_has_vmx_flexprior
 		cpu_has_vmx_virtualize_apic_accesses();
 }
 
+static inline bool cpu_has_vmx_ept_execute_only(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_uncacheable(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_UC_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_writeback(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_WB_BIT);
+}
+
+static inline bool cpu_has_vmx_ept_2m_page(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT);
+}
+
 static inline int cpu_has_vmx_invept_individual_addr(void)
 {
 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
#15 lore raw

PATCH 2/5 KVM: MMU: make for_each_shadow_entry aware of largepages

In reply to Avi Kivity

This way there is no need to add explicit checks in every for_each_shadow_entry user.

arch/x86/kvm/mmu.c +5 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
 	if (iterator->level < PT_PAGE_TABLE_LEVEL)
 		return false;
+
+	if (iterator->level == PT_PAGE_TABLE_LEVEL)
+		if (is_large_pte(*iterator->sptep))
+			return false;
+
 	iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level);
 	iterator->sptep	= ((u64 *)__va(iterator->shadow_addr)) + iterator->index;
 	return true;
#16 lore raw

PATCH 3/5 KVM: MMU: add kvm_mmu_get_spte_hierarchy helper

In reply to Avi Kivity

Required by EPT misconfiguration handler.

arch/x86/kvm/mmu.c +18 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -3013,6 +3013,24 @@ out:
 	return r;
 }
 
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes[4])
+{
+	struct kvm_shadow_walk_iterator iterator;
+	int nr_sptes = 0;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		sptes[iterator.level-1] = iterator.sptep;
+		nr_sptes++;
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
+
+	return nr_sptes;
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
+
 #ifdef AUDIT
 
 static const char *audit_msg;
arch/x86/kvm/mmu.h +2 -0
Index: kvm/arch/x86/kvm/mmu.h
===================================================================
@@ -37,6 +37,8 @@
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes[4]);
+
 static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
 	if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
#17 lore raw

Re: [patch 3/5] KVM: MMU: add kvm_mmu_get_spte_hierarchy helper

Quoted 11 lines · Marcelo Tosatti

Required by EPT misconfiguration handler.

Index: kvm/arch/x86/kvm/mmu.c
===================================================================

arch/x86/kvm/mmu.c +0 -0
@@ -3013,6 +3013,24 @@ out:
 	return r;
 }

arch/x86/kvm/mmu.c out: · line 3024

Quoted 10 lines
arch/x86/kvm/mmu.c +8 -0
 
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes[4])
+{
+	struct kvm_shadow_walk_iterator iterator;
+	int nr_sptes = 0;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		sptes[iterator.level-1] = iterator.sptep;
 

Returning a pointer...

arch/x86/kvm/mmu.c out: · line 3035

Quoted 6 lines
arch/x86/kvm/mmu.c +5 -0
+		nr_sptes++;
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
 

... and unlocking the lock that protects it.

True, this is called in extreme cases, but I think you can dereference the pointer in the function just as easily.

Signature · 1 line
error compiling committee.c: too many arguments to function
Applied
#19 lore raw

Re: [patch 0/5] VMX EPT misconfiguration handler v3

Quoted 4 lines · Marcelo Tosatti

Addressing comments.

Applied all, thanks.

Signature · 1 line
error compiling committee.c: too many arguments to function
#20 lore raw

PATCH 1/5 KVM: VMX: more MSR_IA32_VMX_EPT_VPID_CAP capability bits

In reply to Avi Kivity

Required for EPT misconfiguration handler.

arch/x86/include/asm/vmx.h +7 -0
Index: kvm/arch/x86/include/asm/vmx.h
===================================================================
@@ -352,9 +352,16 @@ enum vmcs_field {
 #define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_EPT_EXTENT_CONTEXT			1
 #define VMX_EPT_EXTENT_GLOBAL			2
+
+#define VMX_EPT_EXECUTE_ONLY_BIT		(1ull)
+#define VMX_EPT_PAGE_WALK_4_BIT			(1ull << 6)
+#define VMX_EPTP_UC_BIT				(1ull << 8)
+#define VMX_EPTP_WB_BIT				(1ull << 14)
+#define VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
 #define VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
+
 #define VMX_EPT_DEFAULT_GAW			3
 #define VMX_EPT_MAX_GAW				0x4
 #define VMX_EPT_MT_EPTE_SHIFT			3
arch/x86/kvm/vmx.c +20 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -270,6 +270,26 @@ static inline bool cpu_has_vmx_flexprior
 		cpu_has_vmx_virtualize_apic_accesses();
 }
 
+static inline bool cpu_has_vmx_ept_execute_only(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_uncacheable(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_UC_BIT);
+}
+
+static inline bool cpu_has_vmx_eptp_writeback(void)
+{
+	return !!(vmx_capability.ept & VMX_EPTP_WB_BIT);
+}
+
+static inline bool cpu_has_vmx_ept_2m_page(void)
+{
+	return !!(vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT);
+}
+
 static inline int cpu_has_vmx_invept_individual_addr(void)
 {
 	return !!(vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT);
#21 lore raw

PATCH 2/5 KVM: MMU: make for_each_shadow_entry aware of largepages

In reply to Avi Kivity

This way there is no need to add explicit checks in every for_each_shadow_entry user.

arch/x86/kvm/mmu.c +5 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -1273,6 +1273,11 @@ static bool shadow_walk_okay(struct kvm_
 {
 	if (iterator->level < PT_PAGE_TABLE_LEVEL)
 		return false;
+
+	if (iterator->level == PT_PAGE_TABLE_LEVEL)
+		if (is_large_pte(*iterator->sptep))
+			return false;
+
 	iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level);
 	iterator->sptep	= ((u64 *)__va(iterator->shadow_addr)) + iterator->index;
 	return true;
#22 lore raw

PATCH 3/5 KVM: MMU: add kvm_mmu_get_spte_hierarchy helper

In reply to Avi Kivity

Required by EPT misconfiguration handler.

arch/x86/kvm/mmu.c +18 -0
Index: kvm/arch/x86/kvm/mmu.c
===================================================================
@@ -3013,6 +3013,24 @@ out:
 	return r;
 }
 
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4])
+{
+	struct kvm_shadow_walk_iterator iterator;
+	int nr_sptes = 0;
+
+	spin_lock(&vcpu->kvm->mmu_lock);
+	for_each_shadow_entry(vcpu, addr, iterator) {
+		sptes[iterator.level-1] = *iterator.sptep;
+		nr_sptes++;
+		if (!is_shadow_present_pte(*iterator.sptep))
+			break;
+	}
+	spin_unlock(&vcpu->kvm->mmu_lock);
+
+	return nr_sptes;
+}
+EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
+
 #ifdef AUDIT
 
 static const char *audit_msg;
arch/x86/kvm/mmu.h +2 -0
Index: kvm/arch/x86/kvm/mmu.h
===================================================================
@@ -37,6 +37,8 @@
 #define PT32_ROOT_LEVEL 2
 #define PT32E_ROOT_LEVEL 3
 
+int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
+
 static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
 	if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
#23 lore raw

PATCH 4/5 KVM: VMX: EPT misconfiguration handler

In reply to Avi Kivity

Handler for EPT misconfiguration which checks for valid state in the shadow pagetables, printing the spte on each level.

The separate WARN_ONs are useful for kerneloops.org.

arch/x86/kvm/vmx.c +85 -1
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -3233,6 +3233,89 @@ static int handle_ept_violation(struct k
 	return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0);
 }
 
+static u64 ept_rsvd_mask(u64 spte, int level)
+{
+	int i;
+	u64 mask = 0;
+
+	for (i = 51; i > boot_cpu_data.x86_phys_bits; i--)
+		mask |= (1ULL << i);
+
+	if (level > 2)
+		/* bits 7:3 reserved */
+		mask |= 0xf8;
+	else if (level == 2) {
+		if (spte & (1ULL << 7))
+			/* 2MB ref, bits 20:12 reserved */
+			mask |= 0x1ff000;
+		else
+			/* bits 6:3 reserved */
+			mask |= 0x78;
+	}
+
+	return mask;
+}
+
+static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 spte,
+				       int level)
+{
+	printk(KERN_ERR "%s: spte 0x%llx level %d\n", __func__, spte, level);
+
+	/* 010b (write-only) */
+	WARN_ON((spte & 0x7) == 0x2);
+
+	/* 110b (write/execute) */
+	WARN_ON((spte & 0x7) == 0x6);
+
+	/* 100b (execute-only) and value not supported by logical processor */
+	if (!cpu_has_vmx_ept_execute_only())
+		WARN_ON((spte & 0x7) == 0x4);
+
+	/* not 000b */
+	if ((spte & 0x7)) {
+		u64 rsvd_bits = spte & ept_rsvd_mask(spte, level);
+
+		if (rsvd_bits != 0) {
+			printk(KERN_ERR "%s: rsvd_bits = 0x%llx\n",
+					 __func__, rsvd_bits);
+			WARN_ON(1);
+		}
+
+		if (level == 1 || (level == 2 && (spte & (1ULL << 7)))) {
+			u64 ept_mem_type = (spte & 0x38) >> 3;
+
+			if (ept_mem_type == 2 || ept_mem_type == 3 ||
+			    ept_mem_type == 7) {
+				printk(KERN_ERR "%s: ept_mem_type=0x%llx\n",
+						__func__, ept_mem_type);
+				WARN_ON(1);
+			}
+		}
+	}
+}
+
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	u64 sptes[4];
+	int nr_sptes, i;
+	gpa_t gpa;
+
+	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+
+	printk(KERN_ERR "EPT: Misconfiguration.\n");
+	printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa);
+
+	nr_sptes = kvm_mmu_get_spte_hierarchy(vcpu, gpa, sptes);
+
+	for (i = PT64_ROOT_LEVEL; i > PT64_ROOT_LEVEL - nr_sptes; --i)
+		ept_misconfig_inspect_spte(vcpu, sptes[i-1], i);
+
+	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+	kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+
+	return 0;
+}
+
 static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	u32 cpu_based_vm_exec_control;
@@ -3303,8 +3386,9 @@ static int (*kvm_vmx_exit_handlers[])(st
 	[EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
 	[EXIT_REASON_WBINVD]                  = handle_wbinvd,
 	[EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
-	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
 	[EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
+	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
+	[EXIT_REASON_EPT_MISCONFIG]           = handle_ept_misconfig,
 };
 
 static const int kvm_vmx_max_exit_handlers =
#24 lore raw

PATCH 5/5 KVM: VMX: conditionally disable 2M pages

In reply to Avi Kivity

Disable usage of 2M pages if VMX_EPT_2MB_PAGE_BIT (bit 16) is clear in MSR_IA32_VMX_EPT_VPID_CAP and EPT is enabled.

arch/x86/kvm/vmx.c +3 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -1393,6 +1393,9 @@ static __init int hardware_setup(void)
 	if (!cpu_has_vmx_tpr_shadow())
 		kvm_x86_ops->update_cr8_intercept = NULL;
 
+	if (enable_ept && !cpu_has_vmx_ept_2m_page())
+		kvm_disable_largepages();
+
 	return alloc_kvm_area();
 }
 
include/linux/kvm_host.h +1 -0
Index: kvm/include/linux/kvm_host.h
===================================================================
@@ -219,6 +219,7 @@ int kvm_arch_set_memory_region(struct kv
 				struct kvm_userspace_memory_region *mem,
 				struct kvm_memory_slot old,
 				int user_alloc);
+void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
virt/kvm/kvm_main.c +12 -2
Index: kvm/virt/kvm/kvm_main.c
===================================================================
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
 
 static bool kvm_rebooting;
 
+static bool largepages_disabled = false;
+
 #ifdef KVM_CAP_DEVICE_ASSIGNMENT
 static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
 						      int assigned_dev_id)
@@ -1171,9 +1173,11 @@ int __kvm_set_memory_region(struct kvm *
 		ugfn = new.userspace_addr >> PAGE_SHIFT;
 		/*
 		 * If the gfn and userspace address are not aligned wrt each
-		 * other, disable large page support for this slot
+		 * other, or if explicitly asked to, disable large page
+		 * support for this slot
 		 */
-		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
+		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1) ||
+		    largepages_disabled)
 			for (i = 0; i < largepages; ++i)
 				new.lpage_info[i].write_count = 1;
 	}
@@ -1286,6 +1290,12 @@ out:
 	return r;
 }
 
+void kvm_disable_largepages(void)
+{
+	largepages_disabled = true;
+}
+EXPORT_SYMBOL_GPL(kvm_disable_largepages);
+
 int is_error_page(struct page *page)
 {
 	return page == bad_page;
#26 lore raw

PATCH 4/5 KVM: VMX: EPT misconfiguration handler

In reply to Avi Kivity

Handler for EPT misconfiguration which checks for valid state in the shadow pagetables, printing the spte on each level.

The separate WARN_ONs are useful for kerneloops.org.

arch/x86/kvm/vmx.c +86 -1
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -3233,6 +3233,90 @@ static int handle_ept_violation(struct k
 	return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0);
 }
 
+static u64 ept_rsvd_mask(u64 *sptep, int level)
+{
+	int i;
+	u64 mask = 0;
+
+	for (i = 51; i > boot_cpu_data.x86_phys_bits; i--)
+		mask |= (1ULL << i);
+
+	if (level > 2)
+		/* bits 7:3 reserved */
+		mask |= 0xf8;
+	else if (level == 2) {
+		if (*sptep & (1ULL << 7))
+			/* 2MB ref, bits 20:12 reserved */
+			mask |= 0x1ff000;
+		else
+			/* bits 6:3 reserved */
+			mask |= 0x78;
+	}
+
+	return mask;
+}
+
+static void ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 *sptep,
+				       int level)
+{
+	printk(KERN_ERR "%s: sptep %p spte 0x%llx level %d\n",
+			__func__, sptep, *sptep, level);
+
+	/* 010b (write-only) */
+	WARN_ON((*sptep & 0x7) == 0x2);
+
+	/* 110b (write/execute) */
+	WARN_ON((*sptep & 0x7) == 0x6);
+
+	/* 100b (execute-only) and value not supported by logical processor */
+	if (!cpu_has_vmx_ept_execute_only())
+		WARN_ON((*sptep & 0x7) == 0x4);
+
+	/* not 000b */
+	if ((*sptep & 0x7)) {
+		u64 rsvd_bits = *sptep & ept_rsvd_mask(sptep, level);
+
+		if (rsvd_bits != 0) {
+			printk(KERN_ERR "%s: rsvd_bits = 0x%llx\n",
+					 __func__, rsvd_bits);
+			WARN_ON(1);
+		}
+
+		if (level == 1 || (level == 2 && (*sptep & (1ULL << 7)))) {
+			u64 ept_mem_type = (*sptep & 0x38) >> 3;
+
+			if (ept_mem_type == 2 || ept_mem_type == 3 ||
+			    ept_mem_type == 7) {
+				printk(KERN_ERR "%s: ept_mem_type=0x%llx\n",
+						__func__, ept_mem_type);
+				WARN_ON(1);
+			}
+		}
+	}
+}
+
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	u64 *sptes[4];
+	int nr_sptes, i;
+	gpa_t gpa;
+
+	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+
+	printk(KERN_ERR "EPT: Misconfiguration.\n");
+	printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa);
+
+	nr_sptes = kvm_mmu_get_spte_hierarchy(vcpu, gpa, sptes);
+
+	for (i = PT64_ROOT_LEVEL; i > PT64_ROOT_LEVEL - nr_sptes; --i)
+		ept_misconfig_inspect_spte(vcpu, sptes[i-1], i);
+
+	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+	kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+
+	return 0;
+}
+
 static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	u32 cpu_based_vm_exec_control;
@@ -3303,8 +3387,9 @@ static int (*kvm_vmx_exit_handlers[])(st
 	[EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
 	[EXIT_REASON_WBINVD]                  = handle_wbinvd,
 	[EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
-	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
 	[EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
+	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
+	[EXIT_REASON_EPT_MISCONFIG]           = handle_ept_misconfig,
 };
 
 static const int kvm_vmx_max_exit_handlers =
#27 lore raw

PATCH 5/5 KVM: VMX: conditionally disable 2M pages

In reply to Avi Kivity

Disable usage of 2M pages if VMX_EPT_2MB_PAGE_BIT (bit 16) is clear in MSR_IA32_VMX_EPT_VPID_CAP and EPT is enabled.

arch/x86/kvm/vmx.c +3 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -1393,6 +1393,9 @@ static __init int hardware_setup(void)
 	if (!cpu_has_vmx_tpr_shadow())
 		kvm_x86_ops->update_cr8_intercept = NULL;
 
+	if (enable_ept && !cpu_has_vmx_ept_2m_page())
+		kvm_disable_largepages();
+
 	return alloc_kvm_area();
 }
 
include/linux/kvm_host.h +1 -0
Index: kvm/include/linux/kvm_host.h
===================================================================
@@ -219,6 +219,7 @@ int kvm_arch_set_memory_region(struct kv
 				struct kvm_userspace_memory_region *mem,
 				struct kvm_memory_slot old,
 				int user_alloc);
+void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
virt/kvm/kvm_main.c +12 -2
Index: kvm/virt/kvm/kvm_main.c
===================================================================
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
 
 static bool kvm_rebooting;
 
+static bool largepages_disabled = false;
+
 #ifdef KVM_CAP_DEVICE_ASSIGNMENT
 static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
 						      int assigned_dev_id)
@@ -1171,9 +1173,11 @@ int __kvm_set_memory_region(struct kvm *
 		ugfn = new.userspace_addr >> PAGE_SHIFT;
 		/*
 		 * If the gfn and userspace address are not aligned wrt each
-		 * other, disable large page support for this slot
+		 * other, or if explicitly asked to, disable large page
+		 * support for this slot
 		 */
-		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
+		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1) ||
+		    largepages_disabled)
 			for (i = 0; i < largepages; ++i)
 				new.lpage_info[i].write_count = 1;
 	}
@@ -1286,6 +1290,12 @@ out:
 	return r;
 }
 
+void kvm_disable_largepages(void)
+{
+	largepages_disabled = true;
+}
+EXPORT_SYMBOL_GPL(kvm_disable_largepages);
+
 int is_error_page(struct page *page)
 {
 	return page == bad_page;
#28 lore raw

PATCH 4/5 KVM: VMX: EPT misconfiguration handler

In reply to Marcelo Tosatti

Handler for EPT misconfiguration which checks for valid state in the shadow pagetables, printing the spte on each level.

The separate WARN_ONs are useful for kerneloops.org.

arch/x86/kvm/vmx.c +96 -1
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -3173,6 +3173,100 @@ static int handle_ept_violation(struct k
 	return kvm_mmu_page_fault(vcpu, gpa & PAGE_MASK, 0);
 }
 
+static u64 ept_rsvd_mask(u64 *sptep, int level)
+{
+	int i;
+	u64 mask = 0;
+
+	for (i = 51; i > boot_cpu_data.x86_phys_bits; i--)
+		mask |= (1ULL << i);
+
+	if (level > 2)
+		/* bits 7:3 reserved */
+		mask |= 0xf8;
+	else if (level == 2) {
+		if (*sptep & (1ULL << 7))
+			/* 2MB ref, bits 20:12 reserved */
+			mask |= 0x1ff000;
+		else
+			/* bits 6:3 reserved */
+			mask |= 0x78;
+	}
+
+	return mask;
+}
+
+struct ept_inspect_spte {
+	int print;
+	struct mmu_shadow_walk walk;
+};
+
+static int ept_misconfig_inspect_spte(struct kvm_vcpu *vcpu, u64 *sptep,
+				      int level,
+				      struct mmu_shadow_walk *walk)
+{
+	struct ept_inspect_spte *iept = container_of(walk,
+					struct ept_inspect_spte, walk);
+
+	if (iept->print)
+		printk(KERN_ERR "%s: sptep %p spte 0x%llx level %d\n",
+				__func__, sptep, *sptep, level);
+
+	/* 010b (write-only) */
+	WARN_ON((*sptep & 0x7) == 0x2);
+
+	/* 110b (write/execute) */
+	WARN_ON((*sptep & 0x7) == 0x6);
+
+	/* 100b (execute-only) and value not supported by logical processor */
+	if (!cpu_has_vmx_ept_execute_only())
+		WARN_ON((*sptep & 0x7) == 0x4);
+
+	/* not 000b */
+	if ((*sptep & 0x7)) {
+		u64 rsvd_bits = *sptep & ept_rsvd_mask(sptep, level);
+
+		if (rsvd_bits != 0) {
+			printk(KERN_ERR "%s: rsvd_bits = 0x%llx\n",
+					 __func__, rsvd_bits);
+			WARN_ON(1);
+		}
+
+		if (level == 1 || (level == 2 && (*sptep & (1ULL << 7)))) {
+			u64 ept_mem_type = (*sptep & 0x38) >> 3;
+
+			if (ept_mem_type == 2 || ept_mem_type == 3 ||
+			    ept_mem_type == 7) {
+				printk(KERN_ERR "%s: ept_mem_type=0x%llx\n",
+						__func__, ept_mem_type);
+				WARN_ON(1);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int handle_ept_misconfig(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+	gpa_t gpa;
+	struct ept_inspect_spte iept = { .print = 1,
+					 .walk.fn =
+					  ept_misconfig_inspect_spte };
+
+	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+
+	printk(KERN_ERR "EPT: Misconfiguration.\n");
+	printk(KERN_ERR "EPT: GPA: 0x%llx\n", gpa);
+
+	kvm_mmu_shadow_walk(vcpu, gpa, &iept.walk);
+
+	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
+	kvm_run->hw.hardware_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+
+	return 0;
+}
+
 static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	u32 cpu_based_vm_exec_control;
@@ -3243,8 +3337,9 @@ static int (*kvm_vmx_exit_handlers[])(st
 	[EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
 	[EXIT_REASON_WBINVD]                  = handle_wbinvd,
 	[EXIT_REASON_TASK_SWITCH]             = handle_task_switch,
-	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
 	[EXIT_REASON_MCE_DURING_VMENTRY]      = handle_machine_check,
+	[EXIT_REASON_EPT_VIOLATION]	      = handle_ept_violation,
+	[EXIT_REASON_EPT_MISCONFIG]           = handle_ept_misconfig,
 };
 
 static const int kvm_vmx_max_exit_handlers =
#29 lore raw

PATCH 5/5 KVM: VMX: conditionally disable 2M pages

In reply to Marcelo Tosatti

Disable usage of 2M pages if VMX_EPT_2MB_PAGE_BIT (bit 16) is clear in MSR_IA32_VMX_EPT_VPID_CAP and EPT is enabled.

arch/x86/kvm/vmx.c +3 -0
Index: kvm/arch/x86/kvm/vmx.c
===================================================================
@@ -1369,6 +1369,9 @@ static __init int hardware_setup(void)
 	if (!cpu_has_vmx_tpr_shadow())
 		kvm_x86_ops->update_cr8_intercept = NULL;
 
+	if (enable_ept && !cpu_has_vmx_ept_2m_page())
+		kvm_disable_largepages();
+
 	return alloc_kvm_area();
 }
 
include/linux/kvm_host.h +1 -0
Index: kvm/include/linux/kvm_host.h
===================================================================
@@ -203,6 +203,7 @@ int kvm_arch_set_memory_region(struct kv
 				struct kvm_userspace_memory_region *mem,
 				struct kvm_memory_slot old,
 				int user_alloc);
+void kvm_disable_largepages(void);
 void kvm_arch_flush_shadow(struct kvm *kvm);
 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn);
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
virt/kvm/kvm_main.c +12 -0
Index: kvm/virt/kvm/kvm_main.c
===================================================================
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
 
 static bool kvm_rebooting;
 
+static bool largepages_disabled = false;
+
 #ifdef KVM_CAP_DEVICE_ASSIGNMENT
 static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
 						      int assigned_dev_id)
@@ -1184,6 +1186,10 @@ int __kvm_set_memory_region(struct kvm *
 		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
 			for (i = 0; i < largepages; ++i)
 				new.lpage_info[i].write_count = 1;
+
+		if (largepages_disabled)
+			for (i = 0; i < largepages; ++i)
+				new.lpage_info[i].write_count = 1;
 	}
 
 	/* Allocate page dirty bitmap if needed */
@@ -1294,6 +1300,12 @@ out:
 	return r;
 }
 
+void kvm_disable_largepages(void)
+{
+	largepages_disabled = true;
+}
+EXPORT_SYMBOL_GPL(kvm_disable_largepages);
+
 int is_error_page(struct page *page)
 {
 	return page == bad_page;
#30 lore raw

Re: [patch 5/5] KVM: VMX: conditionally disable 2M pages

Quoted 17 lines · Marcelo Tosatti

Disable usage of 2M pages if VMX_EPT_2MB_PAGE_BIT (bit 16) is clear in MSR_IA32_VMX_EPT_VPID_CAP and EPT is enabled.

Index: kvm/virt/kvm/kvm_main.c
===================================================================

virt/kvm/kvm_main.c +2 -0
@@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *
 
 static bool kvm_rebooting;
 
+static bool largepages_disabled = false;
+
 #ifdef KVM_CAP_DEVICE_ASSIGNMENT
 static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
 						      int assigned_dev_id)

virt/kvm/kvm_main.c int __kvm_set_memory_region(struct kvm * · line 1194

Quoted 9 lines
virt/kvm/kvm_main.c +4 -0
@@ -1184,6 +1186,10 @@ int __kvm_set_memory_region(struct kvm *
 		if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
 			for (i = 0; i < largepages; ++i)
 				new.lpage_info[i].write_count = 1;
+
+		if (largepages_disabled)
+			for (i = 0; i < largepages; ++i)
+				new.lpage_info[i].write_count = 1;
 	}
 

Please reuse the loop above, it's exactly the same (think of 1GB pages).

Signature · 1 line
error compiling committee.c: too many arguments to function
#31 lore raw
In reply to Marcelo Tosatti
Quoted 7 lines · On Wednesday 10 June 2009 05:30:09 Marcelo Tosatti wrote:
Quoted 1 line

From the Intel docs:

An EPT misconfiguration occurs when, in the course of translation a guest-physical address, the logical processor encounters an EPT paging-structure entry that contains an unsupported value.

Handle this event and print useful information for diagnostics.

Looks fine to me, thanks!

Signature · 2 lines
regards
Yang, Sheng