aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/paging_tmpl.h
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2009-07-27 10:30:46 -0400
committerAvi Kivity <avi@redhat.com>2009-09-10 01:33:19 -0400
commit7e4e4056f72da51c5dede48515df0ecd20eaf8ca (patch)
tree74ed536181a241c959d1bf5366c624f376e6784a /arch/x86/kvm/paging_tmpl.h
parente04da980c35d75fa050ba4009ad99025432d8d7d (diff)
KVM: MMU: shadow support for 1gb pages
This patch adds support for shadow paging to the 1gb page table code in KVM. With this code the guest can use 1gb pages even if the host does not support them. [ Marcelo: fix shadow page collision on pmd level if a guest 1gb page is mapped with 4kb ptes on host level ] Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/paging_tmpl.h')
-rw-r--r--arch/x86/kvm/paging_tmpl.h43
1 files changed, 20 insertions, 23 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 578276e34bd9..d2fec9c12d22 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -256,7 +256,6 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
256 pt_element_t gpte; 256 pt_element_t gpte;
257 unsigned pte_access; 257 unsigned pte_access;
258 pfn_t pfn; 258 pfn_t pfn;
259 int level = vcpu->arch.update_pte.level;
260 259
261 gpte = *(const pt_element_t *)pte; 260 gpte = *(const pt_element_t *)pte;
262 if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) { 261 if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
@@ -275,7 +274,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
275 return; 274 return;
276 kvm_get_pfn(pfn); 275 kvm_get_pfn(pfn);
277 mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, 276 mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
278 gpte & PT_DIRTY_MASK, NULL, level, 277 gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL,
279 gpte_to_gfn(gpte), pfn, true); 278 gpte_to_gfn(gpte), pfn, true);
280} 279}
281 280
@@ -284,7 +283,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
284 */ 283 */
285static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, 284static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
286 struct guest_walker *gw, 285 struct guest_walker *gw,
287 int user_fault, int write_fault, int largepage, 286 int user_fault, int write_fault, int hlevel,
288 int *ptwrite, pfn_t pfn) 287 int *ptwrite, pfn_t pfn)
289{ 288{
290 unsigned access = gw->pt_access; 289 unsigned access = gw->pt_access;
@@ -303,8 +302,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
303 for_each_shadow_entry(vcpu, addr, iterator) { 302 for_each_shadow_entry(vcpu, addr, iterator) {
304 level = iterator.level; 303 level = iterator.level;
305 sptep = iterator.sptep; 304 sptep = iterator.sptep;
306 if (level == PT_PAGE_TABLE_LEVEL 305 if (iterator.level == hlevel) {
307 || (largepage && level == PT_DIRECTORY_LEVEL)) {
308 mmu_set_spte(vcpu, sptep, access, 306 mmu_set_spte(vcpu, sptep, access,
309 gw->pte_access & access, 307 gw->pte_access & access,
310 user_fault, write_fault, 308 user_fault, write_fault,
@@ -323,12 +321,15 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
323 kvm_flush_remote_tlbs(vcpu->kvm); 321 kvm_flush_remote_tlbs(vcpu->kvm);
324 } 322 }
325 323
326 if (level == PT_DIRECTORY_LEVEL 324 if (level <= gw->level) {
327 && gw->level == PT_DIRECTORY_LEVEL) { 325 int delta = level - gw->level + 1;
328 direct = 1; 326 direct = 1;
329 if (!is_dirty_gpte(gw->ptes[level - 1])) 327 if (!is_dirty_gpte(gw->ptes[level - delta]))
330 access &= ~ACC_WRITE_MASK; 328 access &= ~ACC_WRITE_MASK;
331 table_gfn = gpte_to_gfn(gw->ptes[level - 1]); 329 table_gfn = gpte_to_gfn(gw->ptes[level - delta]);
330 /* advance table_gfn when emulating 1gb pages with 4k */
331 if (delta == 0)
332 table_gfn += PT_INDEX(addr, level);
332 } else { 333 } else {
333 direct = 0; 334 direct = 0;
334 table_gfn = gw->table_gfn[level - 2]; 335 table_gfn = gw->table_gfn[level - 2];
@@ -381,7 +382,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
381 int write_pt = 0; 382 int write_pt = 0;
382 int r; 383 int r;
383 pfn_t pfn; 384 pfn_t pfn;
384 int largepage = 0; 385 int level = PT_PAGE_TABLE_LEVEL;
385 unsigned long mmu_seq; 386 unsigned long mmu_seq;
386 387
387 pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code); 388 pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
@@ -407,15 +408,11 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
407 return 0; 408 return 0;
408 } 409 }
409 410
410 if (walker.level == PT_DIRECTORY_LEVEL) { 411 if (walker.level >= PT_DIRECTORY_LEVEL) {
411 gfn_t large_gfn; 412 level = min(walker.level, mapping_level(vcpu, walker.gfn));
412 large_gfn = walker.gfn & 413 walker.gfn = walker.gfn & ~(KVM_PAGES_PER_HPAGE(level) - 1);
413 ~(KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL) - 1);
414 if (mapping_level(vcpu, large_gfn) == PT_DIRECTORY_LEVEL) {
415 walker.gfn = large_gfn;
416 largepage = 1;
417 }
418 } 414 }
415
419 mmu_seq = vcpu->kvm->mmu_notifier_seq; 416 mmu_seq = vcpu->kvm->mmu_notifier_seq;
420 smp_rmb(); 417 smp_rmb();
421 pfn = gfn_to_pfn(vcpu->kvm, walker.gfn); 418 pfn = gfn_to_pfn(vcpu->kvm, walker.gfn);
@@ -432,8 +429,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
432 goto out_unlock; 429 goto out_unlock;
433 kvm_mmu_free_some_pages(vcpu); 430 kvm_mmu_free_some_pages(vcpu);
434 sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, 431 sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
435 largepage, &write_pt, pfn); 432 level, &write_pt, pfn);
436
437 pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__, 433 pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__,
438 sptep, *sptep, write_pt); 434 sptep, *sptep, write_pt);
439 435
@@ -468,8 +464,9 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)
468 sptep = iterator.sptep; 464 sptep = iterator.sptep;
469 465
470 /* FIXME: properly handle invlpg on large guest pages */ 466 /* FIXME: properly handle invlpg on large guest pages */
471 if (level == PT_PAGE_TABLE_LEVEL || 467 if (level == PT_PAGE_TABLE_LEVEL ||
472 ((level == PT_DIRECTORY_LEVEL) && is_large_pte(*sptep))) { 468 ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) ||
469 ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) {
473 struct kvm_mmu_page *sp = page_header(__pa(sptep)); 470 struct kvm_mmu_page *sp = page_header(__pa(sptep));
474 471
475 pte_gpa = (sp->gfn << PAGE_SHIFT); 472 pte_gpa = (sp->gfn << PAGE_SHIFT);
@@ -599,7 +596,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
599 nr_present++; 596 nr_present++;
600 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); 597 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
601 set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, 598 set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
602 is_dirty_gpte(gpte), 0, gfn, 599 is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn,
603 spte_to_pfn(sp->spt[i]), true, false); 600 spte_to_pfn(sp->spt[i]), true, false);
604 } 601 }
605 602