aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-06-04 08:58:30 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:45 -0400
commit17c3ba9d37dbda490792a2b52953f09d0dee30d6 (patch)
tree44749b8658b61c7aa6cdb38d7823fa061d24b12c
parentbd2b2baa5c5fbb08b4b0df7508ff419407f7ece6 (diff)
KVM: Lazy guest cr3 switching
Switch guest paging context may require us to allocate memory, which might fail. Instead of wiring up error paths everywhere, make context switching lazy and actually do the switch before the next guest entry, where we can return an error if allocation fails. Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/kvm.h10
-rw-r--r--drivers/kvm/mmu.c43
-rw-r--r--drivers/kvm/svm.c4
-rw-r--r--drivers/kvm/vmx.c4
4 files changed, 40 insertions, 21 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 199e1e9bae25..3ec4e26b9bd7 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -544,6 +544,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
544 const u8 *old, const u8 *new, int bytes); 544 const u8 *old, const u8 *new, int bytes);
545int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); 545int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
546void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); 546void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
547int kvm_mmu_load(struct kvm_vcpu *vcpu);
548void kvm_mmu_unload(struct kvm_vcpu *vcpu);
547 549
548int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run); 550int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
549 551
@@ -555,6 +557,14 @@ static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
555 return vcpu->mmu.page_fault(vcpu, gva, error_code); 557 return vcpu->mmu.page_fault(vcpu, gva, error_code);
556} 558}
557 559
560static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
561{
562 if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
563 return 0;
564
565 return kvm_mmu_load(vcpu);
566}
567
558static inline int is_long_mode(struct kvm_vcpu *vcpu) 568static inline int is_long_mode(struct kvm_vcpu *vcpu)
559{ 569{
560#ifdef CONFIG_X86_64 570#ifdef CONFIG_X86_64
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 283df031b03d..5915d7a1c4f7 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -949,9 +949,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
949 context->free = nonpaging_free; 949 context->free = nonpaging_free;
950 context->root_level = 0; 950 context->root_level = 0;
951 context->shadow_root_level = PT32E_ROOT_LEVEL; 951 context->shadow_root_level = PT32E_ROOT_LEVEL;
952 mmu_alloc_roots(vcpu); 952 context->root_hpa = INVALID_PAGE;
953 ASSERT(VALID_PAGE(context->root_hpa));
954 kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
955 return 0; 953 return 0;
956} 954}
957 955
@@ -965,11 +963,6 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
965{ 963{
966 pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3); 964 pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3);
967 mmu_free_roots(vcpu); 965 mmu_free_roots(vcpu);
968 if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
969 kvm_mmu_free_some_pages(vcpu);
970 mmu_alloc_roots(vcpu);
971 kvm_mmu_flush_tlb(vcpu);
972 kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
973} 966}
974 967
975static void inject_page_fault(struct kvm_vcpu *vcpu, 968static void inject_page_fault(struct kvm_vcpu *vcpu,
@@ -1003,10 +996,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
1003 context->free = paging_free; 996 context->free = paging_free;
1004 context->root_level = level; 997 context->root_level = level;
1005 context->shadow_root_level = level; 998 context->shadow_root_level = level;
1006 mmu_alloc_roots(vcpu); 999 context->root_hpa = INVALID_PAGE;
1007 ASSERT(VALID_PAGE(context->root_hpa));
1008 kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
1009 (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
1010 return 0; 1000 return 0;
1011} 1001}
1012 1002
@@ -1025,10 +1015,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
1025 context->free = paging_free; 1015 context->free = paging_free;
1026 context->root_level = PT32_ROOT_LEVEL; 1016 context->root_level = PT32_ROOT_LEVEL;
1027 context->shadow_root_level = PT32E_ROOT_LEVEL; 1017 context->shadow_root_level = PT32E_ROOT_LEVEL;
1028 mmu_alloc_roots(vcpu); 1018 context->root_hpa = INVALID_PAGE;
1029 ASSERT(VALID_PAGE(context->root_hpa));
1030 kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
1031 (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
1032 return 0; 1019 return 0;
1033} 1020}
1034 1021
@@ -1042,7 +1029,6 @@ static int init_kvm_mmu(struct kvm_vcpu *vcpu)
1042 ASSERT(vcpu); 1029 ASSERT(vcpu);
1043 ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); 1030 ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
1044 1031
1045 mmu_topup_memory_caches(vcpu);
1046 if (!is_paging(vcpu)) 1032 if (!is_paging(vcpu))
1047 return nonpaging_init_context(vcpu); 1033 return nonpaging_init_context(vcpu);
1048 else if (is_long_mode(vcpu)) 1034 else if (is_long_mode(vcpu))
@@ -1064,16 +1050,31 @@ static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
1064 1050
1065int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) 1051int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
1066{ 1052{
1053 destroy_kvm_mmu(vcpu);
1054 return init_kvm_mmu(vcpu);
1055}
1056
1057int kvm_mmu_load(struct kvm_vcpu *vcpu)
1058{
1067 int r; 1059 int r;
1068 1060
1069 destroy_kvm_mmu(vcpu); 1061 spin_lock(&vcpu->kvm->lock);
1070 r = init_kvm_mmu(vcpu);
1071 if (r < 0)
1072 goto out;
1073 r = mmu_topup_memory_caches(vcpu); 1062 r = mmu_topup_memory_caches(vcpu);
1063 if (r)
1064 goto out;
1065 mmu_alloc_roots(vcpu);
1066 kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
1067 kvm_mmu_flush_tlb(vcpu);
1074out: 1068out:
1069 spin_unlock(&vcpu->kvm->lock);
1075 return r; 1070 return r;
1076} 1071}
1072EXPORT_SYMBOL_GPL(kvm_mmu_load);
1073
1074void kvm_mmu_unload(struct kvm_vcpu *vcpu)
1075{
1076 mmu_free_roots(vcpu);
1077}
1077 1078
1078static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, 1079static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
1079 struct kvm_mmu_page *page, 1080 struct kvm_mmu_page *page,
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 6cd6a50a0340..ec040e2f8c58 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1483,6 +1483,10 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1483 int r; 1483 int r;
1484 1484
1485again: 1485again:
1486 r = kvm_mmu_reload(vcpu);
1487 if (unlikely(r))
1488 return r;
1489
1486 if (!vcpu->mmio_read_completed) 1490 if (!vcpu->mmio_read_completed)
1487 do_interrupt_requests(vcpu, kvm_run); 1491 do_interrupt_requests(vcpu, kvm_run);
1488 1492
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 93e5bb2c40e3..4d255493a57e 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1988,6 +1988,10 @@ again:
1988 vmx_save_host_state(vcpu); 1988 vmx_save_host_state(vcpu);
1989 kvm_load_guest_fpu(vcpu); 1989 kvm_load_guest_fpu(vcpu);
1990 1990
1991 r = kvm_mmu_reload(vcpu);
1992 if (unlikely(r))
1993 goto out;
1994
1991 /* 1995 /*
1992 * Loading guest fpu may have cleared host cr0.ts 1996 * Loading guest fpu may have cleared host cr0.ts
1993 */ 1997 */