From: Ben-Ami Yassour <[EMAIL PROTECTED]>
Signed-off-by: Ben-Ami Yassour <[EMAIL PROTECTED]>
Signed-off-by: Muli Ben-Yehuda <[EMAIL PROTECTED]>
---
arch/x86/kvm/mmu.c | 59 +++++++++++++++++++++++++++++--------------
arch/x86/kvm/paging_tmpl.h | 19 +++++++++----
include/linux/kvm_host.h | 2 +-
virt/kvm/kvm_main.c | 17 +++++++++++-
4 files changed, 69 insertions(+), 28 deletions(-)
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 078a7f1..c89029d 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -112,6 +112,8 @@ static int dbg = 1;
#define PT_FIRST_AVAIL_BITS_SHIFT 9
#define PT64_SECOND_AVAIL_BITS_SHIFT 52
+#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
#define PT64_LEVEL_BITS 9
@@ -237,6 +239,9 @@ static int is_dirty_pte(unsigned long pte)
static int is_rmap_pte(u64 pte)
{
+ if (pte & PT_SHADOW_IO_MARK)
+ return false;
+
return is_shadow_present_pte(pte);
}
@@ -1034,7 +1039,8 @@ 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)
+ pfn_t pfn, bool speculative,
+ int direct_mmio)
{
u64 spte;
int was_rmapped = 0;
@@ -1114,6 +1120,9 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64
*shadow_pte,
}
}
+ if (direct_mmio)
+ spte |= PT_SHADOW_IO_MARK;
+
unshadowed:
if (pte_access & ACC_WRITE_MASK)
@@ -1129,16 +1138,19 @@ unshadowed:
++vcpu->kvm->stat.lpages;
page_header_update_slot(vcpu->kvm, shadow_pte, gfn);
- if (!was_rmapped) {
- rmap_add(vcpu, shadow_pte, gfn, largepage);
- if (!is_rmap_pte(*shadow_pte))
- kvm_release_pfn_clean(pfn);
- } else {
- if (was_writeble)
- kvm_release_pfn_dirty(pfn);
- else
- kvm_release_pfn_clean(pfn);
+ if (!direct_mmio) {
+ if (!was_rmapped) {
+ rmap_add(vcpu, shadow_pte, gfn, largepage);
+ if (!is_rmap_pte(*shadow_pte))
+ kvm_release_pfn_clean(pfn);
+ } else {
+ if (was_writeble)
+ kvm_release_pfn_dirty(pfn);
+ else
+ kvm_release_pfn_clean(pfn);
+ }
}
+
if (!ptwrite || !*ptwrite)
vcpu->arch.last_pte_updated = shadow_pte;
}
@@ -1149,7 +1161,7 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
int largepage, gfn_t gfn, pfn_t pfn,
- int level)
+ int level, int direct_mmio)
{
hpa_t table_addr = vcpu->arch.mmu.root_hpa;
int pt_write = 0;
@@ -1163,13 +1175,15 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v,
int write,
if (level == 1) {
mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL,
- 0, write, 1, &pt_write, 0, gfn, pfn,
false);
+ 0, write, 1, &pt_write, 0, gfn, pfn,
+ false, direct_mmio);
return pt_write;
}
if (largepage && level == 2) {
mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL,
- 0, write, 1, &pt_write, 1, gfn, pfn,
false);
+ 0, write, 1, &pt_write, 1, gfn, pfn,
+ false, direct_mmio);
return pt_write;
}
@@ -1200,6 +1214,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v,
int write, gfn_t gfn)
int r;
int largepage = 0;
pfn_t pfn;
+ int direct_mmio = 0;
down_read(¤t->mm->mmap_sem);
if (is_largepage_backed(vcpu, gfn & ~(KVM_PAGES_PER_HPAGE-1))) {
@@ -1207,10 +1222,10 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t
v, int write, gfn_t gfn)
largepage = 1;
}
- pfn = gfn_to_pfn(vcpu->kvm, gfn);
+ pfn = gfn_to_pfn(vcpu->kvm, gfn, &direct_mmio);
up_read(¤t->mm->mmap_sem);
- /* mmio */
+ /* handle emulated mmio */
if (is_error_pfn(pfn)) {
kvm_release_pfn_clean(pfn);
return 1;
@@ -1219,7 +1234,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v,
int write, gfn_t gfn)
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
r = __direct_map(vcpu, v, write, largepage, gfn, pfn,
- PT32E_ROOT_LEVEL);
+ PT32E_ROOT_LEVEL, direct_mmio);
spin_unlock(&vcpu->kvm->mmu_lock);
@@ -1355,6 +1370,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t
gpa,
int r;
int largepage = 0;
gfn_t gfn = gpa >> PAGE_SHIFT;
+ int direct_mmio = 0;
ASSERT(vcpu);
ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa));
@@ -1368,7 +1384,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t
gpa,
gfn &= ~(KVM_PAGES_PER_HPAGE-1);
largepage = 1;
}
- pfn = gfn_to_pfn(vcpu->kvm, gfn);
+ pfn = gfn_to_pfn(vcpu->kvm, gfn, &direct_mmio);
up_read(¤t->mm->mmap_sem);
if (is_error_pfn(pfn)) {
kvm_release_pfn_clean(pfn);
@@ -1377,7 +1393,8 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t
gpa,
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
r = __direct_map(vcpu, gpa, error_code & PFERR_WRITE_MASK,
- largepage, gfn, pfn, TDP_ROOT_LEVEL);
+ largepage, gfn, pfn, TDP_ROOT_LEVEL,
+ direct_mmio);
spin_unlock(&vcpu->kvm->mmu_lock);
return r;
@@ -1643,6 +1660,7 @@ static void mmu_guess_page_from_pte_write(struct kvm_vcpu
*vcpu, gpa_t gpa,
int r;
u64 gpte = 0;
pfn_t pfn;
+ int direct_mmio = 0;
vcpu->arch.update_pte.largepage = 0;
@@ -1678,9 +1696,12 @@ static void mmu_guess_page_from_pte_write(struct
kvm_vcpu *vcpu, gpa_t gpa,
gfn &= ~(KVM_PAGES_PER_HPAGE-1);
vcpu->arch.update_pte.largepage = 1;
}
- pfn = gfn_to_pfn(vcpu->kvm, gfn);
+ pfn = gfn_to_pfn(vcpu->kvm, gfn, &direct_mmio);
up_read(¤t->mm->mmap_sem);
+ if (direct_mmio)
+ return;
+
if (is_error_pfn(pfn)) {
kvm_release_pfn_clean(pfn);
return;
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 156fe10..e85d8ae 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -264,9 +264,10 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *page,
if (is_error_pfn(pfn))
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);
+ pfn, true, false);
}
/*
@@ -275,7 +276,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct
kvm_mmu_page *page,
static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
struct guest_walker *walker,
int user_fault, int write_fault, int largepage,
- int *ptwrite, pfn_t pfn)
+ int *ptwrite, pfn_t pfn, int direct_mmio)
{
hpa_t shadow_addr;
int level;
@@ -349,11 +350,15 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t
addr,
mmu_set_spte(vcpu, shadow_ent, access, walker->pte_access & access,
user_fault, write_fault,
walker->ptes[walker->level-1] & PT_DIRTY_MASK,
- ptwrite, largepage, walker->gfn, pfn, false);
+ ptwrite, largepage, walker->gfn, pfn, false,
+ direct_mmio);
return shadow_ent;
}
+static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr);
+
+
/*
* Page fault handler. There are several causes for a page fault:
* - there is no shadow pte for the guest pte
@@ -380,6 +385,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t
addr,
int r;
pfn_t pfn;
int largepage = 0;
+ int direct_mmio = 0;
pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
kvm_mmu_audit(vcpu, "pre page fault");
@@ -413,10 +419,10 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t
addr,
largepage = 1;
}
}
- pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);
+ pfn = gfn_to_pfn(vcpu->kvm, walker.gfn, &direct_mmio);
up_read(¤t->mm->mmap_sem);
- /* mmio */
+ /* handle emulated mmio */
if (is_error_pfn(pfn)) {
pgprintk("gfn %x is mmio\n", walker.gfn);
kvm_release_pfn_clean(pfn);
@@ -426,7 +432,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t
addr,
spin_lock(&vcpu->kvm->mmu_lock);
kvm_mmu_free_some_pages(vcpu);
shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
- largepage, &write_pt, pfn);
+ largepage, &write_pt, pfn,
+ direct_mmio);
pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
shadow_pte, *shadow_pte, write_pt);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 578c363..0910cc1 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -173,7 +173,7 @@ void kvm_release_page_dirty(struct page *page);
void kvm_set_page_dirty(struct page *page);
void kvm_set_page_accessed(struct page *page);
-pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn, int *direct_mmio);
void kvm_release_pfn_dirty(pfn_t);
void kvm_release_pfn_clean(pfn_t pfn);
void kvm_set_pfn_dirty(pfn_t pfn);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 6a52c08..07b95f7 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -526,20 +526,33 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
/*
* Requires current->mm->mmap_sem to be held
*/
-pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
+pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn, int *direct_mmio)
{
struct page *page[1];
unsigned long addr;
int npages;
+ struct vm_area_struct *vma;
might_sleep();
+ if (direct_mmio)
+ *direct_mmio = 0;
+
addr = gfn_to_hva(kvm, gfn);
if (kvm_is_error_hva(addr)) {
get_page(bad_page);
return page_to_pfn(bad_page);
}
+ /* handle mmio */
+ vma = find_vma(current->mm, addr);
+ if (vma->vm_flags & VM_IO) {
+ if (direct_mmio)
+ *direct_mmio = 1;
+
+ return ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ }
+
npages = get_user_pages(current, current->mm, addr, 1, 1, 1, page,
NULL);
@@ -555,7 +568,7 @@ EXPORT_SYMBOL_GPL(gfn_to_pfn);
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
{
- return pfn_to_page(gfn_to_pfn(kvm, gfn));
+ return pfn_to_page(gfn_to_pfn(kvm, gfn, NULL));
}
EXPORT_SYMBOL_GPL(gfn_to_page);
--
1.5.4.5
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
kvm-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel