How to Emulate CPUID in a KVM VM

How to Emulate CPUID in a KVM VM

hackernoon.com hackernoon.com2 weeks ago in #Dev Love24

For most workloads it will be necessary to determine characteristics of CPU on which they are run. Most processors have some way of querying capabilities. x86 CPU uses CPUID instruction. Unfortunately you cannot just start a VM and then execute the CPUID instruction. The program will not crash but you will not get useful information either. The reason for this is that sometimes we’d like to tell guests what is available and what is not available for use. At this point we will go with a simple approach – we will let our guest OS do whatever KVM features are available. KVM has an ioctl to do that – KVM_GET_SUPPORTED_CPUID . It also has KVM_SET_CPUID2 that defines vCPU response to CPUID instruction. Before we can make a call to KVM_GET_SUPPORTED_CPUID we need to create kvm_cpuid2 structure and allocate enough space for it. The kvm_cpuid2 structure is defined as follows: struct kvm_cpuid2 { __u32 nent; __u32 padding; struct kvm_cpuid_entry2 entries[0]; }; struct kvm_cpuid_entry2 { __u32 function; __u32 index; __u32 flags; __u32 eax; __u32 ebx; __u32 ecx; __u32 edx; __u32 padding[3]; }; You can see that it has two elements but it also has a trailing array. The way we allocate memory for this type of structure is sizeof(kvm_cpuid2) number_of_entries * sizeof(kvm_cpuid_entry2) ← pseudo-code ⚠️ Following is piece of code that allocates memory for kvm_cpuid2 structure and uses KVM_GET_SUPPORTED_CPUID to populate it. struct kvm_cpuid2 *cpuid; int nent = 40; unsigned long size = sizeof(*cpuid) nent * sizeof(*cpuid-entries); cpuid = (struct kvm_cpuid2*) malloc(size); bzero(cpuid, size); cpuid-nent = nent; if(ioctl(kvm, KVM_GET_SUPPORTED_CPUID, cpuid) == -1) { printf(“KVM_GET_SUPPORTED_CPUID could not read CPUID info. Error code: %dn”, ret); return -1; } Now it can be useful to print out all the available options that KVM has reported. It could be useful to know this once the vCPU starts. for(int i = 0; i < cpuid->nent; i ) { printf(“F: 0xx, idx: 0xx, flags: 0xx, eax: 0xx, ebx: 0xx, ecx: 0xx, edx: 0xxn”, cpuid-entries[i].function, cpuid-entries[i].index, cpuid-entries[i].flags, cpuid-entries[i].eax, cpuid-entries[i].ebx, cpuid-entries[i].ecx, cpuid-entries[i].edx); } Now we can use our pointer to cpuid structure to configure vCPU. if(ioctl(vcpufd, KVM_SET_CPUID2, cpuid) == -1) { printf(“KVM_SET_CPUID2 could not set CPUID info. Error code: %dn”, ret); return -1; } And that is it! Now you can execute CPUID instruction on your vCPU and get correct results. See you next time when we will start working on enabling paging on our x86 CPU 👋 📖 Resources: https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt Tags Subscribe to get your daily round-up of top tech stories!  » Read More

Like to keep reading?

This article first appeared on hackernoon.com. If you'd like to keep reading, follow the white rabbit.

View Full Article

Leave a Reply