arch/arm64/kvm/hyp/nvhe/pkvm.c

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

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/hyp/nvhe/pkvm.c
Extension
.c
Size
28424 bytes
Lines
1170
Domain
Architecture Layer
Bucket
arch/arm64
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 (seeded < min_pages) {
			push_hyp_memcache(&selftest_vcpu.vcpu.arch.pkvm_memcache,
					  hyp_page_to_virt(&p[i]), hyp_virt_to_phys);
			seeded++;
		} else {
			hyp_put_page(&selftest_vm.pool, hyp_page_to_virt(&p[i]));
		}
	}

	selftest_vm.kvm.arch.pkvm.handle = __pkvm_reserve_vm();
	insert_vm_table_entry(selftest_vm.kvm.arch.pkvm.handle, &selftest_vm);
	return &selftest_vcpu;
}

void teardown_selftest_vm(void)
{
	hyp_spin_lock(&vm_table_lock);
	remove_vm_table_entry(selftest_vm.kvm.arch.pkvm.handle);
	hyp_spin_unlock(&vm_table_lock);
}
#endif /* CONFIG_NVHE_EL2_DEBUG */

/*
 * Initialize the hypervisor copy of the VM state using host-donated memory.
 *
 * Unmap the donated memory from the host at stage 2.
 *
 * host_kvm: A pointer to the host's struct kvm.
 * vm_hva: The host va of the area being donated for the VM state.
 *	   Must be page aligned.
 * pgd_hva: The host va of the area being donated for the stage-2 PGD for
 *	    the VM. Must be page aligned. Its size is implied by the VM's
 *	    VTCR.
 *
 * Return 0 success, negative error code on failure.
 */
int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
		   unsigned long pgd_hva)
{
	struct pkvm_hyp_vm *hyp_vm = NULL;
	size_t vm_size, pgd_size;
	unsigned int nr_vcpus;
	pkvm_handle_t handle;
	void *pgd = NULL;
	int ret;

	ret = hyp_pin_shared_mem(host_kvm, host_kvm + 1);
	if (ret)
		return ret;

	nr_vcpus = READ_ONCE(host_kvm->created_vcpus);
	if (nr_vcpus < 1) {
		ret = -EINVAL;
		goto err_unpin_kvm;
	}

	handle = READ_ONCE(host_kvm->arch.pkvm.handle);
	if (unlikely(handle < HANDLE_OFFSET)) {
		ret = -EINVAL;
		goto err_unpin_kvm;
	}

	vm_size = pkvm_get_hyp_vm_size(nr_vcpus);
	pgd_size = kvm_pgtable_stage2_pgd_size(host_mmu.arch.mmu.vtcr);

	ret = -ENOMEM;

	hyp_vm = map_donated_memory(vm_hva, vm_size);
	if (!hyp_vm)
		goto err_remove_mappings;

	pgd = map_donated_memory_noclear(pgd_hva, pgd_size);
	if (!pgd)
		goto err_remove_mappings;

	init_pkvm_hyp_vm(host_kvm, hyp_vm, nr_vcpus, handle);

	ret = kvm_guest_prepare_stage2(hyp_vm, pgd);
	if (ret)
		goto err_remove_mappings;

	/* Must be called last since this publishes the VM. */
	ret = insert_vm_table_entry(handle, hyp_vm);
	if (ret)
		goto err_destroy_stage2;

	return 0;

err_destroy_stage2:
	kvm_guest_destroy_stage2(hyp_vm);

Annotation

Implementation Notes