aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/paging_tmpl.h33
1 files changed, 24 insertions, 9 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 368e4cb6233b..8cb85f9c8adb 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -319,10 +319,11 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
319 int *ptwrite, pfn_t pfn) 319 int *ptwrite, pfn_t pfn)
320{ 320{
321 unsigned access = gw->pt_access; 321 unsigned access = gw->pt_access;
322 struct kvm_mmu_page *sp; 322 struct kvm_mmu_page *sp = NULL;
323 u64 *sptep = NULL; 323 u64 *sptep = NULL;
324 int uninitialized_var(level); 324 int uninitialized_var(level);
325 bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]); 325 bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]);
326 int top_level;
326 unsigned direct_access; 327 unsigned direct_access;
327 struct kvm_shadow_walk_iterator iterator; 328 struct kvm_shadow_walk_iterator iterator;
328 329
@@ -333,6 +334,18 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
333 if (!dirty) 334 if (!dirty)
334 direct_access &= ~ACC_WRITE_MASK; 335 direct_access &= ~ACC_WRITE_MASK;
335 336
337 top_level = vcpu->arch.mmu.root_level;
338 if (top_level == PT32E_ROOT_LEVEL)
339 top_level = PT32_ROOT_LEVEL;
340 /*
341 * Verify that the top-level gpte is still there. Since the page
342 * is a root page, it is either write protected (and cannot be
343 * changed from now on) or it is invalid (in which case, we don't
344 * really care if it changes underneath us after this point).
345 */
346 if (FNAME(gpte_changed)(vcpu, gw, top_level))
347 goto out_gpte_changed;
348
336 for (shadow_walk_init(&iterator, vcpu, addr); 349 for (shadow_walk_init(&iterator, vcpu, addr);
337 shadow_walk_okay(&iterator) && iterator.level > gw->level; 350 shadow_walk_okay(&iterator) && iterator.level > gw->level;
338 shadow_walk_next(&iterator)) { 351 shadow_walk_next(&iterator)) {
@@ -343,12 +356,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
343 356
344 drop_large_spte(vcpu, sptep); 357 drop_large_spte(vcpu, sptep);
345 358
346 if (is_shadow_present_pte(*sptep)) 359 sp = NULL;
347 continue; 360 if (!is_shadow_present_pte(*sptep)) {
348 361 table_gfn = gw->table_gfn[level - 2];
349 table_gfn = gw->table_gfn[level - 2]; 362 sp = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
350 sp = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, 363 false, access, sptep);
351 false, access, sptep); 364 }
352 365
353 /* 366 /*
354 * Verify that the gpte in the page we've just write 367 * Verify that the gpte in the page we've just write
@@ -357,7 +370,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
357 if (FNAME(gpte_changed)(vcpu, gw, level - 1)) 370 if (FNAME(gpte_changed)(vcpu, gw, level - 1))
358 goto out_gpte_changed; 371 goto out_gpte_changed;
359 372
360 link_shadow_page(sptep, sp); 373 if (sp)
374 link_shadow_page(sptep, sp);
361 } 375 }
362 376
363 for (; 377 for (;
@@ -392,7 +406,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
392 return sptep; 406 return sptep;
393 407
394out_gpte_changed: 408out_gpte_changed:
395 kvm_mmu_put_page(sp, sptep); 409 if (sp)
410 kvm_mmu_put_page(sp, sptep);
396 kvm_release_pfn_clean(pfn); 411 kvm_release_pfn_clean(pfn);
397 return NULL; 412 return NULL;
398} 413}