diff options
Diffstat (limited to 'arch/x86/kvm/paging_tmpl.h')
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 36 |
1 files changed, 12 insertions, 24 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 72558f8ff3f5..81eab9a50e6a 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -150,7 +150,9 @@ walk: | |||
150 | walker->table_gfn[walker->level - 1] = table_gfn; | 150 | walker->table_gfn[walker->level - 1] = table_gfn; |
151 | walker->pte_gpa[walker->level - 1] = pte_gpa; | 151 | walker->pte_gpa[walker->level - 1] = pte_gpa; |
152 | 152 | ||
153 | kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte)); | 153 | if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) |
154 | goto not_present; | ||
155 | |||
154 | trace_kvm_mmu_paging_element(pte, walker->level); | 156 | trace_kvm_mmu_paging_element(pte, walker->level); |
155 | 157 | ||
156 | if (!is_present_gpte(pte)) | 158 | if (!is_present_gpte(pte)) |
@@ -160,7 +162,7 @@ walk: | |||
160 | if (rsvd_fault) | 162 | if (rsvd_fault) |
161 | goto access_error; | 163 | goto access_error; |
162 | 164 | ||
163 | if (write_fault && !is_writeble_pte(pte)) | 165 | if (write_fault && !is_writable_pte(pte)) |
164 | if (user_fault || is_write_protection(vcpu)) | 166 | if (user_fault || is_write_protection(vcpu)) |
165 | goto access_error; | 167 | goto access_error; |
166 | 168 | ||
@@ -455,8 +457,6 @@ out_unlock: | |||
455 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | 457 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) |
456 | { | 458 | { |
457 | struct kvm_shadow_walk_iterator iterator; | 459 | struct kvm_shadow_walk_iterator iterator; |
458 | pt_element_t gpte; | ||
459 | gpa_t pte_gpa = -1; | ||
460 | int level; | 460 | int level; |
461 | u64 *sptep; | 461 | u64 *sptep; |
462 | int need_flush = 0; | 462 | int need_flush = 0; |
@@ -467,14 +467,9 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | |||
467 | level = iterator.level; | 467 | level = iterator.level; |
468 | sptep = iterator.sptep; | 468 | sptep = iterator.sptep; |
469 | 469 | ||
470 | /* FIXME: properly handle invlpg on large guest pages */ | ||
471 | if (level == PT_PAGE_TABLE_LEVEL || | 470 | if (level == PT_PAGE_TABLE_LEVEL || |
472 | ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) || | 471 | ((level == PT_DIRECTORY_LEVEL && is_large_pte(*sptep))) || |
473 | ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) { | 472 | ((level == PT_PDPE_LEVEL && is_large_pte(*sptep)))) { |
474 | struct kvm_mmu_page *sp = page_header(__pa(sptep)); | ||
475 | |||
476 | pte_gpa = (sp->gfn << PAGE_SHIFT); | ||
477 | pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); | ||
478 | 473 | ||
479 | if (is_shadow_present_pte(*sptep)) { | 474 | if (is_shadow_present_pte(*sptep)) { |
480 | rmap_remove(vcpu->kvm, sptep); | 475 | rmap_remove(vcpu->kvm, sptep); |
@@ -493,32 +488,25 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | |||
493 | if (need_flush) | 488 | if (need_flush) |
494 | kvm_flush_remote_tlbs(vcpu->kvm); | 489 | kvm_flush_remote_tlbs(vcpu->kvm); |
495 | spin_unlock(&vcpu->kvm->mmu_lock); | 490 | spin_unlock(&vcpu->kvm->mmu_lock); |
496 | |||
497 | if (pte_gpa == -1) | ||
498 | return; | ||
499 | if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte, | ||
500 | sizeof(pt_element_t))) | ||
501 | return; | ||
502 | if (is_present_gpte(gpte) && (gpte & PT_ACCESSED_MASK)) { | ||
503 | if (mmu_topup_memory_caches(vcpu)) | ||
504 | return; | ||
505 | kvm_mmu_pte_write(vcpu, pte_gpa, (const u8 *)&gpte, | ||
506 | sizeof(pt_element_t), 0); | ||
507 | } | ||
508 | } | 491 | } |
509 | 492 | ||
510 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) | 493 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, |
494 | u32 *error) | ||
511 | { | 495 | { |
512 | struct guest_walker walker; | 496 | struct guest_walker walker; |
513 | gpa_t gpa = UNMAPPED_GVA; | 497 | gpa_t gpa = UNMAPPED_GVA; |
514 | int r; | 498 | int r; |
515 | 499 | ||
516 | r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); | 500 | r = FNAME(walk_addr)(&walker, vcpu, vaddr, |
501 | !!(access & PFERR_WRITE_MASK), | ||
502 | !!(access & PFERR_USER_MASK), | ||
503 | !!(access & PFERR_FETCH_MASK)); | ||
517 | 504 | ||
518 | if (r) { | 505 | if (r) { |
519 | gpa = gfn_to_gpa(walker.gfn); | 506 | gpa = gfn_to_gpa(walker.gfn); |
520 | gpa |= vaddr & ~PAGE_MASK; | 507 | gpa |= vaddr & ~PAGE_MASK; |
521 | } | 508 | } else if (error) |
509 | *error = walker.error_code; | ||
522 | 510 | ||
523 | return gpa; | 511 | return gpa; |
524 | } | 512 | } |