arch/arm64/kvm/pkvm.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/pkvm.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/pkvm.c
Extension
.c
Size
15495 bytes
Lines
593
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration 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 (mapping) {
			ret = kvm_call_hyp_nvhe(__pkvm_vcpu_in_poison_fault);
			return ret ? -EFAULT : -EAGAIN;
		}

		ret = kvm_call_hyp_nvhe(__pkvm_host_donate_guest, pfn, gfn);
	} else {
		if (WARN_ON_ONCE(size != PAGE_SIZE && size != PMD_SIZE))
			return -EINVAL;

		/*
		 * We either raced with another vCPU or we're changing between
		 * page and block mappings. As per user_mem_abort(), same-size
		 * permission faults are handled in the relax_perms() path.
		 */
		if (mapping) {
			if (size == (mapping->nr_pages * PAGE_SIZE))
				return -EAGAIN;

			/*
			 * Remove _any_ pkvm_mapping overlapping with the range,
			 * bigger or smaller.
			 */
			ret = __pkvm_pgtable_stage2_unshare(pgt, addr, end);
			if (ret)
				return ret;

			mapping = NULL;
		}

		ret = kvm_call_hyp_nvhe(__pkvm_host_share_guest, pfn, gfn,
					size / PAGE_SIZE, prot);
	}

	if (WARN_ON(ret))
		return ret;

	swap(mapping, cache->mapping);
	mapping->gfn = gfn;
	mapping->pfn = pfn;
	mapping->nr_pages = size / PAGE_SIZE;
	pkvm_mapping_insert(mapping, &pgt->pkvm_mappings);

	return ret;
}

int pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
{
	struct kvm *kvm = kvm_s2_mmu_to_kvm(pgt->mmu);

	if (WARN_ON(kvm_vm_is_protected(kvm)))
		return -EPERM;

	lockdep_assert_held_write(&kvm->mmu_lock);

	return __pkvm_pgtable_stage2_unshare(pgt, addr, addr + size);
}

int pkvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size)
{
	struct kvm *kvm = kvm_s2_mmu_to_kvm(pgt->mmu);
	pkvm_handle_t handle = kvm->arch.pkvm.handle;
	struct pkvm_mapping *mapping;
	int ret = 0;

	if (WARN_ON(kvm_vm_is_protected(kvm)))
		return -EPERM;

	lockdep_assert_held(&kvm->mmu_lock);
	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
		ret = kvm_call_hyp_nvhe(__pkvm_host_wrprotect_guest, handle, mapping->gfn,
					mapping->nr_pages);
		if (WARN_ON(ret))
			break;
	}

	return ret;
}

int pkvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size)
{
	struct kvm *kvm = kvm_s2_mmu_to_kvm(pgt->mmu);
	struct pkvm_mapping *mapping;

	lockdep_assert_held(&kvm->mmu_lock);
	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping)
		__clean_dcache_guest_page(pfn_to_kaddr(mapping->pfn),
					  PAGE_SIZE * mapping->nr_pages);

	return 0;

Annotation

Implementation Notes