Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ea11f2b authored by Suravee Suthikulpanit's avatar Suravee Suthikulpanit Committed by Paolo Bonzini
Browse files

svm: Introduces AVIC per-VM ID



Introduces per-VM AVIC ID and helper functions to manage the IDs.
Currently, the ID will be used to implement 32-bit AVIC IOMMU GA tag.

The ID is 24-bit one-based indexing value, and is managed via helper
functions to get the next ID, or to free an ID once a VM is destroyed.
There should be no ID conflict for any active VMs.

Reviewed-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
Signed-off-by: default avatarSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 9ac7e3e8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -781,6 +781,7 @@ struct kvm_arch {
	bool disabled_lapic_found;

	/* Struct members for AVIC */
	u32 avic_vm_id;
	u32 ldr_mode;
	struct page *avic_logical_id_table_page;
	struct page *avic_physical_id_table_page;
+51 −0
Original line number Diff line number Diff line
@@ -96,6 +96,19 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
#define AVIC_UNACCEL_ACCESS_OFFSET_MASK		0xFF0
#define AVIC_UNACCEL_ACCESS_VECTOR_MASK		0xFFFFFFFF

/* AVIC GATAG is encoded using VM and VCPU IDs */
#define AVIC_VCPU_ID_BITS		8
#define AVIC_VCPU_ID_MASK		((1 << AVIC_VCPU_ID_BITS) - 1)

#define AVIC_VM_ID_BITS			24
#define AVIC_VM_ID_NR			(1 << AVIC_VM_ID_BITS)
#define AVIC_VM_ID_MASK			((1 << AVIC_VM_ID_BITS) - 1)

#define AVIC_GATAG(x, y)		(((x & AVIC_VM_ID_MASK) << AVIC_VCPU_ID_BITS) | \
						(y & AVIC_VCPU_ID_MASK))
#define AVIC_GATAG_TO_VMID(x)		((x >> AVIC_VCPU_ID_BITS) & AVIC_VM_ID_MASK)
#define AVIC_GATAG_TO_VCPUID(x)		(x & AVIC_VCPU_ID_MASK)

static bool erratum_383_found __read_mostly;

static const u32 host_save_user_msrs[] = {
@@ -242,6 +255,10 @@ static int avic;
module_param(avic, int, S_IRUGO);
#endif

/* AVIC VM ID bit masks and lock */
static DECLARE_BITMAP(avic_vm_id_bitmap, AVIC_VM_ID_NR);
static DEFINE_SPINLOCK(avic_vm_id_lock);

static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
static void svm_flush_tlb(struct kvm_vcpu *vcpu);
static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -1280,10 +1297,40 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
	return 0;
}

static inline int avic_get_next_vm_id(void)
{
	int id;

	spin_lock(&avic_vm_id_lock);

	/* AVIC VM ID is one-based. */
	id = find_next_zero_bit(avic_vm_id_bitmap, AVIC_VM_ID_NR, 1);
	if (id <= AVIC_VM_ID_MASK)
		__set_bit(id, avic_vm_id_bitmap);
	else
		id = -EAGAIN;

	spin_unlock(&avic_vm_id_lock);
	return id;
}

static inline int avic_free_vm_id(int id)
{
	if (id <= 0 || id > AVIC_VM_ID_MASK)
		return -EINVAL;

	spin_lock(&avic_vm_id_lock);
	__clear_bit(id, avic_vm_id_bitmap);
	spin_unlock(&avic_vm_id_lock);
	return 0;
}

static void avic_vm_destroy(struct kvm *kvm)
{
	struct kvm_arch *vm_data = &kvm->arch;

	avic_free_vm_id(vm_data->avic_vm_id);

	if (vm_data->avic_logical_id_table_page)
		__free_page(vm_data->avic_logical_id_table_page);
	if (vm_data->avic_physical_id_table_page)
@@ -1300,6 +1347,10 @@ static int avic_vm_init(struct kvm *kvm)
	if (!avic)
		return 0;

	vm_data->avic_vm_id = avic_get_next_vm_id();
	if (vm_data->avic_vm_id < 0)
		return vm_data->avic_vm_id;

	/* Allocating physical APIC ID table (4KB) */
	p_page = alloc_page(GFP_KERNEL);
	if (!p_page)