Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: TDX: Don't offline the last cpu of one package when there's TDX guest

Destroying TDX guest requires there's at least one cpu online for each
package, because reclaiming the TDX KeyID of the guest (as part of the
teardown process) requires to call some SEAMCALL (on any cpu) on all
packages.

Do not offline the last cpu of one package when there's any TDX guest
running, otherwise KVM may not be able to teardown TDX guest resulting
in leaking of TDX KeyID and other resources like TDX guest control
structure pages.

Implement the TDX version 'offline_cpu()' to prevent the cpu from going
offline if it is the last cpu on the package.

Co-developed-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Kai Huang <kai.huang@intel.com>
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Isaku Yamahata and committed by
Paolo Bonzini
9934d7e5 ffb6fc84

+42 -1
+42 -1
arch/x86/kvm/vmx/tdx.c
··· 131 131 */ 132 132 static DEFINE_MUTEX(tdx_lock); 133 133 134 + static atomic_t nr_configured_hkid; 135 + 134 136 static inline void tdx_hkid_free(struct kvm_tdx *kvm_tdx) 135 137 { 136 138 tdx_guest_keyid_free(kvm_tdx->hkid); 137 139 kvm_tdx->hkid = -1; 140 + atomic_dec(&nr_configured_hkid); 138 141 } 139 142 140 143 static inline bool is_hkid_assigned(struct kvm_tdx *kvm_tdx) ··· 606 603 607 604 ret = -ENOMEM; 608 605 606 + atomic_inc(&nr_configured_hkid); 607 + 609 608 tdr_page = alloc_page(GFP_KERNEL); 610 609 if (!tdr_page) 611 610 goto free_hkid; ··· 905 900 return r; 906 901 } 907 902 903 + static int tdx_offline_cpu(unsigned int cpu) 904 + { 905 + int i; 906 + 907 + /* No TD is running. Allow any cpu to be offline. */ 908 + if (!atomic_read(&nr_configured_hkid)) 909 + return 0; 910 + 911 + /* 912 + * In order to reclaim TDX HKID, (i.e. when deleting guest TD), need to 913 + * call TDH.PHYMEM.PAGE.WBINVD on all packages to program all memory 914 + * controller with pconfig. If we have active TDX HKID, refuse to 915 + * offline the last online cpu. 916 + */ 917 + for_each_online_cpu(i) { 918 + /* 919 + * Found another online cpu on the same package. 920 + * Allow to offline. 921 + */ 922 + if (i != cpu && topology_physical_package_id(i) == 923 + topology_physical_package_id(cpu)) 924 + return 0; 925 + } 926 + 927 + /* 928 + * This is the last cpu of this package. Don't offline it. 929 + * 930 + * Because it's hard for human operator to understand the 931 + * reason, warn it. 932 + */ 933 + #define MSG_ALLPKG_ONLINE \ 934 + "TDX requires all packages to have an online CPU. Delete all TDs in order to offline all CPUs of a package.\n" 935 + pr_warn_ratelimited(MSG_ALLPKG_ONLINE); 936 + return -EBUSY; 937 + } 938 + 908 939 static void __do_tdx_cleanup(void) 909 940 { 910 941 /* ··· 973 932 */ 974 933 r = cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, 975 934 "kvm/cpu/tdx:online", 976 - tdx_online_cpu, NULL); 935 + tdx_online_cpu, tdx_offline_cpu); 977 936 if (r < 0) 978 937 return r; 979 938