Received: by 2002:a05:6359:c8b:b0:c7:702f:21d4 with SMTP id go11csp3471629rwb; Fri, 30 Sep 2022 04:13:13 -0700 (PDT) X-Google-Smtp-Source: AMsMyM5dLi9ZKTSyyuRqa+IK9McAoVwGEnhc3DtvdrGWDuG/zEX9SdrlcFZLdqTImqfXv7gHVuJA X-Received: by 2002:a17:90b:3745:b0:205:e53a:41d8 with SMTP id ne5-20020a17090b374500b00205e53a41d8mr17126584pjb.11.1664536393134; Fri, 30 Sep 2022 04:13:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1664536393; cv=none; d=google.com; s=arc-20160816; b=E1wLAJfFKaLEA5JIVyVbf+DNYTkm00LGwQuU8HoWXdaMot7EqqrYNslZqdkLUuJBIF ZQLxNFDal9usA6IQ8njK3Qkwl1l00PozhwQk6oqP0iSfWcRgLTBnYg/+0LKLSvwbHYH3 +XSe5BNwqauOjGVf3zuU4wMO4X4vdAnvR21Qwciw688bz6hYxbVirST1Xyr0oOKrKwo/ dxuy/+dKH8YGbBaeS78KZ1SJZ9YcDJW44LibdgsgNea2Cc/Q83Nghc2jI4hXbKSA9n6D oTGPlSufuxUrVGDWH+uK/Jryt472kgH/pQcSmtnr6ZxDn2+TIYm9VHaQveW/gGNKyXzH j23A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=NYPTVkmuf7Z3GE4q7kHBj7lhJrZMtG5zp1Nl57ctcI0=; b=WWzO8qrXacoHYYrxiYsPrfP5Pp/WADZBEfoEr8+P2X2cCkFk7NLB4lyItYP77C2zI2 nF1RSWE/Elm1bzft8qsm/wBRaCa/CQPwg9bE/xywTHc0enjoVpx1yOJCWTrQGD16YGjd vf5iqEVNu7bAwBGCX4nvFY4uO4QF7xzOvWvOOjIGUZVCtvmKhUo/S94sEY4s9Wg8ZsZO jVxhSWMqqr1oqrlKFKtwl47g9ER02XEkXav3MHxrud/a8IwEIYS0luNhdgT8AE/nQUN7 5YRI6tl8VX18WrH3P/jn8R98yZRi4Qgep7VFYv2OgYPghSQzEe5b7BeIk+FgEE2oPhqi m9IA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=CMzZvMvC; 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=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v22-20020a63f856000000b0041c033e9f54si2437580pgj.848.2022.09.30.04.13.01; Fri, 30 Sep 2022 04:13:13 -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=@intel.com header.s=Intel header.b=CMzZvMvC; 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=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231533AbiI3KTd (ORCPT + 99 others); Fri, 30 Sep 2022 06:19:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33582 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231297AbiI3KS4 (ORCPT ); Fri, 30 Sep 2022 06:18:56 -0400 Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CF6031664AC; Fri, 30 Sep 2022 03:18:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1664533135; x=1696069135; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9bbInB0ukaubXcuWCjnrDa7KuqBfgc8oZMafM3ru0lA=; b=CMzZvMvCTJQ70o89o73peP5HGPca8SZvlC9V9hrWn0aFnj/6Q/ajbwod nztGfsCnCmnHKzrMjIjjTExvNQZ82/DlJyz0os+ej68W/or4s6K/EtM6Y +CWMm9lTEgTjDcRONSeOnKQDsPv87Lri6BUbAFLSMj95nW94WPcAiJYFO cJOqiVHgck/vH2bPDqwL0xBq2M/Lzb3+0UwnhLrGdDHYugrTjJqgSEhao rVA9Cx5u4FDKUT5eDauwycL9IitUaDo3/UwhWLt8pS3F1ctP0Z8jVzzOB j/tQIyKZi+1NgBUZ0qAKaoeBh1MBL2HOZDmkeVLCp1sV6ZXv+enmItm90 g==; X-IronPort-AV: E=McAfee;i="6500,9779,10485"; a="281870067" X-IronPort-AV: E=Sophos;i="5.93,358,1654585200"; d="scan'208";a="281870067" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Sep 2022 03:18:54 -0700 X-IronPort-AV: E=McAfee;i="6500,9779,10485"; a="726807559" X-IronPort-AV: E=Sophos;i="5.93,358,1654585200"; d="scan'208";a="726807559" Received: from ls.sc.intel.com (HELO localhost) ([143.183.96.54]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 30 Sep 2022 03:18:54 -0700 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , erdemaktas@google.com, Sean Christopherson , Sagi Shahar Subject: [PATCH v9 017/105] KVM: TDX: Refuse to unplug the last cpu on the package Date: Fri, 30 Sep 2022 03:17:11 -0700 Message-Id: <3521fdb3fcf30043a0310ed226c06034d6b1cadd.1664530907.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, SPF_HELO_PASS,SPF_NONE autolearn=ham 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 From: Isaku Yamahata In order to reclaim TDX host key id, (i.e. when deleting guest TD), needs to call TDH.PHYMEM.PAGE.WBINVD on all packages. If we have used TDX host key id, refuse to offline the last online cpu. Signed-off-by: Isaku Yamahata --- arch/x86/include/asm/kvm-x86-ops.h | 1 + arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/main.c | 1 + arch/x86/kvm/vmx/tdx.c | 40 +++++++++++++++++++++++++++++- arch/x86/kvm/vmx/x86_ops.h | 2 ++ arch/x86/kvm/x86.c | 27 ++++++++++++-------- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 968e5ba1e4e6..cc7df6fccbb2 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -17,6 +17,7 @@ BUILD_BUG_ON(1) KVM_X86_OP(hardware_enable) KVM_X86_OP(hardware_disable) KVM_X86_OP(hardware_unsetup) +KVM_X86_OP_OPTIONAL_RET0(offline_cpu) KVM_X86_OP(has_emulated_msr) KVM_X86_OP(vcpu_after_set_cpuid) KVM_X86_OP(is_vm_type_supported) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f3d16e5730ac..7cd5e5917bab 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1460,6 +1460,7 @@ struct kvm_x86_ops { int (*hardware_enable)(void); void (*hardware_disable)(void); void (*hardware_unsetup)(void); + int (*offline_cpu)(void); bool (*has_emulated_msr)(struct kvm *kvm, u32 index); void (*vcpu_after_set_cpuid)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index 408afa691bad..43cc3af7d0ec 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -67,6 +67,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .name = "kvm_intel", .hardware_unsetup = vt_hardware_unsetup, + .offline_cpu = tdx_offline_cpu, .check_processor_compatibility = vmx_check_processor_compatibility, .hardware_enable = vmx_hardware_enable, diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 93174b10e1ea..6b07451d6661 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -42,6 +42,7 @@ static struct tdx_capabilities tdx_caps; */ static DEFINE_MUTEX(tdx_lock); static struct mutex *tdx_mng_key_config_lock; +static atomic_t nr_configured_hkid; static __always_inline hpa_t set_hkid_to_hpa(hpa_t pa, u16 hkid) { @@ -210,7 +211,8 @@ void tdx_mmu_release_hkid(struct kvm *kvm) pr_err("tdh_mng_key_freeid failed. HKID %d is leaked.\n", kvm_tdx->hkid); return; - } + } else + atomic_dec(&nr_configured_hkid); free_hkid: tdx_hkid_free(kvm_tdx); @@ -362,6 +364,8 @@ int tdx_vm_init(struct kvm *kvm) if (ret) break; } + if (!ret) + atomic_inc(&nr_configured_hkid); cpus_read_unlock(); free_cpumask_var(packages); if (ret) @@ -512,3 +516,37 @@ void tdx_hardware_unsetup(void) /* kfree accepts NULL. */ kfree(tdx_mng_key_config_lock); } + +int tdx_offline_cpu(void) +{ + int curr_cpu = smp_processor_id(); + cpumask_var_t packages; + int ret = 0; + int i; + + if (!atomic_read(&nr_configured_hkid)) + return 0; + + /* + * To reclaim hkid, need to call TDH.PHYMEM.PAGE.WBINVD on all packages. + * If this is the last online cpu on the package, refuse offline. + */ + if (!zalloc_cpumask_var(&packages, GFP_KERNEL)) + return -ENOMEM; + + for_each_online_cpu(i) { + if (i != curr_cpu) + cpumask_set_cpu(topology_physical_package_id(i), packages); + } + if (!cpumask_test_cpu(topology_physical_package_id(curr_cpu), packages)) + ret = -EBUSY; + free_cpumask_var(packages); + if (ret) + /* + * Because it's hard for human operator to understand the + * reason, warn it. + */ + pr_warn("TDX requires all packages to have an online CPU. " + "Delete all TDs in order to offline all CPUs of a package.\n"); + return ret; +} diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index ce50ddef84bf..5ab78e044895 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -134,6 +134,7 @@ void vmx_setup_mce(struct kvm_vcpu *vcpu); int __init tdx_hardware_setup(struct kvm_x86_ops *x86_ops); bool tdx_is_vm_type_supported(unsigned long type); void tdx_hardware_unsetup(void); +int tdx_offline_cpu(void); int tdx_vm_init(struct kvm *kvm); void tdx_mmu_release_hkid(struct kvm *kvm); @@ -142,6 +143,7 @@ void tdx_vm_free(struct kvm *kvm); static inline int tdx_hardware_setup(struct kvm_x86_ops *x86_ops) { return 0; } static inline bool tdx_is_vm_type_supported(unsigned long type) { return false; } static inline void tdx_hardware_unsetup(void) {} +static inline int tdx_offline_cpu(void) { return 0; } static inline int tdx_vm_init(struct kvm *kvm) { return -EOPNOTSUPP; } static inline void tdx_mmu_release_hkid(struct kvm *kvm) {} diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 82e6f54b35fb..351803fdc944 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12062,16 +12062,23 @@ int kvm_arch_online_cpu(unsigned int cpu, int usage_count) int kvm_arch_offline_cpu(unsigned int cpu, int usage_count) { - if (usage_count) { - /* - * arch callback kvm_arch_hardware_disable() assumes that - * preemption is disabled for historical reason. Disable - * preemption until all arch callbacks are fixed. - */ - preempt_disable(); - hardware_disable(NULL); - preempt_enable(); - } + int ret; + + if (!usage_count) + return 0; + + ret = static_call(kvm_x86_offline_cpu)(); + if (ret) + return ret; + + /* + * arch callback kvm_arch_hardware_disable() assumes that preemption is + * disabled for historical reason. Disable preemption until all arch + * callbacks are fixed. + */ + preempt_disable(); + hardware_disable(NULL); + preempt_enable(); return 0; } -- 2.25.1