arch/x86/kvm/mmu/tdp_mmu.c

Source file repositories/reference/linux-study-clean/arch/x86/kvm/mmu/tdp_mmu.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/mmu/tdp_mmu.c
Extension
.c
Size
60426 bytes
Lines
1950
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (_as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) {	\
		} else

#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id)	\
	__for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, KVM_VALID_ROOTS)

#define for_each_tdp_mmu_root_yield_safe(_kvm, _root)			\
	for (_root = tdp_mmu_next_root(_kvm, NULL, KVM_ALL_ROOTS);		\
	     ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root;	\
	     _root = tdp_mmu_next_root(_kvm, _root, KVM_ALL_ROOTS))

/*
 * Iterate over all TDP MMU roots.  Requires that mmu_lock be held for write,
 * the implication being that any flow that holds mmu_lock for read is
 * inherently yield-friendly and should use the yield-safe variant above.
 * Holding mmu_lock for write obviates the need for RCU protection as the list
 * is guaranteed to be stable.
 */
#define __for_each_tdp_mmu_root(_kvm, _root, _as_id, _types)			\
	list_for_each_entry(_root, &_kvm->arch.tdp_mmu_roots, link)		\
		if (kvm_lockdep_assert_mmu_lock_held(_kvm, false) &&		\
		    ((_as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) ||	\
		     !tdp_mmu_root_match((_root), (_types)))) {			\
		} else

/*
 * Iterate over all TDP MMU roots in an RCU read-side critical section.
 * It is safe to iterate over the SPTEs under the root, but their values will
 * be unstable, so all writes must be atomic. As this routine is meant to be
 * used without holding the mmu_lock at all, any bits that are flipped must
 * be reflected in kvm_tdp_mmu_spte_need_atomic_write().
 */
#define for_each_tdp_mmu_root_rcu(_kvm, _root, _as_id, _types)			\
	list_for_each_entry_rcu(_root, &_kvm->arch.tdp_mmu_roots, link)		\
		if ((_as_id >= 0 && kvm_mmu_page_as_id(_root) != _as_id) ||	\
		    !tdp_mmu_root_match((_root), (_types))) {			\
		} else

#define for_each_valid_tdp_mmu_root(_kvm, _root, _as_id)		\
	__for_each_tdp_mmu_root(_kvm, _root, _as_id, KVM_VALID_ROOTS)

static struct kvm_mmu_page *tdp_mmu_alloc_sp(struct kvm_vcpu *vcpu)
{
	struct kvm_mmu_page *sp;

	sp = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache);
	sp->spt = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_shadow_page_cache);

	return sp;
}

static void tdp_mmu_init_sp(struct kvm_mmu_page *sp, tdp_ptep_t sptep,
			    gfn_t gfn, union kvm_mmu_page_role role)
{
	INIT_LIST_HEAD(&sp->possible_nx_huge_page_link);

	set_page_private(virt_to_page(sp->spt), (unsigned long)sp);

	sp->role = role;
	sp->gfn = gfn;
	sp->ptep = sptep;
	sp->tdp_mmu_page = true;

	trace_kvm_mmu_get_page(sp, true);
}

static void tdp_mmu_init_child_sp(struct kvm_mmu_page *child_sp,
				  struct tdp_iter *iter)
{
	struct kvm_mmu_page *parent_sp;
	union kvm_mmu_page_role role;

	parent_sp = sptep_to_sp(rcu_dereference(iter->sptep));

	role = parent_sp->role;
	role.level--;

	tdp_mmu_init_sp(child_sp, iter->sptep, iter->gfn, role);
}

void kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu, bool mirror)
{
	struct kvm_mmu *mmu = vcpu->arch.mmu;
	union kvm_mmu_page_role role = mmu->root_role;
	int as_id = kvm_mmu_role_as_id(role);
	struct kvm *kvm = vcpu->kvm;
	struct kvm_mmu_page *root;

	if (mirror)
		role.is_mirror = true;

Annotation

Implementation Notes