diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2012-01-23 11:00:26 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-01-23 11:00:26 -0600 |
commit | 5b4448d27d7c6ff6e18a1edc8245cb1db783e37c (patch) | |
tree | a3b896984ff6ae566892eb198e5b34b197288194 /target-i386 | |
parent | c4ccbeaca521bdbf5cb8db37dc67c47e1add0586 (diff) | |
parent | 6a48ffaaa732b2142c1b5030178f2d4a0fa499fe (diff) | |
download | qemu-5b4448d27d7c6ff6e18a1edc8245cb1db783e37c.zip qemu-5b4448d27d7c6ff6e18a1edc8245cb1db783e37c.tar.gz qemu-5b4448d27d7c6ff6e18a1edc8245cb1db783e37c.tar.bz2 |
Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
* qemu-kvm/uq/master:
kvm: Activate in-kernel irqchip support
kvm: x86: Add user space part for in-kernel IOAPIC
kvm: x86: Add user space part for in-kernel i8259
kvm: x86: Add user space part for in-kernel APIC
kvm: x86: Establish IRQ0 override control
kvm: Introduce core services for in-kernel irqchip support
memory: Introduce memory_region_init_reservation
ioapic: Factor out base class for KVM reuse
ioapic: Drop post-load irr initialization
i8259: Factor out base class for KVM reuse
i8259: Completely privatize PicState
apic: Open-code timer save/restore
apic: Factor out base class for KVM reuse
apic: Introduce apic_report_irq_delivered
apic: Inject external NMI events via LINT1
apic: Stop timer on reset
kvm: Move kvmclock into hw/kvm folder
msi: Generalize msix_supported to msi_supported
hyper-v: initialize Hyper-V CPUID leaves.
hyper-v: introduce Hyper-V support infrastructure.
Conflicts:
Makefile.target
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/cpuid.c | 14 | ||||
-rw-r--r-- | target-i386/hyperv.c | 64 | ||||
-rw-r--r-- | target-i386/hyperv.h | 43 | ||||
-rw-r--r-- | target-i386/kvm.c | 114 |
4 files changed, 233 insertions, 2 deletions
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 91a104b..b9bfeaf 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -27,6 +27,8 @@ #include "qemu-option.h" #include "qemu-config.h" +#include "hyperv.h" + /* feature flags taken from "Intel Processor Identification and the CPUID * Instruction" and AMD's "CPUID Specification". In cases of disagreement * between feature naming conventions, aliases may be added. @@ -716,6 +718,14 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) goto error; } x86_cpu_def->tsc_khz = tsc_freq / 1000; + } else if (!strcmp(featurestr, "hv_spinlocks")) { + char *err; + numvalue = strtoul(val, &err, 0); + if (!*val || *err) { + fprintf(stderr, "bad numerical value %s\n", val); + goto error; + } + hyperv_set_spinlock_retries(numvalue); } else { fprintf(stderr, "unrecognized feature %s\n", featurestr); goto error; @@ -724,6 +734,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) check_cpuid = 1; } else if (!strcmp(featurestr, "enforce")) { check_cpuid = enforce_cpuid = 1; + } else if (!strcmp(featurestr, "hv_relaxed")) { + hyperv_enable_relaxed_timing(true); + } else if (!strcmp(featurestr, "hv_vapic")) { + hyperv_enable_vapic_recommended(true); } else { fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); goto error; diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c new file mode 100644 index 0000000..f284e99 --- /dev/null +++ b/target-i386/hyperv.c @@ -0,0 +1,64 @@ +/* + * QEMU Hyper-V support + * + * Copyright Red Hat, Inc. 2011 + * + * Author: Vadim Rozenfeld <vrozenfe@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hyperv.h" + +static bool hyperv_vapic; +static bool hyperv_relaxed_timing; +static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; + +void hyperv_enable_vapic_recommended(bool val) +{ + hyperv_vapic = val; +} + +void hyperv_enable_relaxed_timing(bool val) +{ + hyperv_relaxed_timing = val; +} + +void hyperv_set_spinlock_retries(int val) +{ + hyperv_spinlock_attempts = val; + if (hyperv_spinlock_attempts < 0xFFF) { + hyperv_spinlock_attempts = 0xFFF; + } +} + +bool hyperv_enabled(void) +{ + return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled(); +} + +bool hyperv_hypercall_available(void) +{ + if (hyperv_vapic || + (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) { + return true; + } + return false; +} + +bool hyperv_vapic_recommended(void) +{ + return hyperv_vapic; +} + +bool hyperv_relaxed_timing_enabled(void) +{ + return hyperv_relaxed_timing; +} + +int hyperv_get_spinlock_retries(void) +{ + return hyperv_spinlock_attempts; +} diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h new file mode 100644 index 0000000..15467bf --- /dev/null +++ b/target-i386/hyperv.h @@ -0,0 +1,43 @@ +/* + * QEMU Hyper-V support + * + * Copyright Red Hat, Inc. 2011 + * + * Author: Vadim Rozenfeld <vrozenfe@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_HW_HYPERV_H +#define QEMU_HW_HYPERV_H 1 + +#include "qemu-common.h" +#include <asm/hyperv.h> + +#ifndef HYPERV_SPINLOCK_NEVER_RETRY +#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF +#endif + +#ifndef KVM_CPUID_SIGNATURE_NEXT +#define KVM_CPUID_SIGNATURE_NEXT 0x40000100 +#endif + +#ifndef CONFIG_USER_ONLY +void hyperv_enable_vapic_recommended(bool val); +void hyperv_enable_relaxed_timing(bool val); +void hyperv_set_spinlock_retries(int val); +#else +static inline void hyperv_enable_vapic_recommended(bool val) { } +static inline void hyperv_enable_relaxed_timing(bool val) { } +static inline void hyperv_set_spinlock_retries(int val) { } +#endif + +bool hyperv_enabled(void); +bool hyperv_hypercall_available(void); +bool hyperv_vapic_recommended(void); +bool hyperv_relaxed_timing_enabled(void); +int hyperv_get_spinlock_retries(void); + +#endif /* QEMU_HW_HYPERV_H */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 04e65c5..e41de39 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -29,6 +29,7 @@ #include "hw/pc.h" #include "hw/apic.h" #include "ioport.h" +#include "hyperv.h" //#define DEBUG_KVM @@ -373,11 +374,16 @@ int kvm_arch_init_vcpu(CPUState *env) cpuid_i = 0; /* Paravirtualization CPUIDs */ - memcpy(signature, "KVMKVMKVM\0\0\0", 12); c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_SIGNATURE; - c->eax = 0; + if (!hyperv_enabled()) { + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + c->eax = 0; + } else { + memcpy(signature, "Microsoft Hv", 12); + c->eax = HYPERV_CPUID_MIN; + } c->ebx = signature[0]; c->ecx = signature[1]; c->edx = signature[2]; @@ -388,6 +394,54 @@ int kvm_arch_init_vcpu(CPUState *env) c->eax = env->cpuid_kvm_features & kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX); + if (hyperv_enabled()) { + memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); + c->eax = signature[0]; + + c = &cpuid_data.entries[cpuid_i++]; + memset(c, 0, sizeof(*c)); + c->function = HYPERV_CPUID_VERSION; + c->eax = 0x00001bbc; + c->ebx = 0x00060001; + + c = &cpuid_data.entries[cpuid_i++]; + memset(c, 0, sizeof(*c)); + c->function = HYPERV_CPUID_FEATURES; + if (hyperv_relaxed_timing_enabled()) { + c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; + } + if (hyperv_vapic_recommended()) { + c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; + c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; + } + + c = &cpuid_data.entries[cpuid_i++]; + memset(c, 0, sizeof(*c)); + c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; + if (hyperv_relaxed_timing_enabled()) { + c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; + } + if (hyperv_vapic_recommended()) { + c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; + } + c->ebx = hyperv_get_spinlock_retries(); + + c = &cpuid_data.entries[cpuid_i++]; + memset(c, 0, sizeof(*c)); + c->function = HYPERV_CPUID_IMPLEMENT_LIMITS; + c->eax = 0x40; + c->ebx = 0x40; + + c = &cpuid_data.entries[cpuid_i++]; + memset(c, 0, sizeof(*c)); + c->function = KVM_CPUID_SIGNATURE_NEXT; + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + c->eax = 0; + c->ebx = signature[0]; + c->ecx = signature[1]; + c->edx = signature[2]; + } + has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); @@ -933,6 +987,13 @@ static int kvm_put_msrs(CPUState *env, int level) kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN, env->async_pf_en_msr); } + if (hyperv_hypercall_available()) { + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0); + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0); + } + if (hyperv_vapic_recommended()) { + kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0); + } } if (env->mcg_cap) { int i; @@ -1276,6 +1337,36 @@ static int kvm_get_mp_state(CPUState *env) return 0; } +static int kvm_get_apic(CPUState *env) +{ + DeviceState *apic = env->apic_state; + struct kvm_lapic_state kapic; + int ret; + + if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) { + ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic); + if (ret < 0) { + return ret; + } + + kvm_get_apic_state(apic, &kapic); + } + return 0; +} + +static int kvm_put_apic(CPUState *env) +{ + DeviceState *apic = env->apic_state; + struct kvm_lapic_state kapic; + + if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_put_apic_state(apic, &kapic); + + return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic); + } + return 0; +} + static int kvm_put_vcpu_events(CPUState *env, int level) { struct kvm_vcpu_events events; @@ -1449,6 +1540,10 @@ int kvm_arch_put_registers(CPUState *env, int level) if (ret < 0) { return ret; } + ret = kvm_put_apic(env); + if (ret < 0) { + return ret; + } } ret = kvm_put_vcpu_events(env, level); if (ret < 0) { @@ -1496,6 +1591,10 @@ int kvm_arch_get_registers(CPUState *env) if (ret < 0) { return ret; } + ret = kvm_get_apic(env); + if (ret < 0) { + return ret; + } ret = kvm_get_vcpu_events(env); if (ret < 0) { return ret; @@ -1878,3 +1977,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env) return !(env->cr[0] & CR0_PE_MASK) || ((env->segs[R_CS].selector & 3) != 3); } + +void kvm_arch_init_irq_routing(KVMState *s) +{ + if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { + /* If kernel can't do irq routing, interrupt source + * override 0->2 cannot be set up as required by HPET. + * So we have to disable it. + */ + no_hpet = 1; + } +} |