[patch 06/13] KVM: MMU: global page keeping

Marcelo Tosatti
2008-09-06T19:27:19Z

[-- Attachment #1: kvm-oos-global-keeping --]
[-- Type: text/plain, Size: 3848 bytes --]

Account pages that only have global entries. Such pages need to be
synced on cr4 writes, but not cr3 writes.

Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -778,6 +778,7 @@ static struct kvm_mmu_page *kvm_mmu_allo
ASSERT(is_empty_shadow_page(sp->spt));
sp->slot_bitmap = 0;
sp->multimapped = 0;
+ sp->flags = (1 << KVM_PG_global);
sp->parent_pte = parent_pte;
--vcpu->kvm->arch.n_free_mmu_pages;
return sp;
@@ -1147,18 +1148,22 @@ struct page *gva_to_page(struct kvm_vcpu
static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
unsigned pt_access, unsigned pte_access,
int user_fault, int write_fault, int dirty,
- int *ptwrite, int largepage, gfn_t gfn,
- pfn_t pfn, bool speculative)
+ int global, int *ptwrite, int largepage,
+ gfn_t gfn, pfn_t pfn, bool speculative)
{
u64 spte;
int was_rmapped = 0;
int was_writeble = is_writeble_pte(*shadow_pte);
+ struct kvm_mmu_page *sp = page_header(__pa(shadow_pte));

pgprintk("%s: spte %llx access %x write_fault %d"
" user_fault %d gfn %lx\n",
__func__, *shadow_pte, pt_access,
write_fault, user_fault, gfn);

+ if (!global)
+ kvm_clear_pg_global(sp);
+
if (is_rmap_pte(*shadow_pte)) {
/*
* If we overwrite a PTE page pointer with a 2MB PMD, unlink
@@ -1285,7 +1290,7 @@ static int direct_map_entry(struct kvm_s
if (level == PT_PAGE_TABLE_LEVEL
|| (walk->largepage && level == PT_DIRECTORY_LEVEL)) {
mmu_set_spte(vcpu, sptep, ACC_ALL, ACC_ALL,
- 0, walk->write, 1, &walk->pt_write,
+ 0, walk->write, 1, 0, &walk->pt_write,
walk->largepage, gfn, walk->pfn, false);
++vcpu->stat.pf_fixed;
return 1;
Index: kvm/include/asm-x86/kvm_host.h
===================================================================
--- kvm.orig/include/asm-x86/kvm_host.h
+++ kvm/include/asm-x86/kvm_host.h
@@ -199,6 +199,7 @@ struct kvm_mmu_page {
u64 *parent_pte; /* !multimapped */
struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */
};
+ unsigned long flags;
};

struct kvm_pv_mmu_op_buffer {
@@ -757,4 +758,20 @@ asmlinkage void kvm_handle_fault_on_rebo
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
int kvm_age_hva(struct kvm *kvm, unsigned long hva);

+enum kvm_page_flags {
+ KVM_PG_global,
+};
+
+#define KVMPGFLAG(name) \
+static inline int kvm_page_##name(struct kvm_mmu_page *sp) \
+ { return test_bit(KVM_PG_##name, &sp->flags); } \
+static inline void kvm_set_pg_##name(struct kvm_mmu_page *sp) \
+ { set_bit(KVM_PG_##name, &sp->flags); } \
+static inline void kvm_clear_pg_##name(struct kvm_mmu_page *sp) \
+ { clear_bit(KVM_PG_##name, &sp->flags); } \
+static inline int kvm_test_clear_pg_##name(struct kvm_mmu_page *sp) \
+ { return test_and_clear_bit(KVM_PG_##name, &sp->flags); }
+
+KVMPGFLAG(global);
+
#endif
Index: kvm/arch/x86/kvm/paging_tmpl.h
===================================================================
--- kvm.orig/arch/x86/kvm/paging_tmpl.h
+++ kvm/arch/x86/kvm/paging_tmpl.h
@@ -274,8 +274,8 @@ static void FNAME(update_pte)(struct kvm
return;
kvm_get_pfn(pfn);
mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
- gpte & PT_DIRTY_MASK, NULL, largepage, gpte_to_gfn(gpte),
- pfn, true);
+ gpte & PT_DIRTY_MASK, gpte & PT_GLOBAL_MASK, NULL,
+ largepage, gpte_to_gfn(gpte), pfn, true);
}

/*
@@ -301,6 +301,7 @@ static int FNAME(shadow_walk_entry)(stru
mmu_set_spte(vcpu, sptep, access, gw->pte_access & access,
sw->user_fault, sw->write_fault,
gw->ptes[gw->level-1] & PT_DIRTY_MASK,
+ gw->ptes[gw->level-1] & PT_GLOBAL_MASK,
sw->ptwrite, sw->largepage, gw->gfn, sw->pfn,
false);
sw->sptep = sptep;

--