tools/testing/selftests/kvm/lib/arm64/vgic.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/lib/arm64/vgic.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/lib/arm64/vgic.c
Extension
.c
Size
5628 bytes
Lines
213
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * ARM Generic Interrupt Controller (GIC) v3 host support
 */

#include <linux/kernel.h>
#include <linux/kvm.h>
#include <linux/sizes.h>
#include <asm/cputype.h>
#include <asm/kvm_para.h>
#include <asm/kvm.h>

#include "kvm_util.h"
#include "vgic.h"
#include "gic.h"
#include "gic_v3.h"

bool kvm_supports_vgic_v3(void)
{
	struct kvm_vm *vm = vm_create_barebones();
	int r;

	r = __kvm_test_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3);
	kvm_vm_free(vm);

	return !r;
}

/*
 * vGIC-v3 default host setup
 *
 * Input args:
 *	vm - KVM VM
 *	nr_vcpus - Number of vCPUs supported by this VM
 *
 * Output args: None
 *
 * Return: GIC file-descriptor or negative error code upon failure
 *
 * The function creates a vGIC-v3 device and maps the distributor and
 * redistributor regions of the guest. Since it depends on the number of
 * vCPUs for the VM, it must be called after all the vCPUs have been created.
 */
int __vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, u32 nr_irqs)
{
	int gic_fd;
	u64 attr;
	unsigned int nr_gic_pages;

	/* Distributor setup */
	gic_fd = __kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3);
	if (gic_fd < 0)
		return gic_fd;

	kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &nr_irqs);

	attr = GICD_BASE_GPA;
	kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
			    KVM_VGIC_V3_ADDR_TYPE_DIST, &attr);
	nr_gic_pages = vm_calc_num_guest_pages(vm->mode, KVM_VGIC_V3_DIST_SIZE);
	virt_map(vm, GICD_BASE_GPA, GICD_BASE_GPA, nr_gic_pages);

	/* Redistributor setup */
	attr = REDIST_REGION_ATTR_ADDR(nr_vcpus, GICR_BASE_GPA, 0, 0);
	kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
			    KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &attr);
	nr_gic_pages = vm_calc_num_guest_pages(vm->mode,
						KVM_VGIC_V3_REDIST_SIZE * nr_vcpus);
	virt_map(vm, GICR_BASE_GPA, GICR_BASE_GPA, nr_gic_pages);

	return gic_fd;
}

void __vgic_v3_init(int fd)
{
	kvm_device_attr_set(fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
			    KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
}

int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, u32 nr_irqs)
{
	unsigned int nr_vcpus_created = 0;
	struct list_head *iter;
	int fd;

	TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty");

	/*
	 * Make sure that the caller is infact calling this
	 * function after all the vCPUs are added.

Annotation

Implementation Notes