Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions arch/x86/kvm/mmu/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ struct kmem_cache *mmu_page_header_cache;
static struct percpu_counter kvm_total_used_mmu_pages;

static void mmu_spte_set(u64 *sptep, u64 spte);
static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp,
u64 *spte, struct list_head *invalid_list);

struct kvm_mmu_role_regs {
const unsigned long cr0;
Expand Down Expand Up @@ -1146,20 +1148,6 @@ static void drop_spte(struct kvm *kvm, u64 *sptep)
rmap_remove(kvm, sptep);
}

static void drop_large_spte(struct kvm *kvm, u64 *sptep, bool flush)
{
struct kvm_mmu_page *sp;

sp = sptep_to_sp(sptep);
WARN_ON(sp->role.level == PG_LEVEL_4K);

drop_spte(kvm, sptep);

if (flush)
kvm_flush_remote_tlbs_with_address(kvm, sp->gfn,
KVM_PAGES_PER_HPAGE(sp->role.level));
}

/*
* Write-protect on the specified @sptep, @pt_protect indicates whether
* spte write-protection is caused by protecting shadow page table.
Expand Down Expand Up @@ -2229,12 +2217,15 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
u64 *sptep, gfn_t gfn,
bool direct, unsigned int access)
{
union kvm_mmu_page_role role;
union kvm_mmu_page_role role = kvm_mmu_child_role(sptep, direct, access);

if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep))
if (is_shadow_present_pte(*sptep) &&
!is_large_pte(*sptep) &&
to_shadow_page(*sptep & SPTE_BASE_ADDR_MASK) &&
to_shadow_page(*sptep & SPTE_BASE_ADDR_MASK)->gfn == gfn &&
to_shadow_page(*sptep & SPTE_BASE_ADDR_MASK)->role.word == role.word)
return ERR_PTR(-EEXIST);

role = kvm_mmu_child_role(sptep, direct, access);
return kvm_mmu_get_shadow_page(vcpu, gfn, role);
}

Expand Down Expand Up @@ -2309,13 +2300,16 @@ static void __link_shadow_page(struct kvm *kvm,

BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);

/*
* If an SPTE is present already, it must be a leaf and therefore
* a large one. Drop it, and flush the TLB if needed, before
* installing sp.
*/
if (is_shadow_present_pte(*sptep))
drop_large_spte(kvm, sptep, flush);
if (is_shadow_present_pte(*sptep)) {
struct kvm_mmu_page *parent_sp;
LIST_HEAD(invalid_list);

parent_sp = sptep_to_sp(sptep);
WARN_ON_ONCE(parent_sp->role.level == PG_LEVEL_4K);

mmu_page_zap_pte(kvm, parent_sp, sptep, &invalid_list);
kvm_mmu_remote_flush_or_zap(kvm, &invalid_list, true);
}

spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp));

Expand Down
Loading