mirror of https://github.com/proxmox/mirror_qemu
kvm: Add support for querying supported cpu features
kvm does not support all cpu features; add support for dunamically querying the supported feature set. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>master
parent
ad7b8b3310
commit
b827df585b
3
kvm.h
3
kvm.h
|
@ -120,6 +120,9 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
|
||||||
|
|
||||||
int kvm_check_extension(KVMState *s, unsigned int extension);
|
int kvm_check_extension(KVMState *s, unsigned int extension);
|
||||||
|
|
||||||
|
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
|
||||||
|
int reg);
|
||||||
|
|
||||||
/* generic hooks - to be moved/refactored once there are more users */
|
/* generic hooks - to be moved/refactored once there are more users */
|
||||||
|
|
||||||
static inline void cpu_synchronize_state(CPUState *env, int modified)
|
static inline void cpu_synchronize_state(CPUState *env, int modified)
|
||||||
|
|
|
@ -34,6 +34,86 @@
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef KVM_CAP_EXT_CPUID
|
||||||
|
|
||||||
|
static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
|
||||||
|
{
|
||||||
|
struct kvm_cpuid2 *cpuid;
|
||||||
|
int r, size;
|
||||||
|
|
||||||
|
size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
|
||||||
|
cpuid = (struct kvm_cpuid2 *)qemu_mallocz(size);
|
||||||
|
cpuid->nent = max;
|
||||||
|
r = kvm_ioctl(s, KVM_GET_SUPPORTED_CPUID, cpuid);
|
||||||
|
if (r < 0) {
|
||||||
|
if (r == -E2BIG) {
|
||||||
|
qemu_free(cpuid);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
|
||||||
|
strerror(-r));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cpuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
|
||||||
|
{
|
||||||
|
struct kvm_cpuid2 *cpuid;
|
||||||
|
int i, max;
|
||||||
|
uint32_t ret = 0;
|
||||||
|
uint32_t cpuid_1_edx;
|
||||||
|
|
||||||
|
if (!kvm_check_extension(env->kvm_state, KVM_CAP_EXT_CPUID)) {
|
||||||
|
return -1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
max = 1;
|
||||||
|
while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
|
||||||
|
max *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < cpuid->nent; ++i) {
|
||||||
|
if (cpuid->entries[i].function == function) {
|
||||||
|
switch (reg) {
|
||||||
|
case R_EAX:
|
||||||
|
ret = cpuid->entries[i].eax;
|
||||||
|
break;
|
||||||
|
case R_EBX:
|
||||||
|
ret = cpuid->entries[i].ebx;
|
||||||
|
break;
|
||||||
|
case R_ECX:
|
||||||
|
ret = cpuid->entries[i].ecx;
|
||||||
|
break;
|
||||||
|
case R_EDX:
|
||||||
|
ret = cpuid->entries[i].edx;
|
||||||
|
if (function == 0x80000001) {
|
||||||
|
/* On Intel, kvm returns cpuid according to the Intel spec,
|
||||||
|
* so add missing bits according to the AMD spec:
|
||||||
|
*/
|
||||||
|
cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, R_EDX);
|
||||||
|
ret |= cpuid_1_edx & 0xdfeff7ff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_free(cpuid);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
|
||||||
|
{
|
||||||
|
return -1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int kvm_arch_init_vcpu(CPUState *env)
|
int kvm_arch_init_vcpu(CPUState *env)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
|
|
Loading…
Reference in New Issue