blob: f4347a84952f48612c04099c8e2df440df5b47c4 [file] [log] [blame]
#include "kvm/kvm-cpu.h"
#include "kvm/kvm.h"
#include "kvm/util.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#define MAX_KVM_CPUID_ENTRIES 100
static void filter_cpuid(struct kvm_cpuid2 *kvm_cpuid, int cpu_id)
{
unsigned int i;
/*
* Filter CPUID functions that are not supported by the hypervisor.
*/
for (i = 0; i < kvm_cpuid->nent; i++) {
struct kvm_cpuid_entry2 *entry = &kvm_cpuid->entries[i];
switch (entry->function) {
case 1:
entry->ebx &= ~(0xff << 24);
entry->ebx |= cpu_id << 24;
/* Set X86_FEATURE_HYPERVISOR */
if (entry->index == 0)
entry->ecx |= (1 << 31);
break;
case 6:
/* Clear X86_FEATURE_EPB */
entry->ecx = entry->ecx & ~(1 << 3);
break;
case 10: { /* Architectural Performance Monitoring */
union cpuid10_eax {
struct {
unsigned int version_id :8;
unsigned int num_counters :8;
unsigned int bit_width :8;
unsigned int mask_length :8;
} split;
unsigned int full;
} eax;
/*
* If the host has perf system running,
* but no architectural events available
* through kvm pmu -- disable perf support,
* thus guest won't even try to access msr
* registers.
*/
if (entry->eax) {
eax.full = entry->eax;
if (eax.split.version_id != 2 ||
!eax.split.num_counters)
entry->eax = 0;
}
break;
}
default:
/* Keep the CPUID function as -is */
break;
};
}
}
void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu)
{
struct kvm_cpuid2 *kvm_cpuid;
kvm_cpuid = calloc(1, sizeof(*kvm_cpuid) +
MAX_KVM_CPUID_ENTRIES * sizeof(*kvm_cpuid->entries));
kvm_cpuid->nent = MAX_KVM_CPUID_ENTRIES;
if (ioctl(vcpu->kvm->sys_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid) < 0)
die_perror("KVM_GET_SUPPORTED_CPUID failed");
filter_cpuid(kvm_cpuid, vcpu->cpu_id);
if (ioctl(vcpu->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0)
die_perror("KVM_SET_CPUID2 failed");
free(kvm_cpuid);
}