15c3d55faSPekka Enberg #include "kvm/kvm-cpu.h" 25c3d55faSPekka Enberg 3a1fe6bc5SPekka Enberg #include "kvm/kvm.h" 4a1fe6bc5SPekka Enberg #include "kvm/util.h" 5a1fe6bc5SPekka Enberg 6a1fe6bc5SPekka Enberg #include <sys/ioctl.h> 7a1fe6bc5SPekka Enberg #include <stdlib.h> 8a1fe6bc5SPekka Enberg 9a1fe6bc5SPekka Enberg #define MAX_KVM_CPUID_ENTRIES 100 10a1fe6bc5SPekka Enberg 11*20b93be5SMuchun Song static void filter_cpuid(struct kvm_cpuid2 *kvm_cpuid, int cpu_id) 121e1b3818SPekka Enberg { 13bc0b99a2SCyrill Gorcunov unsigned int signature[3]; 141e1b3818SPekka Enberg unsigned int i; 151e1b3818SPekka Enberg 161e1b3818SPekka Enberg /* 171e1b3818SPekka Enberg * Filter CPUID functions that are not supported by the hypervisor. 181e1b3818SPekka Enberg */ 191e1b3818SPekka Enberg for (i = 0; i < kvm_cpuid->nent; i++) { 201e1b3818SPekka Enberg struct kvm_cpuid_entry2 *entry = &kvm_cpuid->entries[i]; 211e1b3818SPekka Enberg 221e1b3818SPekka Enberg switch (entry->function) { 23bc0b99a2SCyrill Gorcunov case 0: 24bc0b99a2SCyrill Gorcunov /* Vendor name */ 25bc0b99a2SCyrill Gorcunov memcpy(signature, "LKVMLKVMLKVM", 12); 26bc0b99a2SCyrill Gorcunov entry->ebx = signature[0]; 27bc0b99a2SCyrill Gorcunov entry->ecx = signature[1]; 28bc0b99a2SCyrill Gorcunov entry->edx = signature[2]; 29bc0b99a2SCyrill Gorcunov break; 300d5b41d9SSasha Levin case 1: 31*20b93be5SMuchun Song entry->ebx &= ~(0xff << 24); 32*20b93be5SMuchun Song entry->ebx |= cpu_id << 24; 330d5b41d9SSasha Levin /* Set X86_FEATURE_HYPERVISOR */ 340d5b41d9SSasha Levin if (entry->index == 0) 350d5b41d9SSasha Levin entry->ecx |= (1 << 31); 360d5b41d9SSasha Levin break; 37abc73d8dSCyrill Gorcunov case 6: 380d5b41d9SSasha Levin /* Clear X86_FEATURE_EPB */ 39abc73d8dSCyrill Gorcunov entry->ecx = entry->ecx & ~(1 << 3); 40abc73d8dSCyrill Gorcunov break; 417800e6faSCyrill Gorcunov case 10: { /* Architectural Performance Monitoring */ 427800e6faSCyrill Gorcunov union cpuid10_eax { 437800e6faSCyrill Gorcunov struct { 447800e6faSCyrill Gorcunov unsigned int version_id :8; 457800e6faSCyrill Gorcunov unsigned int num_counters :8; 467800e6faSCyrill Gorcunov unsigned int bit_width :8; 477800e6faSCyrill Gorcunov unsigned int mask_length :8; 487800e6faSCyrill Gorcunov } split; 497800e6faSCyrill Gorcunov unsigned int full; 507800e6faSCyrill Gorcunov } eax; 517800e6faSCyrill Gorcunov 527800e6faSCyrill Gorcunov /* 537800e6faSCyrill Gorcunov * If the host has perf system running, 547800e6faSCyrill Gorcunov * but no architectural events available 557800e6faSCyrill Gorcunov * through kvm pmu -- disable perf support, 567800e6faSCyrill Gorcunov * thus guest won't even try to access msr 577800e6faSCyrill Gorcunov * registers. 587800e6faSCyrill Gorcunov */ 597800e6faSCyrill Gorcunov if (entry->eax) { 607800e6faSCyrill Gorcunov eax.full = entry->eax; 617800e6faSCyrill Gorcunov if (eax.split.version_id != 2 || 627800e6faSCyrill Gorcunov !eax.split.num_counters) 637800e6faSCyrill Gorcunov entry->eax = 0; 647800e6faSCyrill Gorcunov } 651e1b3818SPekka Enberg break; 667800e6faSCyrill Gorcunov } 671e1b3818SPekka Enberg default: 681e1b3818SPekka Enberg /* Keep the CPUID function as -is */ 691e1b3818SPekka Enberg break; 701e1b3818SPekka Enberg }; 711e1b3818SPekka Enberg } 721e1b3818SPekka Enberg } 731e1b3818SPekka Enberg 7443835ac9SSasha Levin void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu) 75a1fe6bc5SPekka Enberg { 76a1fe6bc5SPekka Enberg struct kvm_cpuid2 *kvm_cpuid; 77a1fe6bc5SPekka Enberg 783a60be06SSasha Levin kvm_cpuid = calloc(1, sizeof(*kvm_cpuid) + 793a60be06SSasha Levin MAX_KVM_CPUID_ENTRIES * sizeof(*kvm_cpuid->entries)); 80a1fe6bc5SPekka Enberg 81bb988cf5SAsias He kvm_cpuid->nent = MAX_KVM_CPUID_ENTRIES; 8243835ac9SSasha Levin if (ioctl(vcpu->kvm->sys_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid) < 0) 83bb988cf5SAsias He die_perror("KVM_GET_SUPPORTED_CPUID failed"); 84a1fe6bc5SPekka Enberg 85*20b93be5SMuchun Song filter_cpuid(kvm_cpuid, vcpu->cpu_id); 861e1b3818SPekka Enberg 8743835ac9SSasha Levin if (ioctl(vcpu->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0) 88a1fe6bc5SPekka Enberg die_perror("KVM_SET_CPUID2 failed"); 89a1fe6bc5SPekka Enberg 90bb988cf5SAsias He free(kvm_cpuid); 91a1fe6bc5SPekka Enberg } 92