Re: guest PTE write emulation

Dong, Eddie
2007-05-30T11:40:49Z

Avi Kivity wrote:
> On a pte update, npte will always be 1. On a pde update, we won't do
> anything in mmu_pte_write_new_pte because it doesn't handle
> pdes. If we
> extend it to handle pdes, then we need either to modify the
> new gpde or
> to have the update take the quadrant into account.

Agree, so we either just skip npte=2 branch or polish it.
How about following changes?

diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index c85c664..37a7dc5 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -1156,7 +1156,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu,
gpa_t gpa,
struct hlist_node *node, *n;
struct hlist_head *bucket;
unsigned index;
- u64 *spte;
+ u64 *spte, gpte[2];
unsigned offset = offset_in_page(gpa);
unsigned pte_size;
unsigned page_offset;
@@ -1164,7 +1164,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu,
gpa_t gpa,
unsigned quadrant;
int level;
int flooded = 0;
- int npte;
+ int npte, i;

pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
if (gfn == vcpu->last_pt_write_gfn) {
@@ -1202,6 +1202,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu,
gpa_t gpa,
page_offset = offset;
level = page->role.level;
npte = 1;
+ gpte[0] = *(long*)new;
if (page->role.glevels == PT32_ROOT_LEVEL) {
page_offset <<= 1; /* 32->64 */
/*
@@ -1209,10 +1210,16 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu,
gpa_t gpa,
* only 2MB. So we need to double the offset
again
* and zap two pdes instead of one.
*/
- if (level == PT32_ROOT_LEVEL) {
+ if ((level == PT_DIRECTORY_LEVEL) &&
+ (vcpu->cr4 & CR4_PSE_MASK) &&
+ (gpte[0] & PT_PAGE_SIZE_MASK)) {
page_offset &= ~7; /* kill rounding
error */
page_offset <<= 1;
npte = 2;
+ gpte[1] = gpte[0];
+ gpte[1] += 1 << 21;
}
quadrant = page_offset >> PAGE_SHIFT;
page_offset &= ~PAGE_MASK;
@@ -1220,9 +1227,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu,
gpa_t gpa,
continue;
}
spte = &page->spt[page_offset / sizeof(*spte)];
- while (npte--) {
+ for (i=0; i < npte; i++) {
mmu_pte_write_zap_pte(vcpu, page, spte);
- mmu_pte_write_new_pte(vcpu, page, spte, new,
bytes);
+ mmu_pte_write_new_pte(vcpu, page, spte,
&gpte[i], bytes);
++spte;
}
}