Commit fc66963d authored by Sean Christopherson's avatar Sean Christopherson
Browse files

KVM: selftests: Split out kvm_cpuid2_size() from allocate_kvm_cpuid2()



Split out the computation of the effective size of a kvm_cpuid2 struct
from allocate_kvm_cpuid2(), and modify both to take an arbitrary number
of entries.  Future commits will add caching of a vCPU's CPUID model, and
will (a) be able to precisely size the entries array, and (b) will need
to know the effective size of the struct in order to copy to/from the
cache.

Expose the helpers so that the Hyper-V Features test can use them in the
(somewhat distant) future.  The Hyper-V test very, very subtly relies on
propagating CPUID info across vCPU instances, and will need to make a
copy of the previous vCPU's CPUID information when it switches to using
the per-vCPU cache.  Alternatively, KVM could provide helpers to
duplicate and/or copy a kvm_cpuid2 instance, but each is literally a
single line of code if the helpers are exposed, and it's not like the
size of kvm_cpuid2 is secret knowledge.

Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20220614200707.3315957-18-seanjc@google.com
parent 71bcb951
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -595,6 +595,29 @@ static inline bool kvm_cpu_has(struct kvm_x86_cpu_feature feature)
	return kvm_cpuid_has(kvm_get_supported_cpuid(), feature);
}

static inline size_t kvm_cpuid2_size(int nr_entries)
{
	return sizeof(struct kvm_cpuid2) +
	       sizeof(struct kvm_cpuid_entry2) * nr_entries;
}

/*
 * Allocate a "struct kvm_cpuid2* instance, with the 0-length arrary of
 * entries sized to hold @nr_entries.  The caller is responsible for freeing
 * the struct.
 */
static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries)
{
	struct kvm_cpuid2 *cpuid;

	cpuid = malloc(kvm_cpuid2_size(nr_entries));
	TEST_ASSERT(cpuid, "-ENOMEM when allocating kvm_cpuid2");

	cpuid->nent = nr_entries;

	return cpuid;
}

struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu);

static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu,
+7 −41
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
#define DEFAULT_CODE_SELECTOR 0x8
#define DEFAULT_DATA_SELECTOR 0x10

#define MAX_NR_CPUID_ENTRIES 100

vm_vaddr_t exception_handlers;

static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent)
@@ -672,40 +674,6 @@ struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id)
	return vcpu;
}

/*
 * Allocate an instance of struct kvm_cpuid2
 *
 * Input Args: None
 *
 * Output Args: None
 *
 * Return: A pointer to the allocated struct. The caller is responsible
 * for freeing this struct.
 *
 * Since kvm_cpuid2 uses a 0-length array to allow a the size of the
 * array to be decided at allocation time, allocation is slightly
 * complicated. This function uses a reasonable default length for
 * the array and performs the appropriate allocation.
 */
static struct kvm_cpuid2 *allocate_kvm_cpuid2(void)
{
	struct kvm_cpuid2 *cpuid;
	int nent = 100;
	size_t size;

	size = sizeof(*cpuid);
	size += nent * sizeof(struct kvm_cpuid_entry2);
	cpuid = malloc(size);
	if (!cpuid) {
		perror("malloc");
		abort();
	}

	cpuid->nent = nent;

	return cpuid;
}

/*
 * KVM Supported CPUID Get
 *
@@ -725,7 +693,7 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
	if (cpuid)
		return cpuid;

	cpuid = allocate_kvm_cpuid2();
	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
	kvm_fd = open_kvm_dev_path_or_exit();

	kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid);
@@ -781,7 +749,7 @@ struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu)
	int max_ent;
	int rc = -1;

	cpuid = allocate_kvm_cpuid2();
	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
	max_ent = cpuid->nent;

	for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) {
@@ -1295,7 +1263,7 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void)
	if (cpuid)
		return cpuid;

	cpuid = allocate_kvm_cpuid2();
	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
	kvm_fd = open_kvm_dev_path_or_exit();

	kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
@@ -1314,9 +1282,7 @@ void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu)
		cpuid_sys = kvm_get_supported_cpuid();
		cpuid_hv = kvm_get_supported_hv_cpuid();

		cpuid_full = malloc(sizeof(*cpuid_full) +
				    (cpuid_sys->nent + cpuid_hv->nent) *
				    sizeof(struct kvm_cpuid_entry2));
		cpuid_full = allocate_kvm_cpuid2(cpuid_sys->nent + cpuid_hv->nent);
		if (!cpuid_full) {
			perror("malloc");
			abort();
@@ -1343,7 +1309,7 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu)
{
	static struct kvm_cpuid2 *cpuid;

	cpuid = allocate_kvm_cpuid2();
	cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);

	vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid);