From patchwork Wed Nov 2 23:19:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Christopherson X-Patchwork-Id: 14557 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp201918wru; Wed, 2 Nov 2022 16:27:45 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6A89lMJs8KLfpD6cz4S9ZyVmxO2bGuKXXKs1ECPmLm1QlX0SvnMvV/fK1dTrBNYdvsIS+8 X-Received: by 2002:a05:6402:414f:b0:456:c2c1:23ec with SMTP id x15-20020a056402414f00b00456c2c123ecmr27793177eda.420.1667431665419; Wed, 02 Nov 2022 16:27:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1667431665; cv=none; d=google.com; s=arc-20160816; b=r87COeUD0T2gN/PqCgP6udQQYqS6lGhPoHG+J2ZT/CwHXLedg41m6RnXi5V2rIqVtY AP2L04KCxuZ+7amJs7Ohd3dUm2BdhLDgfFJp8jmbFkYymTMV4tT19feF4vm8WCtpjeKc nWFYhRIv3FuD3lfdQqeW3YmuzyJAIT5n/iv7u9v/qQed26YKEjDf0vSwWhVqQZTKlmME 4vKoMXSFZUB0t07tqXBass+aXSy9WQ3RLvRGXHhgku/n7nRav4d+RvKWqDEcnRQbGIXY aXl84SAVmbTrzHvd4UcJaKZwKMWRogsLdNZ5/vOBF/Bxpc9yGJM0dFSX/hWEy/cJ6eyH Cn3w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:reply-to:dkim-signature; bh=hVDla26eytMn5VFnbgyTVPls5SmrgGd/F0K2RutwtIE=; b=zT4dphhDuuIuOilOUzDNaTTDEEhBKM+w3jPNO5dZDdkxjJ81PqB8TtDn4eeS21JJsy /jQz4VWaTwhC3EBnel+YWl4SLqu5dKDQP41x/6GZPo3yd1+nAN33m+WhA8tcD9nb1qdJ l4bDXw7swcSazhG2Fpj14fkfBmwYY0+swfqmuuWrYsz1YvUi6u+H7aHz3UK/wkwmnBRG Syw/XVkFonBFBNkqFTpuNqPtD7TuBq2wU4UanHVffG1wefP1FrEN+cB16O9SU6IGOZC1 hnsHy2aS/6hH17PKe69gGOEDHc/KyF8BOZsuWOCsT0bbjrZT8CX4SY1v8+Y4zVovFbjn L1Og== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=iDIyHkMK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id du20-20020a17090772d400b00781a47397b1si18962668ejc.502.2022.11.02.16.27.22; Wed, 02 Nov 2022 16:27:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=iDIyHkMK; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230265AbiKBXZv (ORCPT + 99 others); Wed, 2 Nov 2022 19:25:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231272AbiKBXYa (ORCPT ); Wed, 2 Nov 2022 19:24:30 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D3B51182C for ; Wed, 2 Nov 2022 16:20:30 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id k7-20020a256f07000000b006cbcc030bc8so332976ybc.18 for ; Wed, 02 Nov 2022 16:20:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=hVDla26eytMn5VFnbgyTVPls5SmrgGd/F0K2RutwtIE=; b=iDIyHkMK4rG4gjhR62NbU2u6gdWGP2OsiuMyUm8igYAHn8Yp75bJ9TkqULzcOkedq9 lrMjOcoojkzBjBrlWbrxKO2hIi08hnG2vGMjy19X2fXFVzh41QfLnOmL8FwroxgO3U/9 M/y/STwQ9eY7WF8E0/2v/0v9jH+QmXpfdWTDy77I/CMIhnQwVipOJiVFqKmJ5knT8kO6 /eER3jJeTkGs/T4H5Ju8HiQ1eI0gIKHtbfqcKoWDK8SihPIEH+EjdUsL3+2iNE+kxZKc HsZJGEKFI4GV2S8b1QPqcice4sYcmqQ+Iksou1vJeTEdz8AoPZCMtO8nunZ43hRprA3N Kt5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=hVDla26eytMn5VFnbgyTVPls5SmrgGd/F0K2RutwtIE=; b=Z67KYPn6GaC7Um1Jc+mot3l8+W6GzXwxNHVWrvc/j9PmGUkuFgp+RCVoUZezmnAJIy M6j5rjuiloAy6ASgDoVIbTHvW2BrhQIjxo21rMbGEGg8PjRjG7d7eZEROMNY3NMYUNhO vMNv7KKFVDlDzGOr1s+k0/HUq9VH0rMHHohMATvo3LZguyLfrc8w6gKOIxjIGJJKw/EO Oj1Jtrt0ev5JFfdbeiJQAvqBhJKfrosAzNRsmSdEt7HUQhVwRf8ndT9YJE0eBObsvQEo C8k13+gG3fjwvaFy+58ZOrPRDsBJkWXYqef6CXcW/xHi3PGhK3pbl6ncxTn3vi+Ic7DA B5hQ== X-Gm-Message-State: ACrzQf2xvAnE6MJis4QU39zLmgae7DMfU1c/+Bi39K7EieqwbSzbS2/E XJ6Su7RNTQNuBES4zt5sTnvN14v8hq4= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a25:b10d:0:b0:6cc:3aa3:8cf2 with SMTP id g13-20020a25b10d000000b006cc3aa38cf2mr22841832ybj.261.1667431216148; Wed, 02 Nov 2022 16:20:16 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 2 Nov 2022 23:19:03 +0000 In-Reply-To: <20221102231911.3107438-1-seanjc@google.com> Mime-Version: 1.0 References: <20221102231911.3107438-1-seanjc@google.com> X-Mailer: git-send-email 2.38.1.431.g37b22c650d-goog Message-ID: <20221102231911.3107438-37-seanjc@google.com> Subject: [PATCH 36/44] KVM: x86: Do compatibility checks when onlining CPU From: Sean Christopherson To: Paolo Bonzini , Marc Zyngier , Huacai Chen , Aleksandar Markovic , Anup Patel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Christian Borntraeger , Janosch Frank , Claudio Imbrenda , Matthew Rosato , Eric Farman , Sean Christopherson , Vitaly Kuznetsov Cc: James Morse , Alexandru Elisei , Suzuki K Poulose , Oliver Upton , Atish Patra , David Hildenbrand , kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, kvmarm@lists.cs.columbia.edu, linux-mips@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, kvm-riscv@lists.infradead.org, linux-riscv@lists.infradead.org, linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org, Isaku Yamahata , Fabiano Rosas , Michael Ellerman , Chao Gao , Thomas Gleixner , Yuan Yao X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1748428825732015019?= X-GMAIL-MSGID: =?utf-8?q?1748428825732015019?= From: Chao Gao Do compatibility checks when enabling hardware to effectively add compatibility checks when onlining a CPU. Abort enabling, i.e. the online process, if the (hotplugged) CPU is incompatible with the known good setup. At init time, KVM does compatibility checks to ensure that all online CPUs support hardware virtualization and a common set of features. But KVM uses hotplugged CPUs without such compatibility checks. On Intel CPUs, this leads to #GP if the hotplugged CPU doesn't support VMX, or VM-Entry failure if the hotplugged CPU doesn't support all features enabled by KVM. Note, this is little more than a NOP on SVM, as SVM already checks for full SVM support during hardware enabling. Opportunistically add a pr_err() if setup_vmcs_config() fails, and tweak all error messages to output which CPU failed. Signed-off-by: Chao Gao Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/svm/svm.c | 20 +++++++++++--------- arch/x86/kvm/vmx/vmx.c | 33 +++++++++++++++++++-------------- arch/x86/kvm/x86.c | 5 +++-- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f223c845ed6e..c99222b71fcc 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1666,7 +1666,7 @@ struct kvm_x86_nested_ops { }; struct kvm_x86_init_ops { - int (*check_processor_compatibility)(void); + int (*check_processor_compatibility)(int cpu); int (*hardware_setup)(void); unsigned int (*handle_intel_pt_intr)(void); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index efda384d29d4..4772835174dd 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -525,13 +525,13 @@ static void svm_init_osvw(struct kvm_vcpu *vcpu) vcpu->arch.osvw.status |= 1; } -static bool kvm_is_svm_supported(void) +static bool kvm_is_svm_supported(int cpu) { const char *msg; u64 vm_cr; if (!cpu_has_svm(&msg)) { - pr_err("SVM not supported, %s\n", msg); + pr_err("SVM not supported by CPU %d, %s\n", cpu, msg); return false; } @@ -542,16 +542,16 @@ static bool kvm_is_svm_supported(void) rdmsrl(MSR_VM_CR, vm_cr); if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) { - pr_err("SVM disabled in MSR_VM_CR\n"); + pr_err("SVM disabled in MSR_VM_CR on CPU %d\n", cpu); return false; } return true; } -static int __init svm_check_processor_compat(void) +static int svm_check_processor_compat(int cpu) { - if (!kvm_is_svm_supported()) + if (!kvm_is_svm_supported(cpu)) return -EIO; return 0; @@ -588,14 +588,16 @@ static int svm_hardware_enable(void) uint64_t efer; struct desc_struct *gdt; int me = raw_smp_processor_id(); + int r; + + r = svm_check_processor_compat(me); + if (r) + return r; rdmsrl(MSR_EFER, efer); if (efer & EFER_SVME) return -EBUSY; - if (!kvm_is_svm_supported()) - return -EINVAL; - sd = per_cpu(svm_data, me); if (!sd) { pr_err("%s: svm_data is NULL on %d\n", __func__, me); @@ -5132,7 +5134,7 @@ static int __init svm_init(void) __unused_size_checks(); - if (!kvm_is_svm_supported()) + if (!kvm_is_svm_supported(raw_smp_processor_id())) return -EOPNOTSUPP; r = kvm_x86_vendor_init(&svm_init_ops); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 07d86535c032..2729de93e0ea 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2520,8 +2520,7 @@ static bool cpu_has_perf_global_ctrl_bug(void) return false; } -static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, - u32 msr, u32 *result) +static int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, u32 msr, u32 *result) { u32 vmx_msr_low, vmx_msr_high; u32 ctl = ctl_min | ctl_opt; @@ -2539,7 +2538,7 @@ static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, return 0; } -static __init u64 adjust_vmx_controls64(u64 ctl_opt, u32 msr) +static u64 adjust_vmx_controls64(u64 ctl_opt, u32 msr) { u64 allowed; @@ -2548,8 +2547,8 @@ static __init u64 adjust_vmx_controls64(u64 ctl_opt, u32 msr) return ctl_opt & allowed; } -static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, - struct vmx_capability *vmx_cap) +static int setup_vmcs_config(struct vmcs_config *vmcs_conf, + struct vmx_capability *vmx_cap) { u32 vmx_msr_low, vmx_msr_high; u32 _pin_based_exec_control = 0; @@ -2710,36 +2709,38 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, return 0; } -static bool __init kvm_is_vmx_supported(void) +static bool kvm_is_vmx_supported(int cpu) { if (!cpu_has_vmx()) { - pr_err("CPU doesn't support VMX\n"); + pr_err("VMX not supported by CPU %d\n", cpu); return false; } if (!boot_cpu_has(X86_FEATURE_MSR_IA32_FEAT_CTL) || !boot_cpu_has(X86_FEATURE_VMX)) { - pr_err("VMX not enabled in MSR_IA32_FEAT_CTL\n"); + pr_err("VMX not enabled in MSR_IA32_FEAT_CTL on CPU %d\n", cpu); return false; } return true; } -static int __init vmx_check_processor_compat(void) +static int vmx_check_processor_compat(int cpu) { struct vmcs_config vmcs_conf; struct vmx_capability vmx_cap; - if (!kvm_is_vmx_supported()) + if (!kvm_is_vmx_supported(cpu)) return -EIO; - if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0) + if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0) { + pr_err("Failed to setup VMCS config on CPU %d\n", cpu); return -EIO; + } if (nested) nested_vmx_setup_ctls_msrs(&vmcs_conf, vmx_cap.ept); - if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { - pr_err("CPU %d feature inconsistency!\n", smp_processor_id()); + if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config))) { + pr_err("Inconsistent VMCS config on CPU %d\n", cpu); return -EIO; } return 0; @@ -2771,6 +2772,10 @@ static int vmx_hardware_enable(void) u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); int r; + r = vmx_check_processor_compat(cpu); + if (r) + return r; + if (cr4_read_shadow() & X86_CR4_VMXE) return -EBUSY; @@ -8517,7 +8522,7 @@ static int __init vmx_init(void) { int r, cpu; - if (!kvm_is_vmx_supported()) + if (!kvm_is_vmx_supported(raw_smp_processor_id())) return -EOPNOTSUPP; hv_setup_evmcs(); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0c1778f3308a..a7b1d916ecb2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9280,7 +9280,8 @@ struct kvm_cpu_compat_check { static int kvm_x86_check_processor_compatibility(struct kvm_x86_init_ops *ops) { - struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); + int cpu = smp_processor_id(); + struct cpuinfo_x86 *c = &cpu_data(cpu); WARN_ON(!irqs_disabled()); @@ -9288,7 +9289,7 @@ static int kvm_x86_check_processor_compatibility(struct kvm_x86_init_ops *ops) __cr4_reserved_bits(cpu_has, &boot_cpu_data)) return -EIO; - return ops->check_processor_compatibility(); + return ops->check_processor_compatibility(cpu); } static void kvm_x86_check_cpu_compat(void *data)