Dan Kenigsberg wrote: > These patches expose host CPU features (that are known to work under > KVM) to guests. It makes a couple of benchmarks run faster, and > generally gives kvm's user better info on its host. > > The kernel-space patch adds KVM_GET_SUPPORTED_CPUID ioctl to obtain the > table of cpuid functions supported by the host. The user-space patch > allows fine-tuning this table from the command-line. > > I had to define struct kvm_cpuid2, KVM_SET_CPUID2 etc., because cpuid > functions are a little more complex than just function-value pairs. > > commit e9775d0a16097cfb71779cb2fb985fb3e5040dc8 > Author: Dan Kenigsberg <[EMAIL PROTECTED]> > Date: Sun Nov 18 13:55:26 2007 +0200 > > Support -cpu host option. Negotiate cpuid table with userspace. >
The kernel doesn't have a -cpu option. The description needs to be more descriptive (motivation, special cases in cpuid). > > > +static int is_efer_nx(void) { > + u64 efer; > blank line > + rdmsrl(MSR_EFER, efer); > + return efer & EFER_NX; > +} > + > > > +static int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu, > + struct kvm_cpuid2 *cpuid, > + struct kvm_cpuid_entry2 __user *entries) > +{ > + int r; > + > + r = -E2BIG; > + if (cpuid->nent < vcpu->cpuid_nent) > + goto out; > + r = -EFAULT; > + if (copy_to_user(entries, &vcpu->cpuid_entries, > + vcpu->cpuid_nent * sizeof(struct kvm_cpuid_entry2))) > + goto out; > + return 0; > + > +out: > + cpuid->nent = vcpu->cpuid_nent; > whitespace damage here > + return r; > + > +static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, > + u32 index, int *nent, int maxnent) > +{ > + const __u32 kvm_supported_word0_x86_features = bit(X86_FEATURE_FPU) | > + bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | > + bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | > + bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | > + bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | > + bit(X86_FEATURE_SEP) | bit(X86_FEATURE_PGE) | > + bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | > + bit(X86_FEATURE_CLFLSH) | bit(X86_FEATURE_MMX) | > + bit(X86_FEATURE_FXSR) | bit(X86_FEATURE_XMM) | > + bit(X86_FEATURE_XMM2) | bit(X86_FEATURE_SELFSNOOP); > u32, not __u32. > + const __u32 kvm_supported_word1_x86_features = bit(X86_FEATURE_FPU) | > + bit(X86_FEATURE_VME) | bit(X86_FEATURE_DE) | > + bit(X86_FEATURE_PSE) | bit(X86_FEATURE_TSC) | > + bit(X86_FEATURE_MSR) | bit(X86_FEATURE_PAE) | > + bit(X86_FEATURE_CX8) | bit(X86_FEATURE_APIC) | > + bit(X86_FEATURE_PGE) | > + bit(X86_FEATURE_CMOV) | bit(X86_FEATURE_PSE36) | > + bit(X86_FEATURE_MMX) | bit(X86_FEATURE_FXSR) | > + bit(X86_FEATURE_SYSCALL) | > + (bit(X86_FEATURE_NX) && is_efer_nx()) | > +#ifdef CONFIG_X86_64 > + bit(X86_FEATURE_LM) | > +#endif > + /* TODO: make sure the following features are > + * safe for SVM guests */ > + bit(X86_FEATURE_MMXEXT) | > + bit(X86_FEATURE_RDTSCP) | bit(X86_FEATURE_3DNOWEXT) | > + bit(X86_FEATURE_3DNOW); > rdtscp isn't, I believe. > + const __u32 kvm_supported_word3_x86_features = > + bit(X86_FEATURE_XMM3) | bit(X86_FEATURE_CX16); > + const __u32 kvm_supported_word6_x86_features = > + bit(X86_FEATURE_LAHF_LM) | bit(X86_FEATURE_CMP_LEGACY); > + > + /* all func 2 cpuid_count() should be called on the same cpu */ > + if (function==2) > + get_cpu(); > Avoid the special case, just to it unconditionally. > + do_cpuid_1_ent(entry, function, index); > + ++*nent; > + > + switch (function) { > + case 0: > + entry->eax = min(entry->eax, (u32)0xb); > + break; > + case 1: > + entry->edx &= kvm_supported_word0_x86_features; > + entry->ecx &= kvm_supported_word3_x86_features; > + break; > + /* function 2 entries are STATEFUL. That is, repeated cpuid commands > + * may return different values. This forces us to get_cpu() before > + * issuing the first command, and also to emulate this annoying behavior > + * in kvm_emulate_cpuid() using KVM_CPUID_FLAG_STATE_READ_NEXT */ > + case 2: { > + int t, times = entry->eax & 0xff; > Indent this normally relative to other entries. > + > + entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; > + for (t = 1; t < times && *nent < maxnent; ++t) { > + do_cpuid_1_ent(&entry[t], function, 0); > + entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; > + ++*nent; > + } > + break; > + } > + /* function 4 and 0xb have additional index. */ > + case 4: { > + int index, cache_type; > + > + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; > + /* read more entries until cache_type is zero */ > + for (index = 1; *nent < maxnent; ++index) { > + cache_type = entry[index - 1].eax & 0x1f; > + if (!cache_type) > + break; > + do_cpuid_1_ent(&entry[index], function, index); > + entry[index].flags |= > + KVM_CPUID_FLAG_SIGNIFCANT_INDEX; > + ++*nent; > + } > + break; > + } > + case 0xb: { > + int index, level_type; > + > + entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; > + /* read more entries until level_type is zero */ > + for (index = 1; *nent < maxnent; ++index) { > + level_type = entry[index - 1].ecx & 0xff; > + if (!level_type) > + break; > + do_cpuid_1_ent(&entry[index], function, index); > + entry[index].flags |= > + KVM_CPUID_FLAG_SIGNIFCANT_INDEX; > + ++*nent; > + } > + break; > + } > + case 0x80000000: > + entry->eax = min(entry->eax, 0x8000001a); > + break; > + case 0x80000001: > + entry->edx &= kvm_supported_word1_x86_features; > + entry->ecx &= kvm_supported_word6_x86_features; > + break; > + } > + if (function==2) > + put_cpu(); > +} > + > +static int kvm_vm_ioctl_get_supported_cpuid(struct kvm *kvm, > + struct kvm_cpuid2 *cpuid, > + struct kvm_cpuid_entry2 __user *entries) > +{ > + struct kvm_cpuid_entry2 *cpuid_entries; > + int limit, nent = 0, r = -E2BIG; > + u32 func whitespace damage > ; > + > + if (cpuid->nent < 1) > + goto out; > + r = -ENOMEM; > + cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); > + if (!cpuid_entries) > + goto out; > + > + do_cpuid_ent(&cpuid_entries[0], 0, 0, &nent, cpuid->nent); > + limit = cpuid_entries[0].eax; > + for (func = 1; func <= limit && nent < cpuid->nent; ++func) > + do_cpuid_ent(&cpuid_entries[nent], func, 0, > + &nent, cpuid->nent); > + > + if (nent >= cpuid->nent) > + goto out_free; > Should exit with an E2BIG here. ENOMEM means kernel's out of memory, which isn't the case here. > + do_cpuid_ent(&cpuid_entries[nent], 0x80000000, 0, &nent, cpuid->nent); > + limit = cpuid_entries[nent - 1].eax; > + for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func) > + do_cpuid_ent(&cpuid_entries[nent], func, 0, > + &nent, cpuid->nent); > + r = -EFAULT; > + if (copy_to_user(entries, cpuid_entries, > + nent * sizeof(struct kvm_cpuid_entry2))) > + goto out_free; > + cpuid->nent = nent; > + r = 0; > + > +out_free: > + vfree(cpuid_entries); > +out: > + return r; > +} > + > static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, > struct kvm_lapic_state *s) > { > @@ -796,6 +1027,36 @@ long kvm_arch_vcpu_ioctl(struct file *filp, > goto out; > break; > } > + case KVM_SET_CPUID2: { > + struct kvm_cpuid2 __user *cpuid_arg = argp; > + struct kvm_cpuid2 cpuid; > + > + r = -EFAULT; > + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) > + goto out; > + r = kvm_vcpu_ioctl_set_cpuid2(vcpu, &cpuid, > + cpuid_arg->entries); > + if (r) > + goto out; > + break; > + } > + case KVM_GET_CPUID2: { > + struct kvm_cpuid2 __user *cpuid_arg = argp; > + struct kvm_cpuid2 cpuid; > + > + r = -EFAULT; > + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) > + goto out; > + r = kvm_vcpu_ioctl_get_cpuid2(vcpu, &cpuid, > + cpuid_arg->entries); > + if (r) > + goto out; > + r = -EFAULT; > + if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid)) > + goto out; > + r = 0; > + break; > + } > case KVM_GET_MSRS: > r = msr_io(vcpu, argp, kvm_get_msr, 1); > break; > @@ -1091,6 +1352,24 @@ long kvm_arch_vm_ioctl(struct file *filp, > r = 0; > break; > } > + case KVM_GET_SUPPORTED_CPUID: { > + struct kvm_cpuid2 __user *cpuid_arg = argp; > + struct kvm_cpuid2 cpuid; > + > + r = -EFAULT; > + if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) > + goto out; > + r = kvm_vm_ioctl_get_supported_cpuid(kvm, &cpuid, > + cpuid_arg->entries); > + if (r) > + goto out; > + > + r = -EFAULT; > + if (copy_to_user(cpuid_arg, &cpuid, sizeof cpuid)) > + goto out; > + r = 0; > + break; > + } > default: > ; > } > @@ -1887,14 +2166,33 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, > unsigned long val, > } > } > > +static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i) > +{ > + struct kvm_cpuid_entry2 *e = &vcpu->cpuid_entries[i]; > + int j, nent = vcpu->cpuid_nent; > + > + e->flags &= ~KVM_CPUID_FLAG_STATE_READ_NEXT; > + /* when no next entry is found, the current entry[i] is reselected */ > + for (j = i + 1; j == i; j = (j + 1) % nent) { > + struct kvm_cpuid_entry2 *ej = > + &vcpu->cpuid_entries[j]; > 80 column limit, not 40. > + if (ej->function == e->function) { > + ej->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; > + return j; > + } > + } > + return 0; /* silence gcc, even though control never reaches here */ > +} > + > void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) > { > int i; > - u32 function; > - struct kvm_cpuid_entry *e, *best; > + u32 function, index; > + struct kvm_cpuid_entry2 *e, *best; > > kvm_x86_ops->cache_regs(vcpu); > function = vcpu->regs[VCPU_REGS_RAX]; > + index = vcpu->regs[VCPU_REGS_RCX]; > vcpu->regs[VCPU_REGS_RAX] = 0; > vcpu->regs[VCPU_REGS_RBX] = 0; > vcpu->regs[VCPU_REGS_RCX] = 0; > @@ -1902,7 +2200,15 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) > best = NULL; > for (i = 0; i < vcpu->cpuid_nent; ++i) { > e = &vcpu->cpuid_entries[i]; > - if (e->function == function) { > + /* find an entry with matching function, matching index (if > + * needed), and that should be read next (if it's stateful) */ > + if (e->function == function && > + (!(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) > + || e->index == index) && > + (!(e->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) > + || (e->flags & KVM_CPUID_FLAG_STATE_READ_NEXT) )) { > + if (e->flags & KVM_CPUID_FLAG_STATEFUL_FUNC) > + move_to_next_stateful_cpuid_entry(vcpu, i); > best = e; > Please move this to a function with multiple if ()s and return statements. > ------------------------------------------------------------------------ > > commit e5a590065ab37fb5eb0481e176d455fba98310dd > Author: Dan Kenigsberg <[EMAIL PROTECTED]> > Date: Sun Nov 18 13:36:41 2007 +0200 > > Add -cpu host option. Negotiate cpuid table with kernel. > > Signed-off-by: Dan Kenigsberg <[EMAIL PROTECTED]> > > diff --git a/kernel/external-module-compat.h b/kernel/external-module-compat.h > index e3f81fe..ef5d70b 100644 > --- a/kernel/external-module-compat.h > +++ b/kernel/external-module-compat.h > @@ -530,14 +530,6 @@ out: > #define dest_ExtINT 7 > #endif > > -/* empty_zero_page isn't exported in all kernels */ > -#include <asm/pgtable.h> > - > -#define empty_zero_page kvm_empty_zero_page > - > -static char empty_zero_page[PAGE_SIZE]; > - > -static inline void blahblah(void) > -{ > - (void)empty_zero_page[0]; > -} > Remove this removal. > > +int kvm_get_supported_cpuid(kvm_context_t kvm, int *nent, > + struct kvm_cpuid_entry2 *entries) > +{ > + struct kvm_cpuid2 *cpuid; > + int r = -1; > blank line. > +#ifdef KVM_CAP_EXT_CPUID > + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_EXT_CPUID); > + if (!r) > + return -1; > return -errno on errors > + > + cpuid = malloc(sizeof(*cpuid) + *nent * sizeof(*entries)); > + if (!cpuid) > + return -ENOMEM; > + cpuid->nent = *nent; > + > + r = ioctl(kvm->vm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); > + > error check > + memcpy(entries, cpuid->entries, *nent * sizeof(*entries)); > + *nent = cpuid->nent; > + free(cpuid); > +#endif > + return r; > +} > + > +int kvm_get_cpuid(kvm_context_t kvm, int vcpu, int *nent, > + struct kvm_cpuid_entry2 *entries) > +{ > + struct kvm_cpuid2 *cpuid; > + int r = -1; > blank line > +#ifdef KVM_CAP_EXT_CPUID > + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_EXT_CPUID); > + if (!r) > + return -1; > -errno > + > + cpuid = malloc(sizeof(*cpuid) + *nent * sizeof(*entries)); > + if (!cpuid) > + return -ENOMEM; > + cpuid->nent = *nent; > + > + r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_CPUID2, cpuid); > + > error check > + memcpy(entries, cpuid->entries, *nent * sizeof(*entries)); > + *nent = cpuid->nent; > + free(cpuid); > +#endif > + return r; > +} > + > -- error compiling committee.c: too many arguments to function ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel