1*a1fe6bc5SPekka Enberg #include "kvm/kvm.h" 2*a1fe6bc5SPekka Enberg 3*a1fe6bc5SPekka Enberg #include "kvm/util.h" 4*a1fe6bc5SPekka Enberg 5*a1fe6bc5SPekka Enberg #include <sys/ioctl.h> 6*a1fe6bc5SPekka Enberg #include <stdlib.h> 7*a1fe6bc5SPekka Enberg #include <assert.h> 8*a1fe6bc5SPekka Enberg 9*a1fe6bc5SPekka Enberg struct cpuid_regs { 10*a1fe6bc5SPekka Enberg uint32_t eax; 11*a1fe6bc5SPekka Enberg uint32_t ebx; 12*a1fe6bc5SPekka Enberg uint32_t ecx; 13*a1fe6bc5SPekka Enberg uint32_t edx; 14*a1fe6bc5SPekka Enberg }; 15*a1fe6bc5SPekka Enberg 16*a1fe6bc5SPekka Enberg static inline void 17*a1fe6bc5SPekka Enberg cpuid(struct cpuid_regs *regs) 18*a1fe6bc5SPekka Enberg { 19*a1fe6bc5SPekka Enberg asm("cpuid" 20*a1fe6bc5SPekka Enberg : "=a" (regs->eax), 21*a1fe6bc5SPekka Enberg "=b" (regs->ebx), 22*a1fe6bc5SPekka Enberg "=c" (regs->ecx), 23*a1fe6bc5SPekka Enberg "=d" (regs->edx) 24*a1fe6bc5SPekka Enberg : "0" (regs->eax), "2" (regs->ecx)); 25*a1fe6bc5SPekka Enberg } 26*a1fe6bc5SPekka Enberg 27*a1fe6bc5SPekka Enberg static struct kvm_cpuid2 *kvm_cpuid__new(unsigned long nent) 28*a1fe6bc5SPekka Enberg { 29*a1fe6bc5SPekka Enberg struct kvm_cpuid2 *self; 30*a1fe6bc5SPekka Enberg 31*a1fe6bc5SPekka Enberg self = calloc(1, sizeof(*self) + (sizeof(struct kvm_cpuid_entry2) * nent)); 32*a1fe6bc5SPekka Enberg 33*a1fe6bc5SPekka Enberg if (!self) 34*a1fe6bc5SPekka Enberg die("out of memory"); 35*a1fe6bc5SPekka Enberg 36*a1fe6bc5SPekka Enberg return self; 37*a1fe6bc5SPekka Enberg } 38*a1fe6bc5SPekka Enberg 39*a1fe6bc5SPekka Enberg static void kvm_cpuid__delete(struct kvm_cpuid2 *self) 40*a1fe6bc5SPekka Enberg { 41*a1fe6bc5SPekka Enberg free(self); 42*a1fe6bc5SPekka Enberg } 43*a1fe6bc5SPekka Enberg 44*a1fe6bc5SPekka Enberg #define MAX_KVM_CPUID_ENTRIES 100 45*a1fe6bc5SPekka Enberg 46*a1fe6bc5SPekka Enberg enum { 47*a1fe6bc5SPekka Enberg CPUID_GET_VENDOR_ID = 0x00, 48*a1fe6bc5SPekka Enberg CPUID_GET_HIGHEST_EXT_FUNCTION = 0x80000000, 49*a1fe6bc5SPekka Enberg }; 50*a1fe6bc5SPekka Enberg 51*a1fe6bc5SPekka Enberg static uint32_t cpuid_highest_ext_func(void) 52*a1fe6bc5SPekka Enberg { 53*a1fe6bc5SPekka Enberg struct cpuid_regs regs; 54*a1fe6bc5SPekka Enberg 55*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 56*a1fe6bc5SPekka Enberg .eax = CPUID_GET_HIGHEST_EXT_FUNCTION, 57*a1fe6bc5SPekka Enberg }; 58*a1fe6bc5SPekka Enberg cpuid(®s); 59*a1fe6bc5SPekka Enberg 60*a1fe6bc5SPekka Enberg return regs.eax; 61*a1fe6bc5SPekka Enberg } 62*a1fe6bc5SPekka Enberg 63*a1fe6bc5SPekka Enberg static uint32_t cpuid_highest_func(void) 64*a1fe6bc5SPekka Enberg { 65*a1fe6bc5SPekka Enberg struct cpuid_regs regs; 66*a1fe6bc5SPekka Enberg 67*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 68*a1fe6bc5SPekka Enberg .eax = CPUID_GET_VENDOR_ID, 69*a1fe6bc5SPekka Enberg }; 70*a1fe6bc5SPekka Enberg cpuid(®s); 71*a1fe6bc5SPekka Enberg 72*a1fe6bc5SPekka Enberg return regs.eax; 73*a1fe6bc5SPekka Enberg } 74*a1fe6bc5SPekka Enberg 75*a1fe6bc5SPekka Enberg void kvm__setup_cpuid(struct kvm *self) 76*a1fe6bc5SPekka Enberg { 77*a1fe6bc5SPekka Enberg struct kvm_cpuid2 *kvm_cpuid; 78*a1fe6bc5SPekka Enberg uint32_t highest_ext; 79*a1fe6bc5SPekka Enberg uint32_t function; 80*a1fe6bc5SPekka Enberg uint32_t highest; 81*a1fe6bc5SPekka Enberg uint32_t ndx = 0; 82*a1fe6bc5SPekka Enberg 83*a1fe6bc5SPekka Enberg kvm_cpuid = kvm_cpuid__new(MAX_KVM_CPUID_ENTRIES); 84*a1fe6bc5SPekka Enberg 85*a1fe6bc5SPekka Enberg highest = cpuid_highest_func(); 86*a1fe6bc5SPekka Enberg 87*a1fe6bc5SPekka Enberg for (function = 0; function < highest; function++) { 88*a1fe6bc5SPekka Enberg /* 89*a1fe6bc5SPekka Enberg * NOTE NOTE NOTE! Functions 0x0b and 0x0d seem to need special 90*a1fe6bc5SPekka Enberg * treatment as per qemu sources but we treat them as regular 91*a1fe6bc5SPekka Enberg * CPUID functions here because they are fairly exotic and the 92*a1fe6bc5SPekka Enberg * Linux kernel is not interested in them during boot up. 93*a1fe6bc5SPekka Enberg */ 94*a1fe6bc5SPekka Enberg switch (function) { 95*a1fe6bc5SPekka Enberg case 0x02: { /* Processor configuration descriptor */ 96*a1fe6bc5SPekka Enberg struct cpuid_regs regs; 97*a1fe6bc5SPekka Enberg uint32_t times; 98*a1fe6bc5SPekka Enberg 99*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 100*a1fe6bc5SPekka Enberg .eax = function, 101*a1fe6bc5SPekka Enberg }; 102*a1fe6bc5SPekka Enberg cpuid(®s); 103*a1fe6bc5SPekka Enberg 104*a1fe6bc5SPekka Enberg kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) { 105*a1fe6bc5SPekka Enberg .function = function, 106*a1fe6bc5SPekka Enberg .index = 0, 107*a1fe6bc5SPekka Enberg .flags = KVM_CPUID_FLAG_STATEFUL_FUNC | KVM_CPUID_FLAG_STATE_READ_NEXT, 108*a1fe6bc5SPekka Enberg .eax = regs.eax, 109*a1fe6bc5SPekka Enberg .ebx = regs.ebx, 110*a1fe6bc5SPekka Enberg .ecx = regs.ecx, 111*a1fe6bc5SPekka Enberg .edx = regs.edx, 112*a1fe6bc5SPekka Enberg }; 113*a1fe6bc5SPekka Enberg 114*a1fe6bc5SPekka Enberg times = regs.eax & 0xff; /* AL */ 115*a1fe6bc5SPekka Enberg 116*a1fe6bc5SPekka Enberg while (times-- > 0) { 117*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 118*a1fe6bc5SPekka Enberg .eax = function, 119*a1fe6bc5SPekka Enberg }; 120*a1fe6bc5SPekka Enberg cpuid(®s); 121*a1fe6bc5SPekka Enberg 122*a1fe6bc5SPekka Enberg kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) { 123*a1fe6bc5SPekka Enberg .function = function, 124*a1fe6bc5SPekka Enberg .index = 0, 125*a1fe6bc5SPekka Enberg .flags = KVM_CPUID_FLAG_STATEFUL_FUNC, 126*a1fe6bc5SPekka Enberg .eax = regs.eax, 127*a1fe6bc5SPekka Enberg .ebx = regs.ebx, 128*a1fe6bc5SPekka Enberg .ecx = regs.ecx, 129*a1fe6bc5SPekka Enberg .edx = regs.edx, 130*a1fe6bc5SPekka Enberg }; 131*a1fe6bc5SPekka Enberg } 132*a1fe6bc5SPekka Enberg break; 133*a1fe6bc5SPekka Enberg } 134*a1fe6bc5SPekka Enberg case 0x04: { 135*a1fe6bc5SPekka Enberg uint32_t index; 136*a1fe6bc5SPekka Enberg 137*a1fe6bc5SPekka Enberg for (index = 0; index < 2; index++) { 138*a1fe6bc5SPekka Enberg struct cpuid_regs regs = { 139*a1fe6bc5SPekka Enberg .eax = function, 140*a1fe6bc5SPekka Enberg .ecx = index, 141*a1fe6bc5SPekka Enberg }; 142*a1fe6bc5SPekka Enberg cpuid(®s); 143*a1fe6bc5SPekka Enberg 144*a1fe6bc5SPekka Enberg kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) { 145*a1fe6bc5SPekka Enberg .function = function, 146*a1fe6bc5SPekka Enberg .index = index, 147*a1fe6bc5SPekka Enberg .flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX, 148*a1fe6bc5SPekka Enberg .eax = regs.eax, 149*a1fe6bc5SPekka Enberg .ebx = regs.ebx, 150*a1fe6bc5SPekka Enberg .ecx = regs.ecx, 151*a1fe6bc5SPekka Enberg .edx = regs.edx, 152*a1fe6bc5SPekka Enberg }; 153*a1fe6bc5SPekka Enberg } 154*a1fe6bc5SPekka Enberg break; 155*a1fe6bc5SPekka Enberg } 156*a1fe6bc5SPekka Enberg default: { 157*a1fe6bc5SPekka Enberg struct cpuid_regs regs; 158*a1fe6bc5SPekka Enberg 159*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 160*a1fe6bc5SPekka Enberg .eax = function, 161*a1fe6bc5SPekka Enberg }; 162*a1fe6bc5SPekka Enberg cpuid(®s); 163*a1fe6bc5SPekka Enberg 164*a1fe6bc5SPekka Enberg kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) { 165*a1fe6bc5SPekka Enberg .function = function, 166*a1fe6bc5SPekka Enberg .index = 0, 167*a1fe6bc5SPekka Enberg .flags = 0, 168*a1fe6bc5SPekka Enberg .eax = regs.eax, 169*a1fe6bc5SPekka Enberg .ebx = regs.ebx, 170*a1fe6bc5SPekka Enberg .ecx = regs.ecx, 171*a1fe6bc5SPekka Enberg .edx = regs.edx, 172*a1fe6bc5SPekka Enberg }; 173*a1fe6bc5SPekka Enberg break; 174*a1fe6bc5SPekka Enberg }}; 175*a1fe6bc5SPekka Enberg } 176*a1fe6bc5SPekka Enberg 177*a1fe6bc5SPekka Enberg highest_ext = cpuid_highest_ext_func(); 178*a1fe6bc5SPekka Enberg 179*a1fe6bc5SPekka Enberg for (function = CPUID_GET_HIGHEST_EXT_FUNCTION; function < highest_ext; function++) { 180*a1fe6bc5SPekka Enberg struct cpuid_regs regs; 181*a1fe6bc5SPekka Enberg 182*a1fe6bc5SPekka Enberg regs = (struct cpuid_regs) { 183*a1fe6bc5SPekka Enberg .eax = function, 184*a1fe6bc5SPekka Enberg }; 185*a1fe6bc5SPekka Enberg cpuid(®s); 186*a1fe6bc5SPekka Enberg 187*a1fe6bc5SPekka Enberg kvm_cpuid->entries[ndx++] = (struct kvm_cpuid_entry2) { 188*a1fe6bc5SPekka Enberg .function = function, 189*a1fe6bc5SPekka Enberg .index = 0, 190*a1fe6bc5SPekka Enberg .flags = 0, 191*a1fe6bc5SPekka Enberg .eax = regs.eax, 192*a1fe6bc5SPekka Enberg .ebx = regs.ebx, 193*a1fe6bc5SPekka Enberg .ecx = regs.ecx, 194*a1fe6bc5SPekka Enberg .edx = regs.edx, 195*a1fe6bc5SPekka Enberg }; 196*a1fe6bc5SPekka Enberg } 197*a1fe6bc5SPekka Enberg 198*a1fe6bc5SPekka Enberg assert(ndx < MAX_KVM_CPUID_ENTRIES); 199*a1fe6bc5SPekka Enberg 200*a1fe6bc5SPekka Enberg kvm_cpuid->nent = ndx; 201*a1fe6bc5SPekka Enberg 202*a1fe6bc5SPekka Enberg if (ioctl(self->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0) 203*a1fe6bc5SPekka Enberg die_perror("KVM_SET_CPUID2 failed"); 204*a1fe6bc5SPekka Enberg 205*a1fe6bc5SPekka Enberg kvm_cpuid__delete(kvm_cpuid); 206*a1fe6bc5SPekka Enberg } 207