aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2013-09-09 07:52:33 -0400
committerGleb Natapov <gleb@redhat.com>2013-09-17 05:52:31 -0400
commitba6a3541545542721ce821d1e7e5ce35752e6fdf (patch)
treeb53ff602454f383dc8148d38d7d870972d7866db /virt
parent3261107ebfd8f6bba57cfcdb89385779fd149a00 (diff)
KVM: mmu: allow page tables to be in read-only slots
Page tables in a read-only memory slot will currently cause a triple fault because the page walker uses gfn_to_hva and it fails on such a slot. OVMF uses such a page table; however, real hardware seems to be fine with that as long as the accessed/dirty bits are set. Save whether the slot is readonly, and later check it when updating the accessed and dirty bits. Reviewed-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Reviewed-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index bf040c4e02b3..979bff485fb0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1058,11 +1058,15 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
1058EXPORT_SYMBOL_GPL(gfn_to_hva); 1058EXPORT_SYMBOL_GPL(gfn_to_hva);
1059 1059
1060/* 1060/*
1061 * The hva returned by this function is only allowed to be read. 1061 * If writable is set to false, the hva returned by this function is only
1062 * It should pair with kvm_read_hva() or kvm_read_hva_atomic(). 1062 * allowed to be read.
1063 */ 1063 */
1064static unsigned long gfn_to_hva_read(struct kvm *kvm, gfn_t gfn) 1064unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable)
1065{ 1065{
1066 struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
1067 if (writable)
1068 *writable = !memslot_is_readonly(slot);
1069
1066 return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false); 1070 return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false);
1067} 1071}
1068 1072
@@ -1430,7 +1434,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
1430 int r; 1434 int r;
1431 unsigned long addr; 1435 unsigned long addr;
1432 1436
1433 addr = gfn_to_hva_read(kvm, gfn); 1437 addr = gfn_to_hva_prot(kvm, gfn, NULL);
1434 if (kvm_is_error_hva(addr)) 1438 if (kvm_is_error_hva(addr))
1435 return -EFAULT; 1439 return -EFAULT;
1436 r = kvm_read_hva(data, (void __user *)addr + offset, len); 1440 r = kvm_read_hva(data, (void __user *)addr + offset, len);
@@ -1468,7 +1472,7 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
1468 gfn_t gfn = gpa >> PAGE_SHIFT; 1472 gfn_t gfn = gpa >> PAGE_SHIFT;
1469 int offset = offset_in_page(gpa); 1473 int offset = offset_in_page(gpa);
1470 1474
1471 addr = gfn_to_hva_read(kvm, gfn); 1475 addr = gfn_to_hva_prot(kvm, gfn, NULL);
1472 if (kvm_is_error_hva(addr)) 1476 if (kvm_is_error_hva(addr))
1473 return -EFAULT; 1477 return -EFAULT;
1474 pagefault_disable(); 1478 pagefault_disable();