diff options
author | Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> | 2011-03-09 02:43:51 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2011-03-17 12:08:35 -0400 |
commit | 0f53b5b1c0baae4f949ac0721a55b7a2158dda01 (patch) | |
tree | 822b7230ed0d9731492733d33ad2221cb644bdf2 | |
parent | 5d163b1c9d6e5562dcdfd6cd471f237f1502bb35 (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.h | 7 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 69 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 12 |
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 | ||
1207 | static 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 | ||
1209 | struct kvm_mmu_pages { | 1216 | struct 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 | ||
3082 | static int init_kvm_mmu(struct kvm_vcpu *vcpu) | 3093 | static 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, | |||
3156 | static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, | 3165 | static 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 | ||
3173 | static bool need_remote_flush(u64 old, u64 new) | 3179 | static 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 | ||
3205 | static 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 | |||
3226 | static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn) | 3211 | static 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 | ||
3384 | int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) | 3361 | int 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 | ||
327 | static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, | 327 | static 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). |