diff options
author | Avi Kivity <avi@qumranet.com> | 2007-06-04 08:58:30 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 05:05:45 -0400 |
commit | 17c3ba9d37dbda490792a2b52953f09d0dee30d6 (patch) | |
tree | 44749b8658b61c7aa6cdb38d7823fa061d24b12c /drivers/kvm/mmu.c | |
parent | bd2b2baa5c5fbb08b4b0df7508ff419407f7ece6 (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>
Diffstat (limited to 'drivers/kvm/mmu.c')
-rw-r--r-- | drivers/kvm/mmu.c | 43 |
1 files changed, 22 insertions, 21 deletions
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 | ||
975 | static void inject_page_fault(struct kvm_vcpu *vcpu, | 968 | static 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 | ||
1065 | int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) | 1051 | int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) |
1066 | { | 1052 | { |
1053 | destroy_kvm_mmu(vcpu); | ||
1054 | return init_kvm_mmu(vcpu); | ||
1055 | } | ||
1056 | |||
1057 | int 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); | ||
1074 | out: | 1068 | out: |
1069 | spin_unlock(&vcpu->kvm->lock); | ||
1075 | return r; | 1070 | return r; |
1076 | } | 1071 | } |
1072 | EXPORT_SYMBOL_GPL(kvm_mmu_load); | ||
1073 | |||
1074 | void kvm_mmu_unload(struct kvm_vcpu *vcpu) | ||
1075 | { | ||
1076 | mmu_free_roots(vcpu); | ||
1077 | } | ||
1077 | 1078 | ||
1078 | static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, | 1079 | static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, |
1079 | struct kvm_mmu_page *page, | 1080 | struct kvm_mmu_page *page, |