aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <xiaoguangrong@cn.fujitsu.com>2011-03-09 02:43:51 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2011-03-17 12:08:35 -0400
commit0f53b5b1c0baae4f949ac0721a55b7a2158dda01 (patch)
tree822b7230ed0d9731492733d33ad2221cb644bdf2
parent5d163b1c9d6e5562dcdfd6cd471f237f1502bb35 (diff)
KVM: MMU: cleanup pte write path
This patch does: - call vcpu->arch.mmu.update_pte directly - use gfn_to_pfn_atomic in update_pte path The suggestion is from Avi. Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_host.h7
-rw-r--r--arch/x86/kvm/mmu.c69
-rw-r--r--arch/x86/kvm/paging_tmpl.h12
3 files changed, 32 insertions, 56 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f08314f303e0..c8af0991fdf0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -255,6 +255,8 @@ struct kvm_mmu {
255 int (*sync_page)(struct kvm_vcpu *vcpu, 255 int (*sync_page)(struct kvm_vcpu *vcpu,
256 struct kvm_mmu_page *sp); 256 struct kvm_mmu_page *sp);
257 void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva); 257 void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
258 void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
259 u64 *spte, const void *pte, unsigned long mmu_seq);
258 hpa_t root_hpa; 260 hpa_t root_hpa;
259 int root_level; 261 int root_level;
260 int shadow_root_level; 262 int shadow_root_level;
@@ -335,11 +337,6 @@ struct kvm_vcpu_arch {
335 u64 *last_pte_updated; 337 u64 *last_pte_updated;
336 gfn_t last_pte_gfn; 338 gfn_t last_pte_gfn;
337 339
338 struct {
339 pfn_t pfn; /* pfn corresponding to that gfn */
340 unsigned long mmu_seq;
341 } update_pte;
342
343 struct fpu guest_fpu; 340 struct fpu guest_fpu;
344 u64 xcr0; 341 u64 xcr0;
345 342
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 83171fdd38a7..22fae7593ee7 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1204,6 +1204,13 @@ static void nonpaging_invlpg(struct kvm_vcpu *vcpu, gva_t gva)
1204{ 1204{
1205} 1205}
1206 1206
1207static void nonpaging_update_pte(struct kvm_vcpu *vcpu,
1208 struct kvm_mmu_page *sp, u64 *spte,
1209 const void *pte, unsigned long mmu_seq)
1210{
1211 WARN_ON(1);
1212}
1213
1207#define KVM_PAGE_ARRAY_NR 16 1214#define KVM_PAGE_ARRAY_NR 16
1208 1215
1209struct kvm_mmu_pages { 1216struct kvm_mmu_pages {
@@ -2796,6 +2803,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu,
2796 context->prefetch_page = nonpaging_prefetch_page; 2803 context->prefetch_page = nonpaging_prefetch_page;
2797 context->sync_page = nonpaging_sync_page; 2804 context->sync_page = nonpaging_sync_page;
2798 context->invlpg = nonpaging_invlpg; 2805 context->invlpg = nonpaging_invlpg;
2806 context->update_pte = nonpaging_update_pte;
2799 context->root_level = 0; 2807 context->root_level = 0;
2800 context->shadow_root_level = PT32E_ROOT_LEVEL; 2808 context->shadow_root_level = PT32E_ROOT_LEVEL;
2801 context->root_hpa = INVALID_PAGE; 2809 context->root_hpa = INVALID_PAGE;
@@ -2925,6 +2933,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu,
2925 context->prefetch_page = paging64_prefetch_page; 2933 context->prefetch_page = paging64_prefetch_page;
2926 context->sync_page = paging64_sync_page; 2934 context->sync_page = paging64_sync_page;
2927 context->invlpg = paging64_invlpg; 2935 context->invlpg = paging64_invlpg;
2936 context->update_pte = paging64_update_pte;
2928 context->free = paging_free; 2937 context->free = paging_free;
2929 context->root_level = level; 2938 context->root_level = level;
2930 context->shadow_root_level = level; 2939 context->shadow_root_level = level;
@@ -2953,6 +2962,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu,
2953 context->prefetch_page = paging32_prefetch_page; 2962 context->prefetch_page = paging32_prefetch_page;
2954 context->sync_page = paging32_sync_page; 2963 context->sync_page = paging32_sync_page;
2955 context->invlpg = paging32_invlpg; 2964 context->invlpg = paging32_invlpg;
2965 context->update_pte = paging32_update_pte;
2956 context->root_level = PT32_ROOT_LEVEL; 2966 context->root_level = PT32_ROOT_LEVEL;
2957 context->shadow_root_level = PT32E_ROOT_LEVEL; 2967 context->shadow_root_level = PT32E_ROOT_LEVEL;
2958 context->root_hpa = INVALID_PAGE; 2968 context->root_hpa = INVALID_PAGE;
@@ -2977,6 +2987,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
2977 context->prefetch_page = nonpaging_prefetch_page; 2987 context->prefetch_page = nonpaging_prefetch_page;
2978 context->sync_page = nonpaging_sync_page; 2988 context->sync_page = nonpaging_sync_page;
2979 context->invlpg = nonpaging_invlpg; 2989 context->invlpg = nonpaging_invlpg;
2990 context->update_pte = nonpaging_update_pte;
2980 context->shadow_root_level = kvm_x86_ops->get_tdp_level(); 2991 context->shadow_root_level = kvm_x86_ops->get_tdp_level();
2981 context->root_hpa = INVALID_PAGE; 2992 context->root_hpa = INVALID_PAGE;
2982 context->direct_map = true; 2993 context->direct_map = true;
@@ -3081,8 +3092,6 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
3081 3092
3082static int init_kvm_mmu(struct kvm_vcpu *vcpu) 3093static int init_kvm_mmu(struct kvm_vcpu *vcpu)
3083{ 3094{
3084 vcpu->arch.update_pte.pfn = bad_pfn;
3085
3086 if (mmu_is_nested(vcpu)) 3095 if (mmu_is_nested(vcpu))
3087 return init_kvm_nested_mmu(vcpu); 3096 return init_kvm_nested_mmu(vcpu);
3088 else if (tdp_enabled) 3097 else if (tdp_enabled)
@@ -3156,7 +3165,7 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
3156static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, 3165static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
3157 struct kvm_mmu_page *sp, 3166 struct kvm_mmu_page *sp,
3158 u64 *spte, 3167 u64 *spte,
3159 const void *new) 3168 const void *new, unsigned long mmu_seq)
3160{ 3169{
3161 if (sp->role.level != PT_PAGE_TABLE_LEVEL) { 3170 if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
3162 ++vcpu->kvm->stat.mmu_pde_zapped; 3171 ++vcpu->kvm->stat.mmu_pde_zapped;
@@ -3164,10 +3173,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
3164 } 3173 }
3165 3174
3166 ++vcpu->kvm->stat.mmu_pte_updated; 3175 ++vcpu->kvm->stat.mmu_pte_updated;
3167 if (!sp->role.cr4_pae) 3176 vcpu->arch.mmu.update_pte(vcpu, sp, spte, new, mmu_seq);
3168 paging32_update_pte(vcpu, sp, spte, new);
3169 else
3170 paging64_update_pte(vcpu, sp, spte, new);
3171} 3177}
3172 3178
3173static bool need_remote_flush(u64 old, u64 new) 3179static bool need_remote_flush(u64 old, u64 new)
@@ -3202,27 +3208,6 @@ static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu)
3202 return !!(spte && (*spte & shadow_accessed_mask)); 3208 return !!(spte && (*spte & shadow_accessed_mask));
3203} 3209}
3204 3210
3205static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
3206 u64 gpte)
3207{
3208 gfn_t gfn;
3209 pfn_t pfn;
3210
3211 if (!is_present_gpte(gpte))
3212 return;
3213 gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
3214
3215 vcpu->arch.update_pte.mmu_seq = vcpu->kvm->mmu_notifier_seq;
3216 smp_rmb();
3217 pfn = gfn_to_pfn(vcpu->kvm, gfn);
3218
3219 if (is_error_pfn(pfn)) {
3220 kvm_release_pfn_clean(pfn);
3221 return;
3222 }
3223 vcpu->arch.update_pte.pfn = pfn;
3224}
3225
3226static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn) 3211static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn)
3227{ 3212{
3228 u64 *spte = vcpu->arch.last_pte_updated; 3213 u64 *spte = vcpu->arch.last_pte_updated;
@@ -3244,21 +3229,14 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
3244 struct kvm_mmu_page *sp; 3229 struct kvm_mmu_page *sp;
3245 struct hlist_node *node; 3230 struct hlist_node *node;
3246 LIST_HEAD(invalid_list); 3231 LIST_HEAD(invalid_list);
3247 u64 entry, gentry; 3232 unsigned long mmu_seq;
3248 u64 *spte; 3233 u64 entry, gentry, *spte;
3249 unsigned offset = offset_in_page(gpa); 3234 unsigned pte_size, page_offset, misaligned, quadrant, offset;
3250 unsigned pte_size; 3235 int level, npte, invlpg_counter, r, flooded = 0;
3251 unsigned page_offset;
3252 unsigned misaligned;
3253 unsigned quadrant;
3254 int level;
3255 int flooded = 0;
3256 int npte;
3257 int r;
3258 int invlpg_counter;
3259 bool remote_flush, local_flush, zap_page; 3236 bool remote_flush, local_flush, zap_page;
3260 3237
3261 zap_page = remote_flush = local_flush = false; 3238 zap_page = remote_flush = local_flush = false;
3239 offset = offset_in_page(gpa);
3262 3240
3263 pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes); 3241 pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
3264 3242
@@ -3293,7 +3271,9 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
3293 break; 3271 break;
3294 } 3272 }
3295 3273
3296 mmu_guess_page_from_pte_write(vcpu, gpa, gentry); 3274 mmu_seq = vcpu->kvm->mmu_notifier_seq;
3275 smp_rmb();
3276
3297 spin_lock(&vcpu->kvm->mmu_lock); 3277 spin_lock(&vcpu->kvm->mmu_lock);
3298 if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter) 3278 if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter)
3299 gentry = 0; 3279 gentry = 0;
@@ -3365,7 +3345,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
3365 if (gentry && 3345 if (gentry &&
3366 !((sp->role.word ^ vcpu->arch.mmu.base_role.word) 3346 !((sp->role.word ^ vcpu->arch.mmu.base_role.word)
3367 & mask.word)) 3347 & mask.word))
3368 mmu_pte_write_new_pte(vcpu, sp, spte, &gentry); 3348 mmu_pte_write_new_pte(vcpu, sp, spte, &gentry,
3349 mmu_seq);
3369 if (!remote_flush && need_remote_flush(entry, *spte)) 3350 if (!remote_flush && need_remote_flush(entry, *spte))
3370 remote_flush = true; 3351 remote_flush = true;
3371 ++spte; 3352 ++spte;
@@ -3375,10 +3356,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
3375 kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); 3356 kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
3376 trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE); 3357 trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE);
3377 spin_unlock(&vcpu->kvm->mmu_lock); 3358 spin_unlock(&vcpu->kvm->mmu_lock);
3378 if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
3379 kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
3380 vcpu->arch.update_pte.pfn = bad_pfn;
3381 }
3382} 3359}
3383 3360
3384int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) 3361int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 86eb8160bcb9..751405097d8c 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -325,7 +325,7 @@ no_present:
325} 325}
326 326
327static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, 327static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
328 u64 *spte, const void *pte) 328 u64 *spte, const void *pte, unsigned long mmu_seq)
329{ 329{
330 pt_element_t gpte; 330 pt_element_t gpte;
331 unsigned pte_access; 331 unsigned pte_access;
@@ -337,12 +337,14 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
337 337
338 pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); 338 pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
339 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); 339 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
340 pfn = vcpu->arch.update_pte.pfn; 340 pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
341 if (is_error_pfn(pfn)) 341 if (is_error_pfn(pfn)) {
342 kvm_release_pfn_clean(pfn);
342 return; 343 return;
343 if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq)) 344 }
345 if (mmu_notifier_retry(vcpu, mmu_seq))
344 return; 346 return;
345 kvm_get_pfn(pfn); 347
346 /* 348 /*
347 * we call mmu_set_spte() with host_writable = true beacuse that 349 * we call mmu_set_spte() with host_writable = true beacuse that
348 * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1). 350 * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).