From patchwork Fri Jun 24 10:49:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev" X-Patchwork-Id: 9197305 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BC79C60754 for ; Fri, 24 Jun 2016 10:50:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC79327BE5 for ; Fri, 24 Jun 2016 10:50:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A133F28464; Fri, 24 Jun 2016 10:50:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id AE9BB27BE5 for ; Fri, 24 Jun 2016 10:50:22 +0000 (UTC) Received: from localhost ([::1]:42591 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGOgn-0001rL-Vt for patchwork-qemu-devel@patchwork.kernel.org; Fri, 24 Jun 2016 06:50:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43448) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGOgY-0001o7-2S for qemu-devel@nongnu.org; Fri, 24 Jun 2016 06:50:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bGOgU-0001H4-Np for qemu-devel@nongnu.org; Fri, 24 Jun 2016 06:50:06 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:48743 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGOgU-00018d-5z for qemu-devel@nongnu.org; Fri, 24 Jun 2016 06:50:02 -0400 Received: from irbis.sw.ru ([10.30.2.139]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u5OAnaU4021332; Fri, 24 Jun 2016 13:49:37 +0300 (MSK) From: "Denis V. Lunev" To: qemu-devel@nongnu.org Date: Fri, 24 Jun 2016 13:49:36 +0300 Message-Id: <1466765376-25722-1-git-send-email-den@openvz.org> X-Mailer: git-send-email 2.1.4 X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH v3 1/1] cpu: report hyperv feature words through qom X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Evgeny Yakovlev , Eduardo Habkost , Marcelo Tosatti , Paolo Bonzini , den@openvz.org, Richard Henderson Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Evgeny Yakovlev This change adds hyperv feature words report through qom rpc. When VM is configured with hyperv features enabled libvirt will check that required feature words are set in cpuid leaf 40000003 through qom request. Currently qemu does not report hyperv feature words which prevents windows guests from starting with libvirt. To avoid conflicting with current hyperv properties all added feature words cannot be set directly with -cpu +feature yet. Signed-off-by: Evgeny Yakovlev Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Richard Henderson CC: Eduardo Habkost CC: Marcelo Tosatti --- Changes from v2: - removed all hyperv feature_names so that we don't have two ways of setting CPUID bits Changes from v1: - renamed hyperv features so they don't conflict with hyperv properties - refactored kvm_arch_init_vcpu to process hyperv props into feature words target-i386/cpu.c | 53 +++++++++++++++++++++++++ target-i386/cpu.h | 3 ++ target-i386/kvm.c | 114 +++++++++++++++++++++++++++++++----------------------- 3 files changed, 122 insertions(+), 48 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3bd3cfc..d07da78 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -245,6 +245,47 @@ static const char *kvm_feature_name[] = { NULL, NULL, NULL, NULL, }; +static const char *hyperv_priv_feature_name[] = { + NULL /* hv_msr_vp_runtime_access */, NULL /* hv_msr_time_refcount_access */, + NULL /* hv_msr_synic_access */, NULL /* hv_msr_stimer_access */, + NULL /* hv_msr_apic_access */, NULL /* hv_msr_hypercall_access */, + NULL /* hv_vpindex_access */, NULL /* hv_msr_reset_access */, + NULL /* hv_msr_stats_access */, NULL /* hv_reftsc_access */, + NULL /* hv_msr_idle_access */, NULL /* hv_msr_frequency_access */, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_ident_feature_name[] = { + NULL /* hv_create_partitions */, NULL /* hv_access_partition_id */, + NULL /* hv_access_memory_pool */, NULL /* hv_adjust_message_buffers */, + NULL /* hv_post_messages */, NULL /* hv_signal_events */, + NULL /* hv_create_port */, NULL /* hv_connect_port */, + NULL /* hv_access_stats */, NULL, NULL, NULL /* hv_debugging */, + NULL /* hv_cpu_power_management */, NULL /* hv_configure_profiler */, + NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + +static const char *hyperv_misc_feature_name[] = { + NULL /* hv_mwait */, NULL /* hv_guest_debugging */, + NULL /* hv_perf_monitor */, NULL /* hv_cpu_dynamic_part */, + NULL /* hv_hypercall_params_xmm */, NULL /* hv_guest_idle_state */, + NULL, NULL, + NULL, NULL, NULL /* hv_guest_crash_msr */, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + static const char *svm_feature_name[] = { "npt", "lbrv", "svm_lock", "nrip_save", "tsc_scale", "vmcb_clean", "flushbyasid", "decodeassists", @@ -411,6 +452,18 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, .tcg_features = TCG_KVM_FEATURES, }, + [FEAT_HYPERV_EAX] = { + .feat_names = hyperv_priv_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EAX, + }, + [FEAT_HYPERV_EBX] = { + .feat_names = hyperv_ident_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EBX, + }, + [FEAT_HYPERV_EDX] = { + .feat_names = hyperv_misc_feature_name, + .cpuid_eax = 0x40000003, .cpuid_reg = R_EDX, + }, [FEAT_SVM] = { .feat_names = svm_feature_name, .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index d9ab884..4496c8b 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -440,6 +440,9 @@ typedef enum FeatureWord { FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */ + FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */ + FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */ FEAT_SVM, /* CPUID[8000_000A].EDX */ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ FEAT_6_EAX, /* CPUID[6].EAX */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f3698f1..f44e3c7 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -574,6 +574,66 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) return 0; } +static int hyperv_handle_properties(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cpu->hyperv_relaxed_timing) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + } + if (cpu->hyperv_vapic) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; + has_msr_hv_vapic = true; + } + if (cpu->hyperv_time && + kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= 0x200; + has_msr_hv_tsc = true; + } + if (cpu->hyperv_crash && has_msr_hv_crash) { + env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; + } + if (cpu->hyperv_reset && has_msr_hv_reset) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_RESET_AVAILABLE; + } + if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_INDEX_AVAILABLE; + } + if (cpu->hyperv_runtime && has_msr_hv_runtime) { + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + } + if (cpu->hyperv_synic) { + int sint; + + if (!has_msr_hv_synic || + kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { + fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); + return -ENOSYS; + } + + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNIC_AVAILABLE; + env->msr_hv_synic_version = HV_SYNIC_VERSION_1; + for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { + env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; + } + } + if (cpu->hyperv_stimer) { + if (!has_msr_hv_stimer) { + fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); + return -ENOSYS; + } + env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNTIMER_AVAILABLE; + } + if (MACHINE_GET_CLASS(current_machine)->hot_add_cpu != NULL) { + env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; + } + return 0; +} + static Error *invtsc_mig_blocker; #define KVM_MAX_CPUID_ENTRIES 100 @@ -633,56 +693,14 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_FEATURES; - if (cpu->hyperv_relaxed_timing) { - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; - } - if (cpu->hyperv_vapic) { - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; - c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; - has_msr_hv_vapic = true; - } - if (cpu->hyperv_time && - kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) { - c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; - c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; - c->eax |= 0x200; - has_msr_hv_tsc = true; - } - if (cpu->hyperv_crash && has_msr_hv_crash) { - c->edx |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; - } - c->edx |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; - if (cpu->hyperv_reset && has_msr_hv_reset) { - c->eax |= HV_X64_MSR_RESET_AVAILABLE; - } - if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { - c->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; - } - if (cpu->hyperv_runtime && has_msr_hv_runtime) { - c->eax |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + r = hyperv_handle_properties(cs); + if (r) { + return r; } - if (cpu->hyperv_synic) { - int sint; - - if (!has_msr_hv_synic || - kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { - fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); - return -ENOSYS; - } + c->eax = env->features[FEAT_HYPERV_EAX]; + c->ebx = env->features[FEAT_HYPERV_EBX]; + c->edx = env->features[FEAT_HYPERV_EDX]; - c->eax |= HV_X64_MSR_SYNIC_AVAILABLE; - env->msr_hv_synic_version = HV_SYNIC_VERSION_1; - for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { - env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; - } - } - if (cpu->hyperv_stimer) { - if (!has_msr_hv_stimer) { - fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); - return -ENOSYS; - } - c->eax |= HV_X64_MSR_SYNTIMER_AVAILABLE; - } c = &cpuid_data.entries[cpuid_i++]; c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) {