From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFFFF23AB81 for ; Wed, 11 Jun 2025 21:16:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676619; cv=none; b=tFfXq48b7F5dxZhmw3tBJ+jhEWUOv8iPYSPoZcdL28rJOyAefD7H9HFsRuPCmOzGIZGXLVrVcSD7ZMF6gmWn0mnJTdaVePz5TbIOfaxFn0K1lHxSeNWMD8UtKqMUvb+EKMK1dBDU4TBkW5rrgpAgH2epvPfZqIjVGKJaG7EFf2M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676619; c=relaxed/simple; bh=1J2BNASlNa1Dhe5jluI1gAN0W9RVPLyHfYbBUQPkC54=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Jv9cAXIaWfyhP4jHzF6szEUxcWuf5Qm64CuJ4B617Ze/NfNHSdcIADtWC8nGaeW4ty1zbrzKnHQOil5QqWF+nPm93muqb2W7RVygUX5/vESj1mxCNnHJi4jNeVIIbGAkykI3t8PE9GZ6kVNwzyZ7QRkPEel6/elP+iXBkiI2dU0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=tX0dj0C6; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="tX0dj0C6" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-7377139d8b1so226611b3a.0 for ; Wed, 11 Jun 2025 14:16:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676617; x=1750281417; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=JVZUY5qeKcLxvon3A1qgzFOnqGD8w3UB+MEi0rObhNA=; b=tX0dj0C6FlJ+8eMNwdZODidXdYTeEqpSRvjX9G1HOn1NuSC4Z0Zn3+2CocNpvgyFJ/ 4ddOneDuYzDCBy6xehXPXgZaK5cxZ+41J+tUNhynqUKn0agFJ4SAO1DV6EsEY8zXt7kr wvfXG4/jMJrHxtfE7tjOC/2kwmEVrI1vh3aaR/ZvZObH7Z8uYnXePADn0bh+SU0qe6wp iLJL+YvTz+oj7v/eMnu70WaJ522v6jI/BK0/1ZO8aGDiOwNEmIkAdNuXW6NAB4ye+tgo pMkS41hMyBeHWl6Nh47llY/7Mtl3gPshfdtNc321TLrH4M17R7m7XVBswzhEK/d7rzlp H8FA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676617; x=1750281417; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JVZUY5qeKcLxvon3A1qgzFOnqGD8w3UB+MEi0rObhNA=; b=lfDCMYBEnh7C0nyHPoYqH6NZxnCLgnt8tfDASIucfanSCbpVG2pZfz/3NIomAu0kxi i8CKlbgxRuNM+qGaOXvkSq+a068GFwOhbE3us+ou6mwcre2s8tsdMiSVtqRSIjmSMwWa 5zevHd6sUQIwNFA5Jz0QEVexZXY1KYFFl122uf3m6SCZCOoQBWFUb+XEaJsY6J2Si+RT /iDPAtvotl9gfp5s4hekOEyfYQv10sMKeu5SAgbY/cyl2KY110XjyXDXl0u/JP6P1NM0 hn3dfZDWSMJWHHAwgFOmUD4oRp3kRnbVRiLfF9q6TxmTOeapDQ+jGTDpO1Dd25CLAVj5 6+4Q== X-Forwarded-Encrypted: i=1; AJvYcCWjshHPKIOPsJjNgJMP2vnW1nFx8ujr2O+xkpQOD6lVfUdcMUwdW48cFg4Yl2sorb0KogW51qOv1unK2ps=@vger.kernel.org X-Gm-Message-State: AOJu0YxGx2zw4fNaM1VfDy/V8AodSPX4rqgf+K0G4iTCZ3RS0JrLDL1W NS2TJIdcZsEM9pgEd4RiULYKughdAnt317uAVnTaWLNaGQnvJkdVaM5Uy49qY/sXpypqTCnFioa qzPjCmxHkvw== X-Google-Smtp-Source: AGHT+IEJ/qdunyiMvwsT10mftztZECZsqDYMcHYykS/gDMvyJ2du0eMtdA6wuu+sltqOX8qT0k9ifIs5X5dW X-Received: from pfble12.prod.google.com ([2002:a05:6a00:4fcc:b0:746:1d26:e8c8]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:394b:b0:21f:775d:107e with SMTP id adf61e73a8af0-21f9b9f75ebmr370105637.17.1749676617125; Wed, 11 Jun 2025 14:16:57 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:28 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: <884dc45a13920578973d5628c7cad79d8d50b7a2.1749672978.git.afranji@google.com> Subject: [RFC PATCH v2 01/10] KVM: Split tdp_mmu_pages to mirror and direct counters From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sagi Shahar tdp_mmu_pages counts all the active pages used by the mmu. When we transfer the state during intra-host migration we need to transfer the mirror pages but not the direct ones. The direct pages are going to be re-faulted as needed on the destination, but that approach doesn't work for mirrored pages which stores information in the secure EPT. Keeping them in separate counters makes this transfer more efficient. Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- arch/x86/include/asm/kvm_host.h | 7 +++++-- arch/x86/kvm/mmu/tdp_mmu.c | 11 +++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 999872c13722..b9966394acda 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1484,10 +1484,13 @@ struct kvm_arch { #ifdef CONFIG_X86_64 #ifdef CONFIG_KVM_PROVE_MMU /* - * The number of TDP MMU pages across all roots. Used only to sanity - * check that KVM isn't leaking TDP MMU pages. + * The number of non-mirrored TDP MMU pages across all roots. + * Used only to sanity check that KVM isn't leaking TDP MMU pages. */ atomic64_t tdp_mmu_pages; + + /* Same as tdp_mmu_pages but only for mirror pages. */ + atomic64_t tdp_mirror_mmu_pages; #endif =20 /* diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7f3d7229b2c1..115af5e4c5ed 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -42,6 +42,7 @@ void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm) =20 #ifdef CONFIG_KVM_PROVE_MMU KVM_MMU_WARN_ON(atomic64_read(&kvm->arch.tdp_mmu_pages)); + KVM_MMU_WARN_ON(atomic64_read(&kvm->arch.tdp_mirror_mmu_pages)); #endif WARN_ON(!list_empty(&kvm->arch.tdp_mmu_roots)); =20 @@ -328,7 +329,10 @@ static void tdp_account_mmu_page(struct kvm *kvm, stru= ct kvm_mmu_page *sp) { kvm_account_pgtable_pages((void *)sp->spt, +1); #ifdef CONFIG_KVM_PROVE_MMU - atomic64_inc(&kvm->arch.tdp_mmu_pages); + if (sp->role.is_mirror) + atomic64_inc(&kvm->arch.tdp_mirror_mmu_pages); + else + atomic64_inc(&kvm->arch.tdp_mmu_pages); #endif } =20 @@ -336,7 +340,10 @@ static void tdp_unaccount_mmu_page(struct kvm *kvm, st= ruct kvm_mmu_page *sp) { kvm_account_pgtable_pages((void *)sp->spt, -1); #ifdef CONFIG_KVM_PROVE_MMU - atomic64_dec(&kvm->arch.tdp_mmu_pages); + if (sp->role.is_mirror) + atomic64_dec(&kvm->arch.tdp_mirror_mmu_pages); + else + atomic64_dec(&kvm->arch.tdp_mmu_pages); #endif } =20 --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F880244660 for ; Wed, 11 Jun 2025 21:16:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676621; cv=none; b=Ul1IKknV/PF2Y/s8NyrHs4H04eb8kM4OiWA4RpSyUPlcX3CiWgCWT8ef314uFoTSF0gjPj/XQCKoCAB0sPhcWAphOv5Rel8I71tey1Mu8pFM+608w7EwBBYzKD0fZfAd2iUPn0ilTgKLrNgxtO9FEALpGW3E9s5E/lHAsM2qa3M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676621; c=relaxed/simple; bh=b4VA2RGdpApRaSDkLmIRrxzmznFdKL/sDPXrbgY9dp8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=j4QYeJPk+S31B2lkeeDneAHFp0nuaio14o9b+PlSFyXw9ujpjiWsbcbTEk76CD2dXsTweeVlrPf4ASo90v0Kpe1YRWEwqLJnoyZGz3nAgmr8lM8mGUQISRbqHZn3RYDobegl7kF6N+XsrDIWXIMR6zpxwVSuxw1qW613MpuaU/0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=cm1llxK3; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="cm1llxK3" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-b2f4c436301so159924a12.0 for ; Wed, 11 Jun 2025 14:16:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676619; x=1750281419; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=zir2Z2BYD9TVMhA71zOuRqts4XDUJGWDctYBYtUWNnI=; b=cm1llxK3nvYST9jiAVqkkidlRCmrAXeSYqwy5PPrNaWKYbh+8JqYpvcGN3lgsTf/Wc ozOIWGOnoc3hfQTF0B6lXe3+itn5k30LD3dLFa4w4HfC5LGDLbWXOVRs+IXdnlE1Z98Q mJ6ntD92WvBTZ/ut1U/0QlZcolXoKaZa8e641SZ+cebYF2uEvRFg7j2FaC4+JXDpMKbp HBqnC5tMXLi16unbvBxg/+CzaOhV09X5+Or0itEx7ufRKimATNBtoHrmhh7F+viWJSz8 FrO+aSNBa/wQGiIXEyLzUIFtM3fVraFwQk2o3P65osGSVPAnfM3WFKUENx0utPSoZV5j flYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676619; x=1750281419; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to; bh=zir2Z2BYD9TVMhA71zOuRqts4XDUJGWDctYBYtUWNnI=; b=Dx/1djyk40+pPhAaaL7/WxjHHC4n7960q1NNKYVMDXgxrNR9ZR8rtpd++o/wnTs9Cb LNIPwBZONBpw4KE3rrVXvMb8cSznUlKlwJlKlnNV6+qVmz1TT8CVLhpzPUvsrhI23t3G orVqxrSedZ3jV5Z5K16IGaqCJ75x4Gv60xBSUHgeqqxGYBq0tLQqlRjcnGVr793c6UUJ vox5rkzTk6XFJlHCc9fTxUQ6DAGnb007eTymKUHSFUdgpnHBppuB0y+nYEDUyL2PeZH7 pyUylcYfKzXafGMVQfAhlfxDHv/wPE5589Q6P9YQ5s/8ODNWy2lagRL+cId0p+P1ZLKl e4DA== X-Forwarded-Encrypted: i=1; AJvYcCWCCFauB20jOJl7dgR7aywwwAwyd+2ZVn5NxPrCarxqoXmzirvYNx3W8B5+7j19bzrXi095KGNXH1TKI9g=@vger.kernel.org X-Gm-Message-State: AOJu0YzeccEGej3s/L5lkB14CoFPGhb6FDbjuEaSgrShR5Eg9SM84sV9 q8p0qr4D7166vMr2A0j0ctQwsrk40SYf6s9qYvAFr1yraEUJVoWrB28ITA8GYAVKIhSExdTJWTM D1PIvy9bgpA== X-Google-Smtp-Source: AGHT+IFEdzwI0hLX7jOjgrsvuEtZ1pf59QC5BkheGfaBuI5bKPz0+MMRvkX5eBM8K7fT56stpLxx97K0L1P1 X-Received: from pjbof7.prod.google.com ([2002:a17:90b:39c7:b0:312:e5dd:9248]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5866:b0:311:b5ac:6f7d with SMTP id 98e67ed59e1d1-313bfd90b31mr1285824a91.6.1749676618837; Wed, 11 Jun 2025 14:16:58 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:29 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: Subject: [RFC PATCH v2 02/10] KVM: x86: Adjust locking order in move_enc_context_from From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Previously, the order for acquiring the locks required for the migration function move_enc_context_from() was: 1) memslot lock 2) vCPU lock. This can trigger a deadlock warning because a vCPU IOCTL modifying memslots will acquire the locks in reverse order: 1) vCPU lock 2) memslot lock. This patch adjusts move_enc_context_from() to match vCPU IOCTL=E2=80=99s lo= cking order to prevent deadlock warnings. Signed-off-by: Ryan Afranji --- arch/x86/kvm/svm/sev.c | 13 +------------ arch/x86/kvm/x86.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 402543994b0b..380d5951f8dd 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1961,26 +1961,15 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, s= truct kvm *source_kvm) charged =3D true; } =20 - ret =3D kvm_lock_all_vcpus(kvm); - if (ret) - goto out_dst_cgroup; - ret =3D kvm_lock_all_vcpus(source_kvm); - if (ret) - goto out_dst_vcpu; - ret =3D sev_check_source_vcpus(kvm, source_kvm); if (ret) - goto out_source_vcpu; + goto out_dst_cgroup; =20 sev_migrate_from(kvm, source_kvm); kvm_vm_dead(source_kvm); cg_cleanup_sev =3D src_sev; ret =3D 0; =20 -out_source_vcpu: - kvm_unlock_all_vcpus(source_kvm); -out_dst_vcpu: - kvm_unlock_all_vcpus(kvm); out_dst_cgroup: /* Operates on the source on success, on the destination on failure. */ if (charged) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b1672379a16b..c28fa28a8e42 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6743,10 +6743,18 @@ static int kvm_vm_move_enc_context_from(struct kvm = *kvm, unsigned int source_fd) if (r) goto out_mark_migration_done; =20 - r =3D kvm_lock_vm_memslots(kvm, source_kvm); + r =3D kvm_lock_all_vcpus(kvm); if (r) goto out_unlock; =20 + r =3D kvm_lock_all_vcpus(source_kvm); + if (r) + goto out_unlock_vcpus; + + r =3D kvm_lock_vm_memslots(kvm, source_kvm); + if (r) + goto out_unlock_source_vcpus; + r =3D kvm_move_memory_ctxt_from(kvm, source_kvm); if (r) goto out_unlock_memslots; @@ -6762,6 +6770,10 @@ static int kvm_vm_move_enc_context_from(struct kvm *= kvm, unsigned int source_fd) =20 out_unlock_memslots: kvm_unlock_vm_memslots(kvm, source_kvm); +out_unlock_source_vcpus: + kvm_unlock_all_vcpus(source_kvm); +out_unlock_vcpus: + kvm_unlock_all_vcpus(kvm); out_unlock: kvm_unlock_two_vms(kvm, source_kvm); out_mark_migration_done: --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F046246778 for ; Wed, 11 Jun 2025 21:17:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676622; cv=none; b=TlW4ssVPhFfT1oLJ46CG7DnRUz/9f5chnWHxzlLzJ0ENKHs17wa5VZwGX4ePBrvNX5yzV2CpIe8NDLiD+KUDGKh6EjU/WXFzSoBFf7fp04py1opZ4zLqfffF8DWce+C+hA3ZUQRZ7vPgpd/jn1kB1NHUWzilDq+DVu/2HLX4s2k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676622; c=relaxed/simple; bh=EliRXJasvagyPsAst5/DK5fV9+Nz9GPWmMU52maUMAU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=aR+Y1aujjI1l1qyCrjPIXMKut2WTQOoLdy8pDaw3xs1OzC81XzaL9RjzHxLLNdTPGqBSXJIXbmtqOY0Ko6jKmArvnN7TUpBzwtPqf7keIPHIJT0Nhzrl5larldInA0ymvEsnLsMU4X+SZgCMXZA+YVK3VZ+RhAnnPmIOwL8hPg4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qZ+shGyL; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qZ+shGyL" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-747d394f45fso216530b3a.2 for ; Wed, 11 Jun 2025 14:17:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676620; x=1750281420; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=sBfca3HTQRqrJJwA201rhl29YEXxOvfPcejKdAe4i9w=; b=qZ+shGyLSQDl3spdrL0FFV3vW8iGhGw1Z4h2wPqXxeuGsCLcQ83MZ8ue9g2j+X11kA z4f2FeAxrBjXCuL4LI1Kg1+KYbESqQMmvL8jLkkPTxWAR6ZW2Q6/UnkSxArJMqajDHyt 9qus/WWX/IdL0fyCnsrbg2U6v746JoU7MwQ1wurBfJP2vMY73ehVDrAeJPPXN6dQfK5k Nn+FGefxQTSUJWI4TZuMcNKTV/94VEbZ8wG9wIpFGIO5prdLP8gGGVIB5j5cOWTLUBkU GvIRC8K0EkDvz5yImlGoUJLt0rIqKbN7g3XXsS4ZnaaVHbvFTSVZ+nNRiZ1Sf6avuKPa JutA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676620; x=1750281420; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sBfca3HTQRqrJJwA201rhl29YEXxOvfPcejKdAe4i9w=; b=F2QfjI1Ym26uRuQYJEF+JzF3UEmFiHSoUy3CyoOmOJsX3FWgjEYg89PRFDmLMXS3/P tAHSLJDWQikax3xeBKV+8kgt4lWnpi4qRjP4DLzXROADgPu46wPHFQUcfGnCwyAFbYB1 ftVNsNYKhJOWuShVQqIn29bDNilfSSYklqAdzh7j2coB5Sx+FIKyoh1hVorukW0SIh/e Fl8uQXd9Y3+YKd+gx/vc9HLKf8X8MlX2xg770EkzZ25bDnWN8rGFeA4JtDwsCBffvzzZ g9PzA9q8imVnPZ0lE6V+i0P9Iy59XbFaFiOb6nH07vZhO+Xw3eW/hj4ONYehI5DjYJXa iosg== X-Forwarded-Encrypted: i=1; AJvYcCXThDFfbM0PxXCRwYUR14WtatKlj92Nxxnhj7iNV0WAkWAgdzj8D+BB7tWLdegAgPI5ge8aFKC1zkPIRWY=@vger.kernel.org X-Gm-Message-State: AOJu0YyhTYFB69fjFjnzFhkbY9/vDq8zuT6P71CVUuD4gWlK/zSRZspL zp2fX3Ywb7WVwjBlSWLqSW0zWsdkD2PMqV58I1DlNLtpu0o2M2AHddMXRVimK49jH7wLNoKgWEp VJGU6Xslxdw== X-Google-Smtp-Source: AGHT+IEwt8NGYhwzS0nUmHsR7Wm0KUS2I53PheVpr9xT2i86QWOhPPHtzrsha444DVNmTlDTkv6MnyHBFveF X-Received: from pfblm9.prod.google.com ([2002:a05:6a00:3c89:b0:746:3244:f1e6]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:194b:b0:748:3485:b99d with SMTP id d2e1a72fcca58-7487c338367mr1420302b3a.18.1749676620423; Wed, 11 Jun 2025 14:17:00 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:30 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: Subject: [RFC PATCH v2 03/10] KVM: TDX: Add base implementation for tdx_vm_move_enc_context_from From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sagi Shahar This should mostly match the logic in sev_vm_move_enc_context_from. Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- arch/x86/kvm/vmx/main.c | 12 +++++++++++- arch/x86/kvm/vmx/tdx.c | 24 ++++++++++++++++++++++++ arch/x86/kvm/vmx/x86_ops.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index d1e02e567b57..125af25fd09a 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -879,6 +879,14 @@ static int vt_gmem_private_max_mapping_level(struct kv= m *kvm, kvm_pfn_t pfn) return 0; } =20 +static int vt_move_enc_context_from(struct kvm *kvm, struct kvm *source_kv= m) +{ + if (!is_td(kvm)) + return -ENOTTY; + + return tdx_vm_move_enc_context_from(kvm, source_kvm); +} + #define vt_op(name) vt_##name #define vt_op_tdx_only(name) vt_##name #else /* CONFIG_KVM_INTEL_TDX */ @@ -1044,7 +1052,9 @@ struct kvm_x86_ops vt_x86_ops __initdata =3D { .mem_enc_ioctl =3D vt_op_tdx_only(mem_enc_ioctl), .vcpu_mem_enc_ioctl =3D vt_op_tdx_only(vcpu_mem_enc_ioctl), =20 - .private_max_mapping_level =3D vt_op_tdx_only(gmem_private_max_mapping_le= vel) + .private_max_mapping_level =3D vt_op_tdx_only(gmem_private_max_mapping_le= vel), + + .vm_move_enc_context_from =3D vt_move_enc_context_from }; =20 struct kvm_x86_init_ops vt_init_ops __initdata =3D { diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index b952bc673271..07583a11d6e3 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -626,6 +626,7 @@ int tdx_vm_init(struct kvm *kvm) kvm->arch.has_protected_state =3D true; kvm->arch.has_private_mem =3D true; kvm->arch.disabled_quirks |=3D KVM_X86_QUIRK_IGNORE_GUEST_PAT; + kvm->arch.use_vm_enc_ctxt_op =3D true; =20 /* * Because guest TD is protected, VMM can't parse the instruction in TD. @@ -3524,3 +3525,26 @@ int __init tdx_bringup(void) enable_tdx =3D 0; return 0; } + +static __always_inline bool tdx_finalized(struct kvm *kvm) +{ + struct kvm_tdx *tdx_kvm =3D to_kvm_tdx(kvm); + + return tdx_kvm->state =3D=3D TD_STATE_RUNNABLE; +} + +static int tdx_migrate_from(struct kvm *dst, struct kvm *src) +{ + return -EINVAL; +} + +int tdx_vm_move_enc_context_from(struct kvm *kvm, struct kvm *src_kvm) +{ + if (!is_td(kvm) || !is_td(src_kvm)) + return -EINVAL; + + if (tdx_finalized(kvm) || !tdx_finalized(src_kvm)) + return -EINVAL; + + return tdx_migrate_from(kvm, src_kvm); +} diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index b4596f651232..001f1540a560 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -164,6 +164,7 @@ void tdx_flush_tlb_current(struct kvm_vcpu *vcpu); void tdx_flush_tlb_all(struct kvm_vcpu *vcpu); void tdx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_leve= l); int tdx_gmem_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn); +int tdx_vm_move_enc_context_from(struct kvm *kvm, struct kvm *source_kvm); #endif =20 #endif /* __KVM_X86_VMX_X86_OPS_H */ --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AD7BD2472BD for ; Wed, 11 Jun 2025 21:17:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676624; cv=none; b=MCj/0GHWKGaQT3iMB1V7GvA6mnu7d03wYx7OkDLjFZjG0RpQfERPMFJmg/AU21hg38bzM8QoPmdMJBifGE/l3WvfWvVJz260k33KC6QwKw7n10FuLWKrX9rBhd1Yol0Wk3B4HWdqwDpadK2LDJQv40KIMXR/eMoo/JI2zeHxx0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676624; c=relaxed/simple; bh=23eEzMfMOXF7V+bWkGGPvYl3Tz385egAD6gxjflsMOg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XxCHLxCUI5NiZYWkOuF2XilotOeFKi9MW137Odvf1NyRdDFaLdOQxqwAJimAUCAE2rZBr6K+eQK9kG63PF5DYAaRhOm/lmnqBdI+zEDOcJtU5LPH51PEXO79rnAJNDtaYUDka+tyllPPnSnAR+AzXVSLr40v+U2wlIgGNbcXn5I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=XtB1acE6; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="XtB1acE6" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2356ce55d33so3387535ad.0 for ; Wed, 11 Jun 2025 14:17:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676622; x=1750281422; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=eeeVbKpBN3tx4HaouiCrmDPq5kK6kn8OwuY8SLpOHLs=; b=XtB1acE6yjL3I9NFyGCi6BYqW5VF0TzWICdBJCaWrTIweyMGIEavO6DhZQhBZkW8GN 786v4e9GuoOBRbsWWukwctYitSaiboVz/g9ey/7nvWZdUf9A73r1NzG0OuTsaWze0ci/ 2uSGrvblLTyRME7FgeaE70AdV0c/+zbTK0ogfcXscUemWAkRubi0wEqZIu8Uw+Sd7rDJ HhAxEe5kGoJD0ew12TqXBWIL3UNK9RJj+Bd4YRSFavUK/CClwPizZHgDeoEz9a59jur0 hbrwGNn7dJNWbzqe390gjZCLv8yuzvmcraRo5R12sd3BxZK6AGaOo/rcnIISN1D3RTAZ H3fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676622; x=1750281422; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=eeeVbKpBN3tx4HaouiCrmDPq5kK6kn8OwuY8SLpOHLs=; b=cpuDZMY9JdtpiZZBZRBbWGMtw+zOv9WUOVXKACSAZkb/fLBBK+FfpHs8yTbKeanwzh KijZsE27BOwd9LqEkxr7qOfp7+UNiq94P6Kl3PwgTqyoVLwVGAmFPQNhZxAy44oZ9UQ+ s39mVDJexLHoZq+wz5Zt/Umlp8ep6X1CQCpLTsPejel88eSosxJF4ELydlBzPqZu4Xwp EgFBvGOMmLRBO1wz5ZZnxW26OR7vMjvCBd7wv9uUZCRmlb1W1aSWzEEYmCdq1JOM4a8P QwA95tYYLwd9uJNBGesNkX9203MO/3NrQ49kKNp2ygVZlvxeSk9Vr3UeFNk96z9E57zY fcQA== X-Forwarded-Encrypted: i=1; AJvYcCUnyKpnCZVjNGpg0Sc0h/e/TL1d45i4TabPl2gOqUvvdNxmshTUYK2/w8hpjHp3FUdM2SFlWan2fuqiqHo=@vger.kernel.org X-Gm-Message-State: AOJu0Yy7XG7tk6Ni9WknG/8I+RLLDKi8Gu9K0DJHRDffStC9F4dhbekp zKHWAl+xa41B9Dk6DDdXW9QVvlyanR3Yzstw3N5Nh3C26tx70S1XTNU0tPeHAgWBRb30OpPOVQ8 h0t5FCtxO2w== X-Google-Smtp-Source: AGHT+IE5WV553GbkZv8fO1P4XOmH7RTOhAm37uG1sjPoDpJHdYSQZ79D7+wj8i1Ji8ZCsjPC1Fa02a37Bbim X-Received: from pjbqo13.prod.google.com ([2002:a17:90b:3dcd:b0:311:a4ee:7c3d]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:46c5:b0:234:8ec1:4ad3 with SMTP id d9443c01a7336-23641b291acmr69887485ad.40.1749676622084; Wed, 11 Jun 2025 14:17:02 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:31 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: Subject: [RFC PATCH v2 04/10] KVM: TDX: Implement moving mirror pages between 2 TDs From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sagi Shahar Added functionality for moving the mirror EPT table from one TD to a new one. This function moves the root of the mirror EPT table and overwrites the root of the destination. Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- arch/x86/kvm/mmu.h | 2 ++ arch/x86/kvm/mmu/mmu.c | 66 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/mmu/tdp_mmu.c | 61 ++++++++++++++++++++++++++++++++--- arch/x86/kvm/mmu/tdp_mmu.h | 6 ++++ 4 files changed, 130 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index b4b6860ab971..b43d770daa05 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -102,6 +102,8 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu); void kvm_mmu_sync_prev_roots(struct kvm_vcpu *vcpu); void kvm_mmu_track_write(struct kvm_vcpu *vcpu, gpa_t gpa, const u8 *new, int bytes); +int kvm_mmu_move_mirror_pages_from(struct kvm_vcpu *vcpu, + struct kvm_vcpu *src_vcpu); =20 static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index cbc84c6abc2e..09c1892e0ac1 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3943,6 +3943,72 @@ static int mmu_first_shadow_root_alloc(struct kvm *k= vm) return r; } =20 +int kvm_mmu_move_mirror_pages_from(struct kvm_vcpu *vcpu, + struct kvm_vcpu *src_vcpu) +{ + struct kvm_mmu *mmu =3D vcpu->arch.mmu; + struct kvm_mmu *src_mmu =3D src_vcpu->arch.mmu; + gfn_t gfn_shared =3D kvm_gfn_direct_bits(vcpu->kvm); + hpa_t mirror_root_hpa; + int r =3D -EINVAL; + + if (!gfn_shared) + return r; + + r =3D mmu_topup_memory_caches(vcpu, !vcpu->arch.mmu->root_role.direct); + if (r) + return r; + + /* Hold locks for both src and dst. Always take the src lock first. */ + read_lock(&src_vcpu->kvm->mmu_lock); + write_lock_nested(&vcpu->kvm->mmu_lock, SINGLE_DEPTH_NESTING); + + WARN_ON_ONCE(!is_tdp_mmu_active(vcpu)); + WARN_ON_ONCE(!is_tdp_mmu_active(src_vcpu)); + + /* + * The mirror root is moved from the src to the dst and is marked as + * invalid in the src. + */ + mirror_root_hpa =3D kvm_tdp_mmu_move_mirror_pages_from(vcpu, src_vcpu); + if (mirror_root_hpa =3D=3D INVALID_PAGE) { + struct kvm_mmu_page *mirror_root; + union kvm_mmu_page_role role =3D vcpu->arch.mmu->root_role; + + /* + * This likely means that the mirror root was already moved by + * another vCPU. + */ + role.is_mirror =3D true; + mirror_root =3D kvm_tdp_mmu_get_vcpu_root(vcpu, role); + if (!mirror_root) { + r =3D -EINVAL; + goto out_unlock; + } + mirror_root_hpa =3D __pa(mirror_root->spt); + } + + mmu->mirror_root_hpa =3D mirror_root_hpa; + mmu_free_root_page(src_vcpu->kvm, &src_mmu->mirror_root_hpa, NULL); + write_unlock(&vcpu->kvm->mmu_lock); + read_unlock(&src_vcpu->kvm->mmu_lock); + + /* The direct root is allocated normally and is not moved from src. */ + kvm_tdp_mmu_alloc_root(vcpu, false); + + kvm_mmu_load_pgd(vcpu); + kvm_x86_call(flush_tlb_current)(vcpu); + + return r; + +out_unlock: + write_unlock(&vcpu->kvm->mmu_lock); + read_unlock(&src_vcpu->kvm->mmu_lock); + + return r; +} +EXPORT_SYMBOL(kvm_mmu_move_mirror_pages_from); + static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) { struct kvm_mmu *mmu =3D vcpu->arch.mmu; diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 115af5e4c5ed..212716ab7e8b 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -251,6 +251,22 @@ static void tdp_mmu_init_child_sp(struct kvm_mmu_page = *child_sp, tdp_mmu_init_sp(child_sp, iter->sptep, iter->gfn, role); } =20 +struct kvm_mmu_page * +kvm_tdp_mmu_get_vcpu_root(struct kvm_vcpu *vcpu, + union kvm_mmu_page_role role) +{ + struct kvm *kvm =3D vcpu->kvm; + struct kvm_mmu_page *root; + + lockdep_assert_held(&kvm->mmu_lock); + list_for_each_entry(root, &kvm->arch.tdp_mmu_roots, link) { + if (root->role.word =3D=3D role.word && + !WARN_ON_ONCE(!kvm_tdp_mmu_get_root(root))) + return root; + } + return NULL; +} + void kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu, bool mirror) { struct kvm_mmu *mmu =3D vcpu->arch.mmu; @@ -285,11 +301,9 @@ void kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu, boo= l mirror) * fails, as the last reference to a root can only be put *after* the * root has been invalidated, which requires holding mmu_lock for write. */ - list_for_each_entry(root, &kvm->arch.tdp_mmu_roots, link) { - if (root->role.word =3D=3D role.word && - !WARN_ON_ONCE(!kvm_tdp_mmu_get_root(root))) - goto out_spin_unlock; - } + root =3D kvm_tdp_mmu_get_vcpu_root(vcpu, role); + if (!!root) + goto out_spin_unlock; =20 root =3D tdp_mmu_alloc_sp(vcpu); tdp_mmu_init_sp(root, NULL, 0, role); @@ -321,6 +335,43 @@ void kvm_tdp_mmu_alloc_root(struct kvm_vcpu *vcpu, boo= l mirror) } } =20 +hpa_t kvm_tdp_mmu_move_mirror_pages_from(struct kvm_vcpu *vcpu, + struct kvm_vcpu *src_vcpu) +{ + union kvm_mmu_page_role role =3D vcpu->arch.mmu->root_role; + struct kvm *kvm =3D vcpu->kvm; + struct kvm *src_kvm =3D src_vcpu->kvm; + struct kvm_mmu_page *mirror_root =3D NULL; + s64 num_mirror_pages, old; + + lockdep_assert_held_read(&src_vcpu->kvm->mmu_lock); + lockdep_assert_held_write(&vcpu->kvm->mmu_lock); + + /* Find the mirror root of the source. */ + role.is_mirror =3D true; + mirror_root =3D kvm_tdp_mmu_get_vcpu_root(src_vcpu, role); + if (!mirror_root) + return INVALID_PAGE; + + /* Remove the mirror root from the src kvm and add it to dst kvm. */ + spin_lock(&src_vcpu->kvm->arch.tdp_mmu_pages_lock); + list_del_rcu(&mirror_root->link); + spin_unlock(&src_vcpu->kvm->arch.tdp_mmu_pages_lock); + + /* The destination holds a write lock so no spin_lock required. */ + list_add_rcu(&mirror_root->link, &kvm->arch.tdp_mmu_roots); + +#ifdef CONFIG_KVM_PROVE_MMU + num_mirror_pages =3D atomic64_read(&src_kvm->arch.tdp_mirror_mmu_pages); + old =3D atomic64_cmpxchg(&kvm->arch.tdp_mirror_mmu_pages, 0, + num_mirror_pages); + /* The destination VM should have no mirror pages at this point. */ + WARN_ON(old); + atomic64_set(&src_kvm->arch.tdp_mirror_mmu_pages, 0); +#endif + return __pa(mirror_root->spt); +} + static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, u64 old_spte, u64 new_spte, int level, bool shared); diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 52acf99d40a0..abb1a84d8b1c 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -63,6 +63,12 @@ static inline struct kvm_mmu_page *tdp_mmu_get_root(stru= ct kvm_vcpu *vcpu, return root_to_sp(vcpu->arch.mmu->root.hpa); } =20 +struct kvm_mmu_page * +kvm_tdp_mmu_get_vcpu_root(struct kvm_vcpu *vcpu, + union kvm_mmu_page_role role); +hpa_t kvm_tdp_mmu_move_mirror_pages_from(struct kvm_vcpu *vcpu, + struct kvm_vcpu *src_vcpu); + bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool f= lush); bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp); void kvm_tdp_mmu_zap_all(struct kvm *kvm); --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74A5A248F58 for ; Wed, 11 Jun 2025 21:17:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676625; cv=none; b=cxdDabwxaRPAwpw/D2HApWrWzdboYD5eV9/6w51EqjYptv8IEjrRQmBbSFB2mguPoRLlJ21xWpHlp4YpPToChnRDGdBp5MPDWzj8Kn/GiVNYds3M3KckHgOSrm7Tgt/YpvNNaVmZ/d9yV/QrkVjlCuD9H65N+VXhOkAy0WGzTLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676625; c=relaxed/simple; bh=l18NNuz2zr+jRstrv6kyMt+9mV72sgFutUjjJmTOoto=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lsbN1o3PxG1XUfOVkN1UmvT1TmaZ1KcRUfZ+BUgfXqfjZp/9c10feesTQXEt7mT3HfjZcKJAMG+i6P3OgCtCfUNn+XKBbyiaD/wie8iMQ8G0xa7GUhZOHtUEz3XhGoIzHQwexNj4D6bELg/fxS58xvKVZEhETAqummDf+ODKtW4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=BejBy1vI; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="BejBy1vI" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-7395d07a3dcso199631b3a.3 for ; Wed, 11 Jun 2025 14:17:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676624; x=1750281424; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=AY4z8bScFURq5DitqWrBML6dYMJAiXsDf7kOOKjRLig=; b=BejBy1vIR7/Xw0bj5zIm74wS/L0gIi6tqSFUNGnGyOCQuYMiPsDWQgN0vyJdtZ7aWc avSYCpgn9pPMrJ5D2w74p5ZfzeqrHR2uk2zGIaqAt7IOjiAH6QSjzdowFqf8iwiihPyH jNFY3dIU4M+Q4HX5ZN/YK2mU17YwGzIEesGeMbUK+69GSkJqCqq1U6fQTWuHLWlS4/xP BGJ+wDrGQsWbqybLg1bVkvBmdsL+gjzu01itNGhz/ynggapTpgFK8Zhm3DZ1gSDRnAt4 7cyZyGmlTigWLws7ffK14yE2cetuutnNGC9pujyjH+QMYM0yTXtNmqPtuLCbBjKxbTZc xZ3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676624; x=1750281424; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=AY4z8bScFURq5DitqWrBML6dYMJAiXsDf7kOOKjRLig=; b=uu6AOrgHb01kw5WSfyz9jJ+bMWbWRTnkWWSSMlb4X052kR3MN2ipErI0W/DQAKxgaa GeaL5tPABrD4nYH/tYxJYP3zSvfEnJQ2I7x4urKyBnK851DmmPlSwrM5mRYa7yMR6cTi W73m2WczkeuE1lnXhJy0oOhlJDgqVuB1eqnNNf9l8mUJlQa3HFOx+c5Y316IGcAlepVO Yj/AKtKkdtpo19N8pu8fJAMSWeNp0cMBgfLTuYs4kt3G1xOLW9qLrH5EvxmEgP22kDOD xgUW6Sc4DNQY2EXkF8HCAyXF50duWxKIQTVgC4a0l3fUm8FVdNLsZOQ6/D2cFidbCHVt 8Ttw== X-Forwarded-Encrypted: i=1; AJvYcCUM1AAMTFtTmXYG6kp1hzsPhGy0D3jgTd+PdmFLVwoP+1z87wyBO0FFOHvC7/BbVwvCdxRAqWBOI3rjZT0=@vger.kernel.org X-Gm-Message-State: AOJu0YzeeGwgo5ertxg04KGwOBZoShNkejm7rB9g/tpIVzVMhTF25ihR jeSbk8xy+fzBn7Pf6sN4jMLwwiVTUtjbdb+9T7g7hjiz5JOn5PUJyPMkJwORlwwtmjDXz5Zv6tn sPqhtGG42kg== X-Google-Smtp-Source: AGHT+IFEX+YyUhAFLiB4PDLh59KjEqWsCilHKWQI2mwBOBQTb2abCAlQoUn+D5s5FIrNKX3bLlnv1X5ckyXg X-Received: from pfva20.prod.google.com ([2002:a05:6a00:c94:b0:746:2414:11ef]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:189b:b0:736:450c:fa54 with SMTP id d2e1a72fcca58-7487e10153dmr654396b3a.6.1749676623770; Wed, 11 Jun 2025 14:17:03 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:32 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: <3a4ee24c9eea7bd25c3c7a8f7060c89ba69f56d9.1749672978.git.afranji@google.com> Subject: [RFC PATCH v2 05/10] KVM: TDX: Allow vCPUs to be created for migration From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" During migration, vCPUs need to be created for an uninitialized VM. This commit moves the TDX vCPU setup that requires an initialized VM out of tdx_vcpu_create() and into tdx_td_vcpu_init(). Signed-off-by: Ryan Afranji --- arch/x86/kvm/vmx/tdx.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 07583a11d6e3..4582f94175b7 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -664,9 +664,6 @@ int tdx_vcpu_create(struct kvm_vcpu *vcpu) struct kvm_tdx *kvm_tdx =3D to_kvm_tdx(vcpu->kvm); struct vcpu_tdx *tdx =3D to_tdx(vcpu); =20 - if (kvm_tdx->state !=3D TD_STATE_INITIALIZED) - return -EIO; - /* * TDX module mandates APICv, which requires an in-kernel local APIC. * Disallow an in-kernel I/O APIC, because level-triggered interrupts @@ -692,12 +689,6 @@ int tdx_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.tsc_scaling_ratio =3D kvm_tdx->tsc_multiplier; vcpu->arch.l1_tsc_scaling_ratio =3D kvm_tdx->tsc_multiplier; =20 - vcpu->arch.guest_state_protected =3D - !(to_kvm_tdx(vcpu->kvm)->attributes & TDX_TD_ATTR_DEBUG); - - if ((kvm_tdx->xfam & XFEATURE_MASK_XTILE) =3D=3D XFEATURE_MASK_XTILE) - vcpu->arch.xfd_no_write_intercept =3D true; - tdx->vt.pi_desc.nv =3D POSTED_INTR_VECTOR; __pi_set_sn(&tdx->vt.pi_desc); =20 @@ -3003,8 +2994,9 @@ static int tdx_vcpu_get_cpuid(struct kvm_vcpu *vcpu, = struct kvm_tdx_cmd *cmd) =20 static int tdx_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd) { - u64 apic_base; + struct kvm_tdx *kvm_tdx =3D to_kvm_tdx(vcpu->kvm); struct vcpu_tdx *tdx =3D to_tdx(vcpu); + u64 apic_base; int ret; =20 if (cmd->flags) @@ -3013,6 +3005,15 @@ static int tdx_vcpu_init(struct kvm_vcpu *vcpu, stru= ct kvm_tdx_cmd *cmd) if (tdx->state !=3D VCPU_TD_STATE_UNINITIALIZED) return -EINVAL; =20 + if (kvm_tdx->state !=3D TD_STATE_INITIALIZED) + return -EIO; + + vcpu->arch.guest_state_protected =3D !(kvm_tdx->attributes & + TDX_TD_ATTR_DEBUG); + + if ((kvm_tdx->xfam & XFEATURE_MASK_XTILE) =3D=3D XFEATURE_MASK_XTILE) + vcpu->arch.xfd_no_write_intercept =3D true; + /* * TDX requires X2APIC, userspace is responsible for configuring guest * CPUID accordingly. --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 22D3C24A067 for ; Wed, 11 Jun 2025 21:17:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676627; cv=none; b=cT2f6E/S3+QfCzPnuMA+jkpzy8IZK3E8ab0tn26NwR21WFIla9gLhkTvTANI2ejDmxD6rojBbEUN7AfEUxntHYRDzD0VFshaI/j2O89N3Vs1+xLp8QkU7a2+1teYQY63DIujaNpsUxgDCuD1JDNfIAM05Nzoziu6nQPGybxO4Qg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676627; c=relaxed/simple; bh=x3k8bhvleSPHVSZM+Hu9CVZnDZNGJdDQHXfon2q0JNg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=EVtLbMp/bxBH0JF/zlsZi93ZKJeI/w+xYXB1yJjN9wfhgn66htpA+F590KBJB/U+IAQv2WHK9ogIbh0QpkBKADlNz+FhFnLOKkIrFLNzlESzBrQcxTsbmLuukJ+6HprSi5a5IsInlpm2NzTEK9XJ9dEQGc2lzkSbONR0NLP9G30= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=VHjZDJc/; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="VHjZDJc/" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-31327b2f8e4so245431a91.1 for ; Wed, 11 Jun 2025 14:17:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676625; x=1750281425; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=sUa6MDoTcZ9fiqDL9aF0ZXv2kKdfYnDn1hf7TqaAmz0=; b=VHjZDJc/Y9l5PmFrsPGNW0CrFoJrgplwW4NKLlbpdBvuuXcmBYULslJjEF+GoMewGQ +Aqu1AO26tF6a17cxBGSyLHESlIfPqxO2+B6yJjo1PSTb9EOXv94hPs2SVhHIVDL4dBk yXb6sfISfTN3+Manx9zRaE19yAaY9YxLzfVnhQFcNe30Qqt6FRGJ0JIgjgmDGghUVFtL m91vgS/E1MecHtVe9iffuR88v6ItkxopCZ1hp5t4og2R/HLp4Ty3Fbj8p96UMonnTbeq gnY+w3WuT3Ef/tHVjwO36pgQqhLaFfJr1fdeR7lVfaQVDZWghD8sMEIqshDktCe6tply pMvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676625; x=1750281425; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sUa6MDoTcZ9fiqDL9aF0ZXv2kKdfYnDn1hf7TqaAmz0=; b=OENjzO3dvBgi6WikQn/xWGj/f1zdHPQZw7e5XthV5bGwncsJLWwRvLkP+MycvXIeb+ rf2NPBZIBuIuR1ziPcMv2f5vFV2F5CDkc5KfhvO7vSOne3SB/3d7NoHnS+oLdrZHuxv5 bnulAUq+d3nF0w83pIod8kBgE2WUQEb/k+CY5X+bHt8lxg/4q7bBn6YtoY9mdRxF8ens RGvgOa70QFnTaVOe6o1blp6A8vRl4oDf+KBuVH9gQnZ6V2qnkRTOVBdqJZkpUPUnmjoZ L8Wc/nwWs1gJtgxjhmCfiPnZcBPHiAyEqfOpOfF8iTHaOuBmGN+TqusAVRbhkRspAiEd fY0A== X-Forwarded-Encrypted: i=1; AJvYcCWYKequWthbpo+XYfzjYqM+CjgXgRYHzIKALOl5+Ljo2kpRj5ElTukRWm1Tad3/a4eFXDR08LeUFJMrBk0=@vger.kernel.org X-Gm-Message-State: AOJu0YyN75Vla/OkAwkz3LtU8+MbsfkdavkLtu1tXKcYCAkNiT/NZlf9 7nRl6/kWKHYpapWD6QlYMGHczkN6bTLL9NALX2iZCaQmzE5HtCHtHiXqZy6IlLFOp8lnhbpKGSA JM/YD73xRkw== X-Google-Smtp-Source: AGHT+IFvw3e8kSlOft2Aa67tR4tbWriXJAz6qMW5rx2kfDteHiCjVlYUYiTe4hevdIc3/x6NCe31w22UVNJM X-Received: from pjoo4.prod.google.com ([2002:a17:90b:5824:b0:30a:7da4:f075]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4b87:b0:311:d05c:936 with SMTP id 98e67ed59e1d1-313bfbf521fmr1449542a91.17.1749676625477; Wed, 11 Jun 2025 14:17:05 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:33 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: Subject: [RFC PATCH v2 06/10] KVM: TDX: Add core logic for TDX intra-host migration From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sagi Shahar Adds the core logic for transferring state between source and destination TDs during intra-host migration. Signed-off-by: Sagi Shahar Co-developed-by: Ryan Afranji Signed-off-by: Ryan Afranji --- arch/x86/kvm/vmx/tdx.c | 193 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index 4582f94175b7..268aca28d878 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -3534,9 +3534,200 @@ static __always_inline bool tdx_finalized(struct kv= m *kvm) return tdx_kvm->state =3D=3D TD_STATE_RUNNABLE; } =20 +#define MAX_APIC_VECTOR 256 + +static int tdx_migrate_vcpus(struct kvm *dst, struct kvm *src) +{ + struct kvm_vcpu *src_vcpu; + struct kvm_tdx *dst_tdx; + unsigned long i; + + dst_tdx =3D to_kvm_tdx(dst); + + kvm_for_each_vcpu(i, src_vcpu, src) + tdx_flush_vp_on_cpu(src_vcpu); + + /* Copy per-vCPU state. */ + kvm_for_each_vcpu(i, src_vcpu, src) { + struct vcpu_tdx *dst_tdx_vcpu, *src_tdx_vcpu; + struct kvm_lapic_state src_lapic_state; + struct kvm_vcpu *dst_vcpu; + u64 apic_base; + u32 vector; + int ret; + + src_tdx_vcpu =3D to_tdx(src_vcpu); + dst_vcpu =3D kvm_get_vcpu(dst, i); + dst_tdx_vcpu =3D to_tdx(dst_vcpu); + + dst_vcpu->cpu =3D -1; + + /* Destination vCPU initialization skipped so do it here. */ + apic_base =3D APIC_DEFAULT_PHYS_BASE | LAPIC_MODE_X2APIC | + (kvm_vcpu_is_reset_bsp(dst_vcpu) ? + MSR_IA32_APICBASE_BSP : 0); + if (kvm_apic_set_base(dst_vcpu, apic_base, true)) + return -EINVAL; + + /* Copy lapic state. */ + ret =3D kvm_apic_get_state(src_vcpu, &src_lapic_state); + if (ret) + return -EINVAL; + + ret =3D kvm_apic_set_state(dst_vcpu, &src_lapic_state); + if (ret) + return -EINVAL; + + /* + * pi_desc stores state of posted interrupts for VMs which are + * processed by pcpu during VM entry/runtime. For + * non-confidential VMs, this storage is synchronized to vcpu + * state using set_lapic_state(sync_pir_to_virr). + * + * For TDX VMs, KVM doesn't have access to virtual lapic page, + * so in order to preserve the interrupt state, copy over + * pi_desc contents to destination VM during copyless migration. + */ + dst_tdx_vcpu->vt =3D src_tdx_vcpu->vt; + for (vector =3D 0; vector < MAX_APIC_VECTOR; vector++) { + if (pi_test_pir(vector, &src_tdx_vcpu->vt.pi_desc)) { + __vmx_deliver_posted_interrupt( + dst_vcpu, + &dst_tdx_vcpu->vt.pi_desc, + vector); + } + } + + /* Copy non-TDX vCPU state. */ + memcpy(dst_vcpu->arch.regs, src_vcpu->arch.regs, + NR_VCPU_REGS * sizeof(src_vcpu->arch.regs[0])); + + dst_vcpu->arch.regs_avail =3D src_vcpu->arch.regs_avail; + dst_vcpu->arch.regs_dirty =3D src_vcpu->arch.regs_dirty; + dst_vcpu->arch.tsc_offset =3D dst_tdx->tsc_offset; + dst_vcpu->arch.guest_state_protected =3D + src_vcpu->arch.guest_state_protected; + dst_vcpu->arch.xfd_no_write_intercept =3D + src_vcpu->arch.xfd_no_write_intercept; + dst_vcpu->arch.tsc_offset =3D dst_tdx->tsc_offset; + + /* Copy TD structures. */ + dst_tdx_vcpu->vp.tdvpr_page =3D src_tdx_vcpu->vp.tdvpr_page; + dst_tdx_vcpu->vp.tdcx_pages =3D src_tdx_vcpu->vp.tdcx_pages; + + td_vmcs_write64(dst_tdx_vcpu, POSTED_INTR_DESC_ADDR, + __pa(&dst_tdx_vcpu->vt.pi_desc)); + + /* Copy current vCPU status. */ + dst_tdx_vcpu->ext_exit_qualification =3D + src_tdx_vcpu->ext_exit_qualification; + dst_tdx_vcpu->exit_gpa =3D src_tdx_vcpu->exit_gpa; + dst_tdx_vcpu->vp_enter_args =3D src_tdx_vcpu->vp_enter_args; + dst_tdx_vcpu->vp_enter_ret =3D src_tdx_vcpu->vp_enter_ret; + dst_tdx_vcpu->guest_entered =3D src_tdx_vcpu->guest_entered; + dst_tdx_vcpu->map_gpa_next =3D src_tdx_vcpu->map_gpa_next; + dst_tdx_vcpu->map_gpa_end =3D src_tdx_vcpu->map_gpa_end; + + /* Copy mirror EPT tables. */ + vcpu_load(dst_vcpu); + if (kvm_mmu_move_mirror_pages_from(dst_vcpu, src_vcpu)) { + vcpu_put(dst_vcpu); + return -EINVAL; + } + vcpu_put(dst_vcpu); + + dst_vcpu->arch.mp_state =3D KVM_MP_STATE_RUNNABLE; + dst_tdx_vcpu->state =3D VCPU_TD_STATE_INITIALIZED; + + /* + * Set these source's vCPU migrated structures to NULL to avoid + * freeing them during source VM shutdown. + */ + src_tdx_vcpu->vp.tdvpr_page =3D NULL; + src_tdx_vcpu->vp.tdcx_pages =3D NULL; + } + + return 0; +} + static int tdx_migrate_from(struct kvm *dst, struct kvm *src) { - return -EINVAL; + struct kvm_tdx *src_tdx, *dst_tdx; + bool charged =3D false; + int ret; + + src_tdx =3D to_kvm_tdx(src); + dst_tdx =3D to_kvm_tdx(dst); + + ret =3D -EINVAL; + + if (src_tdx->state !=3D TD_STATE_RUNNABLE) { + pr_warn("Cannot migrate from a non finalized VM\n"); + goto abort; + } + + /* Transfer miscellaneous cgroup. */ + dst_tdx->misc_cg =3D get_current_misc_cg(); + if (dst_tdx->misc_cg !=3D src_tdx->misc_cg) { + ret =3D misc_cg_try_charge(MISC_CG_RES_TDX, dst_tdx->misc_cg, 1); + if (ret) + goto abort_dst_cgroup; + charged =3D true; + } + + dst_tdx->hkid =3D src_tdx->hkid; + + /* Copy VM data. */ + dst_tdx->attributes =3D src_tdx->attributes; + dst_tdx->xfam =3D src_tdx->xfam; + dst_tdx->tsc_offset =3D src_tdx->tsc_offset; + dst_tdx->tsc_multiplier =3D src_tdx->tsc_multiplier; + dst_tdx->nr_premapped =3D src_tdx->nr_premapped; + dst_tdx->wait_for_sept_zap =3D src_tdx->wait_for_sept_zap; + dst_tdx->kvm.arch.gfn_direct_bits =3D src_tdx->kvm.arch.gfn_direct_bits; + + /* Copy TD structures. */ + dst_tdx->td.tdcs_nr_pages =3D src_tdx->td.tdcs_nr_pages; + dst_tdx->td.tdcx_nr_pages =3D src_tdx->td.tdcx_nr_pages; + dst_tdx->td.tdr_page =3D src_tdx->td.tdr_page; + dst_tdx->td.tdcs_pages =3D src_tdx->td.tdcs_pages; + + /* Copy per-vCPU state. */ + ret =3D tdx_migrate_vcpus(dst, src); + if (ret) + goto late_abort; + + dst->mem_attr_array.xa_head =3D src->mem_attr_array.xa_head; + src->mem_attr_array.xa_head =3D NULL; + + dst_tdx->state =3D TD_STATE_RUNNABLE; + + /* + * Set these source's vCPU migrated structures to NULL to avoid + * freeing them during source VM shutdown. + */ + src_tdx->hkid =3D -1; + src_tdx->td.tdr_page =3D NULL; + src_tdx->td.tdcs_pages =3D NULL; + + return 0; + +late_abort: + /* + * If we aborted after the state transfer already started, the src VM + * is no longer valid. + */ + kvm_vm_dead(src); + +abort_dst_cgroup: + if (charged) + misc_cg_uncharge(MISC_CG_RES_TDX, dst_tdx->misc_cg, 1); + put_misc_cg(dst_tdx->misc_cg); + dst_tdx->misc_cg =3D NULL; +abort: + dst_tdx->hkid =3D -1; + dst_tdx->td.tdr_page =3D 0; + return ret; } =20 int tdx_vm_move_enc_context_from(struct kvm *kvm, struct kvm *src_kvm) --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4D1024CEE8 for ; Wed, 11 Jun 2025 21:17:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676629; cv=none; b=FS3IAPFn5csTpBpt+8JDxgzN4vaIWP2g14J4ahLNScbtL8A00Gb8uNKTI4iES7+cQI5AvTuBl0kTyyzloxo3ETRobyibM9gEBXKB9R5ZFAjZQ3GeXYeLRXCJWb0qEkXmpsIniVnB5RU5+bWU/DpHvmsbXINNGVOIDUgK+TH6sjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676629; c=relaxed/simple; bh=E1J5NvWvWAj9PK8Bj/QCV4SungXm4iyN66KAsLSKFdw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=d9Ww7FFY3Co3sQT/oUqSgq4DfbiCXVDLNO+az8/qfCTcXYzOrfPkjJMKWEGaG87lmA1s6LteIwnLHClqbhuDA34RrVkbrqaVOPbsOPUdNJ2T0UYbqCyKwWV/I2np8o0iFUfazkb0JGZkXhrxI45l2YBmb1LoiW9CIb36htDCDrQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=RRR0bdHH; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RRR0bdHH" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-234906c5e29so2985345ad.0 for ; Wed, 11 Jun 2025 14:17:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676627; x=1750281427; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=QRxvuTFismoVMH6kpT5Sxdu0Bq/4xhAKlCPWJnUhYZA=; b=RRR0bdHHF6eDnTUFrWPl04OZfdCXYpLxNz4Nd+3TbL2dyZZ5k9iv1uBJvnVZk04q+M 2M9tKoVhSTcHhGYgWn41jI8AmN1AUssmutEtp4Cj7qvYzI8K0Te/68aI2qjfHt7JziBs hDsO8zr5AiAo5UDAncgM0DpZAq8EoiT+BIOoU0anA7duhZdyadEOJK2nOhh3khXPjXqM LezVO3ikWz87q1BRpArrBuLvk363hxKNPjv85lYFHyTEN2V3FhcOm1bZkN8iUxZvw1Fj cJsAAGJJHZ+rJ2hMQmyqfEtG/K3j6TwsdsYeTY1gzEPS/r9lKsoKZfgyLWnXPIaefYvP toGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676627; x=1750281427; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=QRxvuTFismoVMH6kpT5Sxdu0Bq/4xhAKlCPWJnUhYZA=; b=n5GlRfp6VnMhSJClYGItKPk+6Y1uta1OYNk1rb+Bytwgk7KhOlU0yd9UnHpa9P1Dk5 OP5/p9Dz0fRFppdV4q4IQolzs2XPmFSOI1fCp7vUIbqjdPgTrOJ5CrZfBCAd0DAbifsI hL9DrgxQYP1HmJ1r30Lh5fG3QmA3vQutolEzovWD78D7jFrQXJtHLFJCImGXxerF5J5G 4Deg2N/w70RXfQ+Bw6PqXrxn0IA0n12QwypieZQteCGaqX8Otca7x+Bbd7DNrIDXRb6H 7Y6AZnvOmjUj0QxXkUZUHSLyYDb6dvqE3NsRwDnzQVc8zKmNkRnf3p/qxZ9bBzx4E0ho oQ+Q== X-Forwarded-Encrypted: i=1; AJvYcCWpzz383oXic3l1iiYzkRN5cPNzszDxY07+bIsq3S+MRgVnKUo6cl0UVhTURu8nkGVlf75iTnbANieMNmo=@vger.kernel.org X-Gm-Message-State: AOJu0Ywlxd20CqDcTx3u3K8v9vmni+MVfrcfcfzxdyJ4rBt01Sx5/pag rSSGotz8uluy+0GR29BH0V8p2WGv3RaQ6P/GJT2Dw0Ohl5erL0RxdR93sS90qMqs4E8VXrvlwE+ sQQcyfGTE5A== X-Google-Smtp-Source: AGHT+IGH5noWtFNaTsbN875vKa4LJH+6nipS2I+HvnDRFXrBbmRj/sTqaIhQjDr9GIyLPz+Si3nAHutYaq+4 X-Received: from pldg6.prod.google.com ([2002:a17:903:3a86:b0:235:6d5:688b]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:d4d0:b0:235:27b6:a891 with SMTP id d9443c01a7336-2364ca469aamr16477225ad.28.1749676627115; Wed, 11 Jun 2025 14:17:07 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:34 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: <75edc2c08a63316135ddf59d0961f1fadbe2e264.1749672978.git.afranji@google.com> Subject: [RFC PATCH v2 07/10] KVM: selftests: Refactor userspace_mem_region creation out of vm_mem_add From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Refactor the creation and committing of userspace_mem_region to their own functions so that they can reused by future TDX migration functions. Signed-off-by: Ryan Afranji --- tools/testing/selftests/kvm/lib/kvm_util.c | 147 +++++++++++++-------- 1 file changed, 89 insertions(+), 58 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 2b442639ee2d..3c131718b81a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -974,50 +974,47 @@ void vm_set_user_memory_region2(struct kvm_vm *vm, ui= nt32_t slot, uint32_t flags errno, strerror(errno)); } =20 - -/* FIXME: This thing needs to be ripped apart and rewritten. */ -void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, - uint64_t guest_paddr, uint32_t slot, uint64_t npages, - uint32_t flags, int guest_memfd, uint64_t guest_memfd_offset) +static struct userspace_mem_region *vm_mem_region_alloc(struct kvm_vm *vm, + uint64_t guest_paddr, + uint32_t slot, + size_t npages, + uint32_t flags) { - int ret; struct userspace_mem_region *region; - size_t backing_src_pagesz =3D get_backing_src_pagesz(src_type); - size_t mem_size =3D npages * vm->page_size; - size_t alignment; =20 TEST_REQUIRE_SET_USER_MEMORY_REGION2(); =20 TEST_ASSERT(vm_adjust_num_guest_pages(vm->mode, npages) =3D=3D npages, - "Number of guest pages is not compatible with the host. " - "Try npages=3D%d", vm_adjust_num_guest_pages(vm->mode, npages)); + "Number of guest pages is not compatible with the host. " + "Try npages=3D%d", vm_adjust_num_guest_pages(vm->mode, npages)); =20 TEST_ASSERT((guest_paddr % vm->page_size) =3D=3D 0, "Guest physical " - "address not on a page boundary.\n" - " guest_paddr: 0x%lx vm->page_size: 0x%x", - guest_paddr, vm->page_size); + "address not on a page boundary.\n" + " guest_paddr: 0x%lx vm->page_size: 0x%x", + guest_paddr, vm->page_size); TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) - <=3D vm->max_gfn, "Physical range beyond maximum " - "supported physical address,\n" - " guest_paddr: 0x%lx npages: 0x%lx\n" - " vm->max_gfn: 0x%lx vm->page_size: 0x%x", - guest_paddr, npages, vm->max_gfn, vm->page_size); + <=3D vm->max_gfn, "Physical range beyond maximum " + "supported physical address,\n" + " guest_paddr: 0x%lx npages: 0x%lx\n" + " vm->max_gfn: 0x%lx vm->page_size: 0x%x", + guest_paddr, npages, vm->max_gfn, vm->page_size); =20 /* * Confirm a mem region with an overlapping address doesn't * already exist. */ region =3D (struct userspace_mem_region *) userspace_mem_region_find( - vm, guest_paddr, (guest_paddr + npages * vm->page_size) - 1); + vm, guest_paddr, + (guest_paddr + npages * vm->page_size) - 1); if (region !=3D NULL) TEST_FAIL("overlapping userspace_mem_region already " - "exists\n" - " requested guest_paddr: 0x%lx npages: 0x%lx " - "page_size: 0x%x\n" - " existing guest_paddr: 0x%lx size: 0x%lx", - guest_paddr, npages, vm->page_size, - (uint64_t) region->region.guest_phys_addr, - (uint64_t) region->region.memory_size); + "exists\n" + " requested guest_paddr: 0x%lx npages: 0x%lx " + "page_size: 0x%x\n" + " existing guest_paddr: 0x%lx size: 0x%lx", + guest_paddr, npages, vm->page_size, + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size); =20 /* Confirm no region with the requested slot already exists. */ hash_for_each_possible(vm->regions.slot_hash, region, slot_node, @@ -1026,19 +1023,73 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_back= ing_src_type src_type, continue; =20 TEST_FAIL("A mem region with the requested slot " - "already exists.\n" - " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" - " existing slot: %u paddr: 0x%lx size: 0x%lx", - slot, guest_paddr, npages, - region->region.slot, - (uint64_t) region->region.guest_phys_addr, - (uint64_t) region->region.memory_size); + "already exists.\n" + " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" + " existing slot: %u paddr: 0x%lx size: 0x%lx", + slot, guest_paddr, npages, + region->region.slot, + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size); } =20 /* Allocate and initialize new mem region structure. */ region =3D calloc(1, sizeof(*region)); TEST_ASSERT(region !=3D NULL, "Insufficient Memory"); - region->mmap_size =3D mem_size; + + region->unused_phy_pages =3D sparsebit_alloc(); + if (vm_arch_has_protected_memory(vm)) + region->protected_phy_pages =3D sparsebit_alloc(); + sparsebit_set_num(region->unused_phy_pages, + guest_paddr >> vm->page_shift, npages); + region->region.slot =3D slot; + region->region.flags =3D flags; + region->region.guest_phys_addr =3D guest_paddr; + region->region.memory_size =3D npages * vm->page_size; + + region->mmap_start =3D NULL; + region->mmap_size =3D 0; + region->host_mem =3D NULL; + region->fd =3D -1; + + return region; +} + +static void userspace_mem_region_commit(struct kvm_vm *vm, + struct userspace_mem_region *region) +{ + int ret; + + region->region.userspace_addr =3D (uintptr_t) region->host_mem; + ret =3D __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); + TEST_ASSERT(ret =3D=3D 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n" + " rc: %i errno: %i\n" + " slot: %u flags: 0x%x\n" + " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d", + ret, errno, region->region.slot, region->region.flags, + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size, + region->region.guest_memfd); + + /* Add to quick lookup data structures */ + vm_userspace_mem_region_gpa_insert(&vm->regions.gpa_tree, region); + vm_userspace_mem_region_hva_insert(&vm->regions.hva_tree, region); + hash_add(vm->regions.slot_hash, ®ion->slot_node, + region->region.slot); +} + +/* FIXME: This thing needs to be ripped apart and rewritten. */ +void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, + uint64_t guest_paddr, uint32_t slot, uint64_t npages, + uint32_t flags, int guest_memfd, uint64_t guest_memfd_offset) +{ + int ret; + struct userspace_mem_region *region; + size_t backing_src_pagesz =3D get_backing_src_pagesz(src_type); + size_t mem_size =3D npages * vm->page_size; + size_t alignment; + + region =3D vm_mem_region_alloc(vm, guest_paddr, slot, npages, + flags); =20 #ifdef __s390x__ /* On s390x, the host address must be aligned to 1M (due to PGSTEs) */ @@ -1058,6 +1109,8 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backin= g_src_type src_type, =20 TEST_ASSERT_EQ(guest_paddr, align_up(guest_paddr, backing_src_pagesz)); =20 + region->mmap_size =3D mem_size; + /* Add enough memory to align up if necessary */ if (alignment > 1) region->mmap_size +=3D alignment; @@ -1117,29 +1170,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backi= ng_src_type src_type, region->region.guest_memfd =3D -1; } =20 - region->unused_phy_pages =3D sparsebit_alloc(); - if (vm_arch_has_protected_memory(vm)) - region->protected_phy_pages =3D sparsebit_alloc(); - sparsebit_set_num(region->unused_phy_pages, - guest_paddr >> vm->page_shift, npages); - region->region.slot =3D slot; - region->region.flags =3D flags; - region->region.guest_phys_addr =3D guest_paddr; - region->region.memory_size =3D npages * vm->page_size; - region->region.userspace_addr =3D (uintptr_t) region->host_mem; - ret =3D __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); - TEST_ASSERT(ret =3D=3D 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n" - " rc: %i errno: %i\n" - " slot: %u flags: 0x%x\n" - " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d", - ret, errno, slot, flags, - guest_paddr, (uint64_t) region->region.memory_size, - region->region.guest_memfd); - - /* Add to quick lookup data structures */ - vm_userspace_mem_region_gpa_insert(&vm->regions.gpa_tree, region); - vm_userspace_mem_region_hva_insert(&vm->regions.hva_tree, region); - hash_add(vm->regions.slot_hash, ®ion->slot_node, slot); + userspace_mem_region_commit(vm, region); =20 /* If shared memory, create an alias. */ if (region->fd >=3D 0) { --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E1D624E4A8 for ; Wed, 11 Jun 2025 21:17:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676631; cv=none; b=K268cDkO9weC9LHdfnWlwzWEeSnppUiyv9NjvP5d3Fo95a9JphlYHkz4RpGJrAf/9W3mURlS0M5wzfJxumECkytUnMShweUIjeGnTezokx3tf4Dv5EqiBOBo3q6C/fBKUujWRWK4InjvcsLugkVr+DOrVCYIzEMMRIfUTWIZOu4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676631; c=relaxed/simple; bh=9bHODc+L3jY8CU4AGA0f9Uj2uodDYKTbx2LQsdLuFe8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dup8Ihed6FsBPIoLCha9zQPpfIpgaOJzLtg6x7aEczECqfrSLCYH1Ua/rpodQ+K5IiH7YaBIUsUX2xc+WxHs8v69Edvx4qyvAmu2cV4pIG3+Z+5+7Uf02jNMwCkBnMmY9+3UpeeywYhFzGy/X9TaPcDTgxWJmKdz8qfw4p8irwo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=yW4OwMA5; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="yW4OwMA5" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-7462aff55bfso204735b3a.2 for ; Wed, 11 Jun 2025 14:17:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676629; x=1750281429; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ssjnbQ4kJflk7fXBHBaf7ALVkd5j+ovjxWVLHw4vo40=; b=yW4OwMA5+E3hWIoxPhcBzfrFkWa/ZxvxscuiJyItpBbf32NStZuTgoNAket1hu0HCN RNTOg6fWhNGCtoMKBt9MvSWs3Bht0wsj8KGvGBPY8BiWyrtrnfzC0iRG7fKOLmGUalVm 5OaSu4i7OIE91w8ILEbFbXzKSSfWDSQX3PHijTAjLurasKbzC2D0vkvXL6Du9WFBhs/x H22bKbu2IjNZzP6HQRFC7dED+uD+7bxucl3nM5J06l+FKzhWYmPkvkFzXgpJAHNrkAZ/ OXBbQ3bgenhidqd7qFJOVVag7ptjyke2Mpzh+MTH3boyjXIOiPR9s0kOjUFqxbooCvyp nSvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676629; x=1750281429; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=ssjnbQ4kJflk7fXBHBaf7ALVkd5j+ovjxWVLHw4vo40=; b=oCaqoj4PW34uWq5tjtogP6Ro0u4+dpfCFM0U1XaF4uhgszp7H5LMh+Zwxo3pUxCcok yp8r5FmGQada46QIBlCc5zi7k5vic8eKSyO9+LOdYwFE1JnscsnZeFnjxAfIXwGJS11Q SrBTVS3yKO3n3LDEq/PLiARO8GY92K8vr8VxbzVRocjJBrWLzURqY86IBYPNxXNVnSqR AuY0gSjgrHlrsIFuIdcE9Oez/V2naGxcdjB8TYaKUETPU+nBH2On9L+DQJGTF/e/sDEy otG11od+f81+uJFKUrp1JZ4d1uXYD/LS8hr5h0oXWBUWZQIo1MOHGM05Huffa+TaUWZP jejw== X-Forwarded-Encrypted: i=1; AJvYcCUk3nekGcd9IsIbvWCWjR8OMNg7t+ZpG7AxtTUCh23YE0kwyUCV/UrX2kwqZS2QjT8iUtaY9OnvpPqB7+U=@vger.kernel.org X-Gm-Message-State: AOJu0YygoIX/SJrEK2F3U2ywzXj+fAbCVD83xCPgD+y0rcaNc9CyC7CM O/LuZ7tHAPIc04acgJ8nj9L40b9PYiHjOlaJhsnvkBFFzItberqoG9007k7pOB3ZnQ2vMmCbTOE hiiJV5sniog== X-Google-Smtp-Source: AGHT+IGt8itXpNhAIFBj62DiJ64U9JmDFLzjGyRqSV6OdShtMpiACjneNt3RcQvG2dGMamb53/SKPyXvNeW+ X-Received: from pfbfr17.prod.google.com ([2002:a05:6a00:8111:b0:73e:665:360]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:aa7:8882:0:b0:73d:ff02:8d83 with SMTP id d2e1a72fcca58-7486cb21c08mr7425055b3a.3.1749676628808; Wed, 11 Jun 2025 14:17:08 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:35 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: <92f22ace98238b79c25bd8759c75a1143d82a741.1749672978.git.afranji@google.com> Subject: [RFC PATCH v2 08/10] KVM: selftests: TDX: Add tests for TDX in-place migration From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Sagi Shahar Adds selftests for TDX in-place migration. Signed-off-by: Ryan Afranji Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/include/kvm_util.h | 20 + .../selftests/kvm/include/x86/tdx/tdx_util.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 50 ++- .../selftests/kvm/lib/x86/tdx/tdx_util.c | 3 +- .../selftests/kvm/x86/tdx_migrate_tests.c | 358 ++++++++++++++++++ 6 files changed, 429 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86/tdx_migrate_tests.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 1c7ea61e9031..d4c8cfb5910f 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -155,6 +155,7 @@ TEST_GEN_PROGS_x86 +=3D pre_fault_memory_test TEST_GEN_PROGS_x86 +=3D x86/tdx_vm_test TEST_GEN_PROGS_x86 +=3D x86/tdx_shared_mem_test TEST_GEN_PROGS_x86 +=3D x86/tdx_upm_test +TEST_GEN_PROGS_x86 +=3D x86/tdx_migrate_tests =20 # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86 +=3D x86/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index 267f78f3f16f..1b6489081e74 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -110,6 +110,9 @@ struct kvm_vm { =20 struct kvm_binary_stats stats; =20 + /* VM was migrated using KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM */ + bool enc_migrated; + /* * KVM region slots. These are the default memslots used by page * allocators, e.g., lib/elf uses the memslots[MEM_REGION_CODE] @@ -673,6 +676,7 @@ static inline bool vm_arch_has_protected_memory(struct = kvm_vm *vm) =20 void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t fl= ags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa= ); +void vm_migrate_mem_regions(struct kvm_vm *dst_vm, struct kvm_vm *src_vm); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id); void vm_populate_vaddr_bitmap(struct kvm_vm *vm); @@ -1132,6 +1136,22 @@ static inline struct kvm_vcpu *vm_vcpu_add(struct kv= m_vm *vm, uint32_t vcpu_id, return vcpu; } =20 +/* + * Adds a vCPU with no defaults. This vcpu will be used for migration + * + * Input Args: + * vm - Virtual Machine + * vcpu_id - The id of the VCPU to add to the VM. + */ +struct kvm_vcpu *vm_arch_vcpu_add_for_migration(struct kvm_vm *vm, + uint32_t vcpu_id); + +static inline struct kvm_vcpu *vm_vcpu_add_for_migration(struct kvm_vm *vm, + uint32_t vcpu_id) +{ + return vm_arch_vcpu_add_for_migration(vm, vcpu_id); +} + /* Re-create a vCPU after restarting a VM, e.g. for state save/restore tes= ts. */ struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id= ); =20 diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools= /testing/selftests/kvm/include/x86/tdx/tdx_util.h index ae39b78aa4af..9b495e621225 100644 --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h @@ -9,6 +9,7 @@ extern uint64_t tdx_s_bit; void tdx_filter_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid_data); void __tdx_mask_cpuid_features(struct kvm_cpuid_entry2 *entry); +void tdx_enable_capabilities(struct kvm_vm *vm); =20 struct kvm_vcpu *td_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, void *gu= est_code); =20 diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 3c131718b81a..9dc3c7bf0443 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -805,8 +805,10 @@ static void __vm_mem_region_delete(struct kvm_vm *vm, =20 sparsebit_free(®ion->unused_phy_pages); sparsebit_free(®ion->protected_phy_pages); - ret =3D munmap(region->mmap_start, region->mmap_size); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); + if (!vm->enc_migrated) { + ret =3D munmap(region->mmap_start, region->mmap_size); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); + } if (region->fd >=3D 0) { /* There's an extra map when using shared memory. */ ret =3D munmap(region->mmap_alias, region->mmap_size); @@ -1287,6 +1289,50 @@ void vm_mem_region_move(struct kvm_vm *vm, uint32_t = slot, uint64_t new_gpa) ret, errno, slot, new_gpa); } =20 +static void vm_migrate_mem_region(struct kvm_vm *dst_vm, struct kvm_vm *sr= c_vm, + struct userspace_mem_region *src_region) +{ + struct userspace_mem_region *dst_region; + int dst_guest_memfd; + + dst_guest_memfd =3D + vm_link_guest_memfd(dst_vm, src_region->region.guest_memfd, 0); + + dst_region =3D vm_mem_region_alloc( + dst_vm, src_region->region.guest_phys_addr, + src_region->region.slot, + src_region->region.memory_size / src_vm->page_size, + src_region->region.flags); + + dst_region->mmap_size =3D src_region->mmap_size; + dst_region->mmap_start =3D src_region->mmap_start; + dst_region->host_mem =3D src_region->host_mem; + + src_region->mmap_start =3D 0; + src_region->host_mem =3D 0; + + dst_region->region.guest_memfd =3D dst_guest_memfd; + dst_region->region.guest_memfd_offset =3D + src_region->region.guest_memfd_offset; + + userspace_mem_region_commit(dst_vm, dst_region); +} + +void vm_migrate_mem_regions(struct kvm_vm *dst_vm, struct kvm_vm *src_vm) +{ + int bkt; + struct hlist_node *node; + struct userspace_mem_region *region; + + hash_for_each_safe(src_vm->regions.slot_hash, bkt, node, region, + slot_node) { + TEST_ASSERT(region->region.guest_memfd >=3D 0, + "Migrating mem regions is only supported for GUEST_MEMFD"); + + vm_migrate_mem_region(dst_vm, src_vm, region); + } +} + /* * VM Memory Region Delete * diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/tes= ting/selftests/kvm/lib/x86/tdx/tdx_util.c index c5bee67099c5..ef03d42f58d0 100644 --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c @@ -344,7 +344,7 @@ static void register_encrypted_memory_region(struct kvm= _vm *vm, * TD creation/setup/finalization */ =20 -static void tdx_enable_capabilities(struct kvm_vm *vm) +void tdx_enable_capabilities(struct kvm_vm *vm) { int rc; =20 @@ -574,7 +574,6 @@ void td_initialize(struct kvm_vm *vm, enum vm_mem_backi= ng_src_type src_type, uint64_t nr_pages_required; =20 tdx_enable_capabilities(vm); - tdx_td_init(vm, attributes); =20 nr_pages_required =3D vm_nr_pages_required(VM_MODE_DEFAULT, 1, 0); diff --git a/tools/testing/selftests/kvm/x86/tdx_migrate_tests.c b/tools/te= sting/selftests/kvm/x86/tdx_migrate_tests.c new file mode 100644 index 000000000000..e15da2aa0437 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/tdx_migrate_tests.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "tdx/tdcall.h" +#include "tdx/tdx.h" +#include "tdx/tdx_util.h" +#include "tdx/test_util.h" +#include +#include + +#define NR_MIGRATE_TEST_VMS 10 +#define TDX_IOEXIT_TEST_PORT 0x50 + +static int __tdx_migrate_from(int dst_fd, int src_fd) +{ + struct kvm_enable_cap cap =3D { + .cap =3D KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, + .args =3D { src_fd } + }; + + return ioctl(dst_fd, KVM_ENABLE_CAP, &cap); +} + + +static void tdx_migrate_from(struct kvm_vm *dst_vm, struct kvm_vm *src_vm) +{ + int ret; + + vm_migrate_mem_regions(dst_vm, src_vm); + ret =3D __tdx_migrate_from(dst_vm->fd, src_vm->fd); + TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno); + src_vm->enc_migrated =3D true; +} + +void guest_code(void) +{ + int ret; + uint64_t data; + + data =3D 1; + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE, + &data); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + data++; + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE, + &data); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + tdx_test_success(); +} + +static void test_tdx_migrate_vm_with_private_memory(void) +{ + struct kvm_vm *src_vm; + struct kvm_vm *dst_vm; + struct kvm_vcpu *dst_vcpu; + uint32_t data; + + printf("Verifying migration of VM with private memory:\n"); + + src_vm =3D td_create(); + td_initialize(src_vm, VM_MEM_SRC_ANONYMOUS, 0); + td_vcpu_add(src_vm, 0, guest_code); + td_finalize(src_vm); + + dst_vm =3D td_create(); + tdx_enable_capabilities(dst_vm); + dst_vcpu =3D vm_vcpu_recreate(dst_vm, 0); + + tdx_migrate_from(dst_vm, src_vm); + + kvm_vm_free(src_vm); + + tdx_run(dst_vcpu); + tdx_test_assert_io(dst_vcpu, TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE); + data =3D *(uint8_t *)((void *)dst_vcpu->run + + dst_vcpu->run->io.data_offset); + TEST_ASSERT_EQ(data, 1); + + tdx_run(dst_vcpu); + tdx_test_assert_io(dst_vcpu, TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE); + data =3D *(uint8_t *)((void *)dst_vcpu->run + + dst_vcpu->run->io.data_offset); + TEST_ASSERT_EQ(data, 2); + + tdx_run(dst_vcpu); + tdx_test_assert_success(dst_vcpu); + + kvm_vm_free(dst_vm); + + printf("\t ... PASSED\n"); +} + +static void test_tdx_migrate_running_vm(void) +{ + struct kvm_vm *src_vm; + struct kvm_vm *dst_vm; + struct kvm_vcpu *src_vcpu; + struct kvm_vcpu *dst_vcpu; + uint32_t data; + + printf("Verifying migration of a running VM:\n"); + + src_vm =3D td_create(); + td_initialize(src_vm, VM_MEM_SRC_ANONYMOUS, 0); + src_vcpu =3D td_vcpu_add(src_vm, 0, guest_code); + td_finalize(src_vm); + + dst_vm =3D td_create(); + tdx_enable_capabilities(dst_vm); + dst_vcpu =3D vm_vcpu_recreate(dst_vm, 0); + + tdx_run(src_vcpu); + tdx_test_assert_io(src_vcpu, TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE); + data =3D *(uint8_t *)((void *)src_vcpu->run + + src_vcpu->run->io.data_offset); + TEST_ASSERT_EQ(data, 1); + + tdx_migrate_from(dst_vm, src_vm); + + kvm_vm_free(src_vm); + + tdx_run(dst_vcpu); + tdx_test_assert_io(dst_vcpu, TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE); + data =3D *(uint8_t *)((void *)dst_vcpu->run + + dst_vcpu->run->io.data_offset); + TEST_ASSERT_EQ(data, 2); + + tdx_run(dst_vcpu); + tdx_test_assert_success(dst_vcpu); + + kvm_vm_free(dst_vm); + + printf("\t ... PASSED\n"); +} + +#define TDX_SHARED_MEM_TEST_PRIVATE_GVA (0x80000000) +#define TDX_SHARED_MEM_TEST_VADDR_SHARED_MASK BIT_ULL(30) +#define TDX_SHARED_MEM_TEST_SHARED_GVA \ + (TDX_SHARED_MEM_TEST_PRIVATE_GVA | \ + TDX_SHARED_MEM_TEST_VADDR_SHARED_MASK) + +#define TDX_SHARED_MEM_TEST_PRIVATE_VALUE (100) +#define TDX_SHARED_MEM_TEST_SHARED_VALUE (200) +#define TDX_SHARED_MEM_TEST_DIFF_VALUE (1) + + +static uint64_t test_mem_private_gpa; +static uint64_t test_mem_shared_gpa; + +void guest_with_shared_mem(void) +{ + uint64_t *test_mem_shared_gva =3D + (uint64_t *)TDX_SHARED_MEM_TEST_SHARED_GVA; + + uint64_t *private_data, *shared_data; + uint64_t placeholder; + uint64_t failed_gpa; + uint64_t data; + int ret; + + /* Map gpa as shared */ + tdg_vp_vmcall_map_gpa(test_mem_shared_gpa, PAGE_SIZE, + &failed_gpa); + + shared_data =3D test_mem_shared_gva; + private_data =3D &data; + + *private_data =3D TDX_SHARED_MEM_TEST_PRIVATE_VALUE; + *shared_data =3D TDX_SHARED_MEM_TEST_SHARED_VALUE; + + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE, + private_data); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + /* Exit so host can read shared value */ + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE, + &placeholder); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + *private_data +=3D TDX_SHARED_MEM_TEST_DIFF_VALUE; + *shared_data +=3D TDX_SHARED_MEM_TEST_DIFF_VALUE; + + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE, + private_data); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + /* Exit so host can read shared value */ + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE, + &placeholder); + if (ret) + tdx_test_fatal_with_data(ret, __LINE__); + + tdx_test_success(); +} + +static void test_tdx_migrate_vm_with_shared_mem(void) +{ + uint32_t private_data; + vm_vaddr_t test_mem_private_gva; + uint32_t *test_mem_hva; + struct kvm_vm *src_vm; + struct kvm_vm *dst_vm; + struct kvm_vcpu *src_vcpu; + struct kvm_vcpu *dst_vcpu; + + printf("Verifying migration of a VM with shared memory:\n"); + + src_vm =3D td_create(); + td_initialize(src_vm, VM_MEM_SRC_ANONYMOUS, 0); + src_vcpu =3D td_vcpu_add(src_vm, 0, guest_with_shared_mem); + + /* + * Set up shared memory page for testing by first allocating as private + * and then mapping the same GPA again as shared. This way, the TD does + * not have to remap its page tables at runtime. + */ + test_mem_private_gva =3D vm_vaddr_alloc(src_vm, src_vm->page_size, + TDX_SHARED_MEM_TEST_PRIVATE_GVA); + TEST_ASSERT_EQ(test_mem_private_gva, TDX_SHARED_MEM_TEST_PRIVATE_GVA); + + test_mem_hva =3D addr_gva2hva(src_vm, test_mem_private_gva); + TEST_ASSERT(test_mem_hva !=3D NULL, + "Guest address not found in guest memory regions\n"); + + test_mem_private_gpa =3D addr_gva2gpa(src_vm, test_mem_private_gva); + virt_map_shared(src_vm, TDX_SHARED_MEM_TEST_SHARED_GVA, + test_mem_private_gpa, 1); + + test_mem_shared_gpa =3D test_mem_private_gpa | src_vm->arch.s_bit; + sync_global_to_guest(src_vm, test_mem_shared_gpa); + + td_finalize(src_vm); + + dst_vm =3D td_create(); + tdx_enable_capabilities(dst_vm); + dst_vcpu =3D vm_vcpu_recreate(dst_vm, 0); + + vm_enable_cap(src_vm, KVM_CAP_EXIT_HYPERCALL, + BIT_ULL(KVM_HC_MAP_GPA_RANGE)); + + printf("Verifying shared memory accesses for TDX\n"); + + /* Begin guest execution; guest writes to shared memory. */ + printf("\t ... Starting guest execution\n"); + + /* Handle map gpa as shared */ + tdx_run(src_vcpu); + + tdx_run(src_vcpu); + tdx_test_assert_io(src_vcpu, TDX_IOEXIT_TEST_PORT, 4, PORT_WRITE); + TEST_ASSERT_EQ(*(uint32_t *)((void *)src_vcpu->run + + src_vcpu->run->io.data_offset), + TDX_SHARED_MEM_TEST_PRIVATE_VALUE); + + tdx_run(src_vcpu); + tdx_test_assert_io(src_vcpu, TDX_IOEXIT_TEST_PORT, 4, PORT_WRITE); + TEST_ASSERT_EQ(*test_mem_hva, TDX_SHARED_MEM_TEST_SHARED_VALUE); + + tdx_migrate_from(dst_vm, src_vm); + + kvm_vm_free(src_vm); + + tdx_run(dst_vcpu); + tdx_test_assert_io(dst_vcpu, TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE); + private_data =3D *(uint32_t *)((void *)dst_vcpu->run + + dst_vcpu->run->io.data_offset); + TEST_ASSERT_EQ(private_data, TDX_SHARED_MEM_TEST_PRIVATE_VALUE + + TDX_SHARED_MEM_TEST_DIFF_VALUE); + + tdx_run(dst_vcpu); + tdx_test_assert_io(dst_vcpu, TDX_IOEXIT_TEST_PORT, 4, + PORT_WRITE); + TEST_ASSERT_EQ(*test_mem_hva, TDX_SHARED_MEM_TEST_SHARED_VALUE + + TDX_SHARED_MEM_TEST_DIFF_VALUE); + + tdx_run(dst_vcpu); + tdx_test_assert_success(dst_vcpu); + + kvm_vm_free(dst_vm); + + printf("\t ... PASSED\n"); +} + +void guest_code_empty(void) +{ + tdx_test_success(); +} + +static void test_tdx_migrate_multiple_vms(void) +{ + struct kvm_vm *src_vm; + struct kvm_vm *dst_vms[NR_MIGRATE_TEST_VMS]; + int i, ret; + + printf("Verifying migration between multiple VMs:\n"); + + src_vm =3D td_create(); + td_initialize(src_vm, VM_MEM_SRC_ANONYMOUS, 0); + td_vcpu_add(src_vm, 0, guest_code_empty); + td_finalize(src_vm); + + for (i =3D 0; i < NR_MIGRATE_TEST_VMS; ++i) { + dst_vms[i] =3D td_create(); + tdx_enable_capabilities(dst_vms[i]); + vm_vcpu_recreate(dst_vms[i], 0); + } + + /* Initial migration from the src to the first dst. */ + tdx_migrate_from(dst_vms[0], src_vm); + + for (i =3D 1; i < NR_MIGRATE_TEST_VMS; i++) + tdx_migrate_from(dst_vms[i], dst_vms[i - 1]); + + /* Migrate the guest back to the original VM. */ + ret =3D __tdx_migrate_from(src_vm->fd, + dst_vms[NR_MIGRATE_TEST_VMS - 1]->fd); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EIO, + "VM that was migrated from should be dead. ret %d, errno: %d\n", + ret, errno); + + kvm_vm_free(src_vm); + for (i =3D 0; i < NR_MIGRATE_TEST_VMS; ++i) + kvm_vm_free(dst_vms[i]); + + printf("\t ... PASSED\n"); +} + +int main(int argc, char *argv[]) +{ + if (!is_tdx_enabled()) { + print_skip("TDX is not supported by the KVM"); + exit(KSFT_SKIP); + } + + run_in_new_process(&test_tdx_migrate_vm_with_private_memory); + run_in_new_process(&test_tdx_migrate_running_vm); + run_in_new_process(&test_tdx_migrate_vm_with_shared_mem); + run_in_new_process(&test_tdx_migrate_multiple_vms); + + return 0; +} --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3A7B325486E for ; Wed, 11 Jun 2025 21:17:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676633; cv=none; b=Z7U8U5WI+qKFcI7S7rZ1TleNJUv2WVh2bnFegUFTXYjdGpZPn7bljHhirC/LptXoTRe0xLeWzFlPsf+IU7b5ji9hefR6VJttOiyf6ZSnE8w2y+2451O+xDPouv9g3w113N1b6Z9CDLsgY6tQdfzaqpKt/blhN8Gl5CiM+/gpm+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676633; c=relaxed/simple; bh=3IrONkjSfZHSUwPR/efaP61FbpeztFmotATV6TKU0Sg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=rMHmunHG+A/4HqQXqCDS8YBA24RgTB+5zL6HtzSJ1PZArNlkQIg3QTdrVMpXAeLQnWbHCvyl91Y0/2KFoAqwr2UNusLdK/a0XKAgAwMqm2ETkOfDt9C3KC1Vhoej0/WmcW9EZ4ZC65fmWfU3x0nrTmmYkceBUlRbx4l27VEQY8Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=QzLizjIE; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="QzLizjIE" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b115fb801bcso171757a12.3 for ; Wed, 11 Jun 2025 14:17:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676630; x=1750281430; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=QL/RdKZkxRdzT4JBOycXHxG8/DXNnGB2DrLug1v+dg0=; b=QzLizjIEbHmnTqzPmI8H+M0jARKhiC6q/+DC5kaqSa4sWrmltBP+ZVmiuNI5lP8eP9 OzN12uy98sTPn6niPtKYwVLoCqQe9IPRQxA3dzAW1wrvUamEZ3F/oGwpOmDmgcogbsfE tgJSqGtcv6oNRastGWCCP62jGtaa5ESEwA9SFcUCWeB//GHJcmuB9sUDZ2+/gp4OcOqY MxVBciLxCAHlTAV07QK0IekheckSEgaopBkMx8pxTw+AaWkinBf6RF//rNjTP7BnJYMK shIcNvHiuGjQwkC3mNjpF0RZDocgtJYYAmbxTn7xmLtuoBt4ViUfYCa/HKpd3LtZJnnr f8Tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676630; x=1750281430; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=QL/RdKZkxRdzT4JBOycXHxG8/DXNnGB2DrLug1v+dg0=; b=axXM2MsNslThoJugGsjrhIABR08a0pzhV/QWw5rvQABMPCtRJfUjio7CYWZIpvAx63 bKpCX1ZCJM54cZMTAzysCKeVWNR3tiUvo9noroqEE/57ZN7raIUIc1IEyj0jzySEQU9x iAAhZrHIwTig8Pstml2Dh7vvHD9w8vu9lDnF34z8G70YNya5dR74CWGGJMilZI5oVlGy z/1bn0ie0VrJ908OmLIpcQg5LeTdHBzQY2vSYk5SgBUAZRqKV931WLkPTyutKpw4vkOG 2q8EAlVv3NQEDKEveMLnQkPXgt4MRz/5iXJA0mn4vDoQxdaid5qeFThPAAChpWOryw03 7zsw== X-Forwarded-Encrypted: i=1; AJvYcCXvU0eIKGuq1DuIjKVCDjskzttFqoZcivURGSAn4ta4DhIyuF4FlUQW9qhXTx3w8eplFiHBPh9Dt9P1dns=@vger.kernel.org X-Gm-Message-State: AOJu0YzT5Cxa0a5T2Ee411FoMFH9iSg8x5IZXh9uYw6fk+T8WC1GLAzw UhfdlJK+XjtdxuxpkDGrQ8WaXM0x0FKMwxk05ftH3wN/sM+vQzclwBQqh9lIXHxO9BXWvpcG7zx WFlalxqXrWA== X-Google-Smtp-Source: AGHT+IH14aTAy2iw/U4wnQQFAPnkTzil6bCM78S3xEy8UEiHKZBuOafN0hQzXY+znZ0hE18aaQ9zR5PzBo4m X-Received: from plog2.prod.google.com ([2002:a17:902:8682:b0:235:85e:1fac]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:f60e:b0:236:363e:55d with SMTP id d9443c01a7336-23641b19883mr73107675ad.28.1749676630519; Wed, 11 Jun 2025 14:17:10 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:36 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: <09d68c4748c0804f86aa6d943cf416742ef0f741.1749672978.git.afranji@google.com> Subject: [RFC PATCH v2 09/10] KVM: selftests: Add TDX support for ucalls From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ackerley Tng ucalls for non-Coco VMs work by having the guest write to the rdi register, then perform an io instruction to exit to the host. The host then reads rdi using kvm_get_regs(). CPU registers can't be read using kvm_get_regs() for TDX, so TDX guests use MMIO to pass the struct ucall's hva to the host. MMIO was chosen because it is one of the simplest (hence unlikely to fail) mechanisms that support passing 8 bytes from guest to host. A new kvm_mem_region_type, MEM_REGION_UCALL, is added so TDX VMs can set up a different memslot for the ucall_pool that is set up as shared memory. Signed-off-by: Ackerley Tng Signed-off-by: Ryan Afranji --- .../testing/selftests/kvm/include/kvm_util.h | 1 + .../testing/selftests/kvm/include/x86/ucall.h | 4 +- .../testing/selftests/kvm/lib/ucall_common.c | 2 +- .../selftests/kvm/lib/x86/tdx/tdx_util.c | 40 +++++++ tools/testing/selftests/kvm/lib/x86/ucall.c | 108 ++++++++++++------ 5 files changed, 118 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index 1b6489081e74..8b252a668c78 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -80,6 +80,7 @@ enum kvm_mem_region_type { MEM_REGION_PT, MEM_REGION_TEST_DATA, MEM_REGION_TDX_BOOT_PARAMS, + MEM_REGION_UCALL, NR_MEM_REGIONS, }; =20 diff --git a/tools/testing/selftests/kvm/include/x86/ucall.h b/tools/testin= g/selftests/kvm/include/x86/ucall.h index d3825dcc3cd9..0494a4a21557 100644 --- a/tools/testing/selftests/kvm/include/x86/ucall.h +++ b/tools/testing/selftests/kvm/include/x86/ucall.h @@ -6,8 +6,6 @@ =20 #define UCALL_EXIT_REASON KVM_EXIT_IO =20 -static inline void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) -{ -} +void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa); =20 #endif diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing= /selftests/kvm/lib/ucall_common.c index 42151e571953..5f195d4d15dc 100644 --- a/tools/testing/selftests/kvm/lib/ucall_common.c +++ b/tools/testing/selftests/kvm/lib/ucall_common.c @@ -33,7 +33,7 @@ void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) int i; =20 vaddr =3D vm_vaddr_alloc_shared(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR, - MEM_REGION_DATA); + MEM_REGION_UCALL); hdr =3D (struct ucall_header *)addr_gva2hva(vm, vaddr); memset(hdr, 0, sizeof(*hdr)); =20 diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/tes= ting/selftests/kvm/lib/x86/tdx/tdx_util.c index ef03d42f58d0..a3612bf187a0 100644 --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c @@ -11,6 +11,7 @@ #include "tdx/td_boot.h" #include "tdx/tdx.h" #include "test_util.h" +#include "ucall_common.h" =20 uint64_t tdx_s_bit; =20 @@ -568,6 +569,43 @@ static void td_setup_boot_parameters(struct kvm_vm *vm= , enum vm_mem_backing_src_ TEST_ASSERT_EQ(addr, TD_BOOT_PARAMETERS_GPA); } =20 +/* + * GPA where ucall headers/pool will be set up + * + * TD_UCALL_POOL_GPA is arbitrarily chosen to + * + * + Be within the 4GB address space + * + Not clash with the other memslots for boot parameters, boot code and = test + * code + */ +#define TD_UCALL_POOL_GPA 0x30000000 +/* + * GPA to use for ucall MMIO writes + * + * TD_UCALL_MMIO_GPA is arbitrarily chosen to + * + * + Be within the 4GB address space + * + Not clash with the other memslots for boot parameters, boot code and = test + * code + * + Not be configured in any memslot (unconfigured GPAs are treated as + * MMIOs). For now, TDX VMs can't be used with KVM_MEM_READONLY so using + * readonly memslots won't work for TDX VMs. + */ +#define TD_UCALL_MMIO_GPA 0x40000000 +#define TD_UCALL_MEMSLOT 4 + +static void td_setup_ucall(struct kvm_vm *vm) +{ + int npages; + + npages =3D ucall_nr_pages_required(PAGE_SIZE); + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, TD_UCALL_POOL_GPA, + TD_UCALL_MEMSLOT, npages, 0); + vm->memslots[MEM_REGION_UCALL] =3D TD_UCALL_MEMSLOT; + + ucall_init(vm, TD_UCALL_MMIO_GPA); +} + void td_initialize(struct kvm_vm *vm, enum vm_mem_backing_src_type src_typ= e, uint64_t attributes) { @@ -593,6 +631,8 @@ void td_initialize(struct kvm_vm *vm, enum vm_mem_backi= ng_src_type src_type, =20 td_setup_boot_code(vm, src_type); td_setup_boot_parameters(vm, src_type); + + td_setup_ucall(vm); } =20 void td_finalize(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c b/tools/testing/se= lftests/kvm/lib/x86/ucall.c index 1265cecc7dd1..5cf915dbb588 100644 --- a/tools/testing/selftests/kvm/lib/x86/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86/ucall.c @@ -5,52 +5,94 @@ * Copyright (C) 2018, Red Hat, Inc. */ #include "kvm_util.h" +#include "kvm_util_types.h" +#include "tdx/tdx.h" =20 #define UCALL_PIO_PORT ((uint16_t)0x1000) =20 +static uint8_t vm_type; +static vm_paddr_t host_ucall_mmio_gpa; +static vm_paddr_t ucall_mmio_gpa; + +void ucall_arch_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa) +{ + vm_type =3D vm->type; + sync_global_to_guest(vm, vm_type); + + host_ucall_mmio_gpa =3D ucall_mmio_gpa =3D mmio_gpa; + +#ifdef __x86_64__ + if (vm_type =3D=3D KVM_X86_TDX_VM) + ucall_mmio_gpa |=3D vm->arch.s_bit; +#endif + + sync_global_to_guest(vm, ucall_mmio_gpa); +} + void ucall_arch_do_ucall(vm_vaddr_t uc) { - /* - * FIXME: Revert this hack (the entire commit that added it) once nVMX - * preserves L2 GPRs across a nested VM-Exit. If a ucall from L2, e.g. - * to do a GUEST_SYNC(), lands the vCPU in L1, any and all GPRs can be - * clobbered by L1. Save and restore non-volatile GPRs (clobbering RBP - * in particular is problematic) along with RDX and RDI (which are - * inputs), and clobber volatile GPRs. *sigh* - */ -#define HORRIFIC_L2_UCALL_CLOBBER_HACK \ + switch (vm_type) { + case KVM_X86_TDX_VM: + tdg_vp_vmcall_ve_request_mmio_write(ucall_mmio_gpa, 8, uc); + return; + default: + /* + * FIXME: Revert this hack (the entire commit that added it) + * once nVMX preserves L2 GPRs across a nested VM-Exit. If a + * ucall from L2, e.g. to do a GUEST_SYNC(), lands the vCPU in + * L1, any and all GPRs can be clobbered by L1. Save and + * restore non-volatile GPRs (clobbering RBP in particular is + * problematic) along with RDX and RDI (which are inputs), and + * clobber volatile GPRs. *sigh* + */ +#define HORRIFIC_L2_UCALL_CLOBBER_HACK \ "rcx", "rsi", "r8", "r9", "r10", "r11" =20 - asm volatile("push %%rbp\n\t" - "push %%r15\n\t" - "push %%r14\n\t" - "push %%r13\n\t" - "push %%r12\n\t" - "push %%rbx\n\t" - "push %%rdx\n\t" - "push %%rdi\n\t" - "in %[port], %%al\n\t" - "pop %%rdi\n\t" - "pop %%rdx\n\t" - "pop %%rbx\n\t" - "pop %%r12\n\t" - "pop %%r13\n\t" - "pop %%r14\n\t" - "pop %%r15\n\t" - "pop %%rbp\n\t" - : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory", - HORRIFIC_L2_UCALL_CLOBBER_HACK); + asm volatile("push %%rbp\n\t" + "push %%r15\n\t" + "push %%r14\n\t" + "push %%r13\n\t" + "push %%r12\n\t" + "push %%rbx\n\t" + "push %%rdx\n\t" + "push %%rdi\n\t" + "in %[port], %%al\n\t" + "pop %%rdi\n\t" + "pop %%rdx\n\t" + "pop %%rbx\n\t" + "pop %%r12\n\t" + "pop %%r13\n\t" + "pop %%r14\n\t" + "pop %%r15\n\t" + "pop %%rbp\n\t" + : + : [port] "d"(UCALL_PIO_PORT), "D"(uc) + : "rax", "memory", HORRIFIC_L2_UCALL_CLOBBER_HACK); + } } =20 void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu) { struct kvm_run *run =3D vcpu->run; =20 - if (run->exit_reason =3D=3D KVM_EXIT_IO && run->io.port =3D=3D UCALL_PIO_= PORT) { - struct kvm_regs regs; + switch (vm_type) { + case KVM_X86_TDX_VM: + if (vcpu->run->exit_reason =3D=3D KVM_EXIT_MMIO && + vcpu->run->mmio.phys_addr =3D=3D host_ucall_mmio_gpa && + vcpu->run->mmio.len =3D=3D 8 && vcpu->run->mmio.is_write) { + uint64_t data =3D *(uint64_t *)vcpu->run->mmio.data; + + return (void *)data; + } + return NULL; + default: + if (run->exit_reason =3D=3D KVM_EXIT_IO && + run->io.port =3D=3D UCALL_PIO_PORT) { + struct kvm_regs regs; =20 - vcpu_regs_get(vcpu, ®s); - return (void *)regs.rdi; + vcpu_regs_get(vcpu, ®s); + return (void *)regs.rdi; + } + return NULL; } - return NULL; } --=20 2.50.0.rc1.591.g9c95f17f64-goog From nobody Sat Oct 11 00:30:47 2025 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE8C4257440 for ; Wed, 11 Jun 2025 21:17:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676634; cv=none; b=bASoFsmL+DXA91WcaNx06c9sHKMrDWcq0V5np1tHHSVwn6KHaZgMcAFYPkBMVQDtMh4ZJqXLtU66/zY21906A0y76FECERiP7aGF7pXBBbKRZ9pHbxkBi90l/lyCzVIaZJVH+IaMTZQW0mLQ+YM6mXoHjXlwPo1ptmRQOCPyiaA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749676634; c=relaxed/simple; bh=lE6nUOIrKb4G9fRr4Fu+box3ulN6PQJB0SdDXJ5axmc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Zf3ym243r9Vy8aPuw0juPhDdvo65H7ycCsLo83UPtjMVr0YXqzlcAPiC3YdGwUmtb1qyXKOJNiTfZH3PAW/7EadHXwA6EzCUqUlrkIQTeaxyb/hmQQrUQfQruy0TGmD9xOVMi+vSBSfVnr+cWOmLlUlA1yUGrfLgla01RNFdyag= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=clHW15g6; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--afranji.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="clHW15g6" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-b26db9af463so199554a12.2 for ; Wed, 11 Jun 2025 14:17:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749676632; x=1750281432; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=J6jtteubntBQN2p3kF5NvnYpZ0T18nDw91+DVALzqP8=; b=clHW15g6nMAIEe05bx4UKcajDHkPzhzaLIH8m1Lm3JVQKS8sNI3HtPuOqAHJ2q6lez rexYKQfTofnvda8gQCrwhgpqE+e7mv+TVAaGpAgKbYl/ImUv8m1xDNRCLqya2+BaFqJG fvNCLzhE1dVeUNbr+AZcHZuNijms3Z06GkDDk8YU4mfzQfZzT+b8jfHptiAZ/agPC2Qj b/GzOkzlE87s62fozUN6ZQjIoOO1peBlw7rHoRo1H0tw5gNafCRFVMqGX3S+XNW2LLzx q+xgnbzrb661auxG5942JE8jJKQ+HZpFGTLtvK25Xbshr0bqhTCqZ30Qmu+k7fNLfypU RRUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749676632; x=1750281432; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=J6jtteubntBQN2p3kF5NvnYpZ0T18nDw91+DVALzqP8=; b=MGQWRYVRN5Qr/zIGnRo7eGXUTcnntMopcN04fU5tTNcxGvyJpRhFH02siUnNjoT6yb vF1gu3Y7kNxk7JFqUxuK3iay0BmoTVjgIcq6Yqd8f1JTeW1U7IpPn0nHqpM1I3ZbZk/2 VDLkviebgvqS58l31EBLWejcbXFLhPmMIwUTUUGgyWJUJS+O1E2xsUyuOUpi08yI0w9e O6p9x2XKuNyMTSWR0vJvGjTzisQpQt9hod9Yz5aBizTubOzuTetPkjbna+WhSlxFLS1W GsfTN5QQxROKOiemkmkOYq4Ziy4BGO98ZvQKFb2/+qGz5czNIiH03Eh3SWT+eYLuobXb bCZw== X-Forwarded-Encrypted: i=1; AJvYcCU+OP8fS9iK2+hCSloBvNFU8NP1YoJ37VBMZxN7xhSF56/peNQxQrd9rh9BKcN9eRS5QhuUHA6/icWJFwQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwT+Q7uhao1ULbZgwKoco2YUom99a1SRp6wq+x+8KYp4tPzT/9R OYZ40CcJYIOX52xqp0fi5vm+QFpc1QSe+Ginq76bYBDyjcpJaxM+Zb144ZlySMSI/J2RJ0ZbnG/ PqU8brUi6nA== X-Google-Smtp-Source: AGHT+IEr8iX/cIgcvsGYjAWSEZKLzLBYLe9qYqD9d7H++gZpo2ukhpqL6kw+SW8ooyNprJAB1kFZlg6/m6pQ X-Received: from pgdu24.prod.google.com ([2002:a05:6a02:2f58:b0:b2f:b096:8b5a]) (user=afranji job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:431c:b0:201:85f4:ade6 with SMTP id adf61e73a8af0-21f9b8f4694mr394232637.27.1749676632082; Wed, 11 Jun 2025 14:17:12 -0700 (PDT) Date: Wed, 11 Jun 2025 21:16:37 +0000 In-Reply-To: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.50.0.rc1.591.g9c95f17f64-goog Message-ID: Subject: [RFC PATCH v2 10/10] KVM: selftests: Add irqfd/interrupts test for TDX with migration From: Ryan Afranji To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, x86@kernel.org Cc: sagis@google.com, bp@alien8.de, chao.p.peng@linux.intel.com, dave.hansen@linux.intel.com, dmatlack@google.com, erdemaktas@google.com, isaku.yamahata@intel.com, kai.huang@intel.com, mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com, tglx@linutronix.de, zhi.wang.linux@gmail.com, ackerleytng@google.com, andrew.jones@linux.dev, david@redhat.com, hpa@zytor.com, kirill.shutemov@linux.intel.com, linux-kselftest@vger.kernel.org, tabba@google.com, vannapurve@google.com, yan.y.zhao@intel.com, rick.p.edgecombe@intel.com, Ryan Afranji Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ackerley Tng Adds a selftest to verify interrupts sent to a TDX VM before migration are successfully handled by the migrated VM. Co-developed-by: Ryan Afranji Signed-off-by: Ryan Afranji Signed-off-by: Ackerley Tng --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/include/kvm_util.h | 4 + .../selftests/kvm/include/x86/tdx/tdx_util.h | 2 + .../selftests/kvm/include/x86/tdx/test_util.h | 5 + tools/testing/selftests/kvm/lib/kvm_util.c | 35 ++- .../selftests/kvm/lib/x86/tdx/tdx_util.c | 20 ++ .../selftests/kvm/lib/x86/tdx/test_util.c | 17 ++ .../kvm/x86/tdx_irqfd_migrate_test.c | 264 ++++++++++++++++++ .../selftests/kvm/x86/tdx_migrate_tests.c | 21 -- 9 files changed, 343 insertions(+), 26 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86/tdx_irqfd_migrate_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index d4c8cfb5910f..4ae0d105c2a7 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -156,6 +156,7 @@ TEST_GEN_PROGS_x86 +=3D x86/tdx_vm_test TEST_GEN_PROGS_x86 +=3D x86/tdx_shared_mem_test TEST_GEN_PROGS_x86 +=3D x86/tdx_upm_test TEST_GEN_PROGS_x86 +=3D x86/tdx_migrate_tests +TEST_GEN_PROGS_x86 +=3D x86/tdx_irqfd_migrate_test =20 # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86 +=3D x86/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index 8b252a668c78..f93ac2b9b0ff 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -80,6 +80,7 @@ enum kvm_mem_region_type { MEM_REGION_PT, MEM_REGION_TEST_DATA, MEM_REGION_TDX_BOOT_PARAMS, + MEM_REGION_TDX_SHARED_DATA, MEM_REGION_UCALL, NR_MEM_REGIONS, }; @@ -958,6 +959,9 @@ int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int = level); struct kvm_irq_routing *kvm_gsi_routing_create(void); void kvm_gsi_routing_irqchip_add(struct kvm_irq_routing *routing, uint32_t gsi, uint32_t pin); +void kvm_gsi_routing_msi_add(struct kvm_irq_routing *routing, uint32_t gsi, + uint32_t address_lo, uint32_t address_hi, + uint32_t data); int _kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *rout= ing); void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *rout= ing); =20 diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h b/tools= /testing/selftests/kvm/include/x86/tdx/tdx_util.h index 9b495e621225..4393c8649718 100644 --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx_util.h @@ -10,6 +10,8 @@ extern uint64_t tdx_s_bit; void tdx_filter_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid_data); void __tdx_mask_cpuid_features(struct kvm_cpuid_entry2 *entry); void tdx_enable_capabilities(struct kvm_vm *vm); +int __tdx_migrate_from(int dst_fd, int src_fd); +void tdx_migrate_from(struct kvm_vm *dst_vm, struct kvm_vm *src_vm); =20 struct kvm_vcpu *td_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, void *gu= est_code); =20 diff --git a/tools/testing/selftests/kvm/include/x86/tdx/test_util.h b/tool= s/testing/selftests/kvm/include/x86/tdx/test_util.h index 3330d5a54698..0dd859974cb3 100644 --- a/tools/testing/selftests/kvm/include/x86/tdx/test_util.h +++ b/tools/testing/selftests/kvm/include/x86/tdx/test_util.h @@ -130,4 +130,9 @@ uint64_t tdx_test_read_64bit(struct kvm_vcpu *vcpu, uin= t64_t port); */ uint64_t tdx_test_read_64bit_report_from_guest(struct kvm_vcpu *vcpu); =20 +/* + * Enables X2APIC for TDX guests. + */ +void tdx_guest_x2apic_enable(void); + #endif // SELFTEST_TDX_TEST_UTIL_H diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 9dc3c7bf0443..bbb489635064 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1293,10 +1293,12 @@ static void vm_migrate_mem_region(struct kvm_vm *ds= t_vm, struct kvm_vm *src_vm, struct userspace_mem_region *src_region) { struct userspace_mem_region *dst_region; - int dst_guest_memfd; + int dst_guest_memfd =3D -1; =20 - dst_guest_memfd =3D - vm_link_guest_memfd(dst_vm, src_region->region.guest_memfd, 0); + if (src_region->region.guest_memfd !=3D -1) + dst_guest_memfd =3D vm_link_guest_memfd(dst_vm, + src_region->region.guest_memfd, + 0); =20 dst_region =3D vm_mem_region_alloc( dst_vm, src_region->region.guest_phys_addr, @@ -1312,8 +1314,12 @@ static void vm_migrate_mem_region(struct kvm_vm *dst= _vm, struct kvm_vm *src_vm, src_region->host_mem =3D 0; =20 dst_region->region.guest_memfd =3D dst_guest_memfd; - dst_region->region.guest_memfd_offset =3D - src_region->region.guest_memfd_offset; + if (src_region->region.guest_memfd =3D=3D -1) { + dst_region->fd =3D src_region->fd; + } else { + dst_region->region.guest_memfd_offset =3D + src_region->region.guest_memfd_offset; + } =20 userspace_mem_region_commit(dst_vm, dst_region); } @@ -2057,6 +2063,25 @@ void kvm_gsi_routing_irqchip_add(struct kvm_irq_rout= ing *routing, routing->nr++; } =20 +void kvm_gsi_routing_msi_add(struct kvm_irq_routing *routing, uint32_t gsi, + uint32_t address_lo, uint32_t address_hi, + uint32_t data) +{ + int i; + + assert(routing); + assert(routing->nr < KVM_MAX_IRQ_ROUTES); + + i =3D routing->nr; + routing->entries[i].gsi =3D gsi; + routing->entries[i].type =3D KVM_IRQ_ROUTING_MSI; + routing->entries[i].flags =3D 0; + routing->entries[i].u.msi.address_lo =3D address_lo; + routing->entries[i].u.msi.address_hi =3D address_hi; + routing->entries[i].u.msi.data =3D data; + routing->nr++; +} + int _kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *rout= ing) { int ret; diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c b/tools/tes= ting/selftests/kvm/lib/x86/tdx/tdx_util.c index a3612bf187a0..8216a778474a 100644 --- a/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx_util.c @@ -372,6 +372,26 @@ static void tdx_apply_cr4_restrictions(struct kvm_sreg= s *sregs) sregs->cr4 &=3D ~(X86_CR4_VMXE | X86_CR4_SMXE); } =20 +int __tdx_migrate_from(int dst_fd, int src_fd) +{ + struct kvm_enable_cap cap =3D { + .cap =3D KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, + .args =3D { src_fd } + }; + + return ioctl(dst_fd, KVM_ENABLE_CAP, &cap); +} + +void tdx_migrate_from(struct kvm_vm *dst_vm, struct kvm_vm *src_vm) +{ + int ret; + + vm_migrate_mem_regions(dst_vm, src_vm); + ret =3D __tdx_migrate_from(dst_vm->fd, src_vm->fd); + TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno); + src_vm->enc_migrated =3D true; +} + static void load_td_boot_code(struct kvm_vm *vm) { void *boot_code_hva =3D addr_gpa2hva(vm, FOUR_GIGABYTES_GPA - TD_BOOT_COD= E_SIZE); diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/test_util.c b/tools/te= sting/selftests/kvm/lib/x86/tdx/test_util.c index f92ddda2d1ac..7b622ccb2433 100644 --- a/tools/testing/selftests/kvm/lib/x86/tdx/test_util.c +++ b/tools/testing/selftests/kvm/lib/x86/tdx/test_util.c @@ -6,6 +6,7 @@ #include #include =20 +#include "apic.h" #include "kvm_util.h" #include "tdx/tdcall.h" #include "tdx/tdx.h" @@ -185,3 +186,19 @@ uint64_t tdx_test_read_64bit_report_from_guest(struct = kvm_vcpu *vcpu) { return tdx_test_read_64bit(vcpu, TDX_TEST_REPORT_PORT); } + +void tdx_guest_x2apic_enable(void) +{ + uint64_t x2apic_spiv =3D APIC_BASE_MSR + (APIC_SPIV >> 4); + uint64_t value, ret; + + /* + * x2apic does not have to be enabled for TDs, TDs already have x2apic + * enabled, and must use x2apic. Hence, we just soft-enable APIC. + */ + ret =3D tdg_vp_vmcall_instruction_rdmsr(x2apic_spiv, &value); + GUEST_ASSERT_EQ(ret, 0); + ret =3D tdg_vp_vmcall_instruction_wrmsr(x2apic_spiv, + value | APIC_SPIV_APIC_ENABLED); + GUEST_ASSERT_EQ(ret, 0); +} diff --git a/tools/testing/selftests/kvm/x86/tdx_irqfd_migrate_test.c b/too= ls/testing/selftests/kvm/x86/tdx_irqfd_migrate_test.c new file mode 100644 index 000000000000..d80cc204bd67 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/tdx_irqfd_migrate_test.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include + +#include "apic.h" +#include "kvm_util.h" +#include "processor.h" +#include "tdx/tdcall.h" +#include "tdx/tdx.h" +#include "tdx/tdx_util.h" +#include "tdx/test_util.h" +#include "test_util.h" +#include "ucall_common.h" + +#define TEST_IRQ_PIN 24 + +#define NUM_INTERRUPTS 256 +#define INTERRUPT_COUNT_GPA 0x100000000ULL +#define INTERRUPT_COUNT_MEMSLOT 5 + +#define MIGRATION_LOOPS 10 + +static uint32_t (*interrupt_count_per_vector)[NUM_INTERRUPTS]; + +static void interrupt_handler_increment_count(struct ex_regs *regs) +{ + (*interrupt_count_per_vector)[regs->vector]++; + x2apic_write_reg(APIC_EOI, 0); +} + +static void guest_code(void) +{ + uint32_t sync_count =3D 0; + + tdx_guest_x2apic_enable(); + + /* Enable interrupts which are disabled by default. */ + asm volatile("sti"); + + /* Keep guest runnable by continuously looping. */ + while (true) + GUEST_SYNC(++sync_count); +} + +/** + * gsi_route_add - Used to add a GSI route. + * + * @msi_redir_hint: Look up "Message Address Register Format" in Intel SDM + * @dest_mode: Look up "Message Address Register Format" in Intel SDM + * Use false for DM=3D0 and true for DM=3D1 + * @trig_mode: Look up "Message Data Register Format" in Intel SDM + * Use false for edge sensitive and true for level sensitive + * @delivery_mode: A 3 bit code: look up "Message Data Register Format" + * + * Add a route by building up the routing information in address_hi, addre= ss_lo + * and data according to how it is used in struct kvm_lapic_irq. For full + * details, look up how fields in struct kvm_lapic_irq are used. + * + * Return: None + */ +static void gsi_route_add(struct kvm_irq_routing *table, uint32_t gsi, + bool use_x2apic_format, uint32_t dest_id, + uint8_t vector, bool msi_redir_hint, bool dest_mode, + bool trig_mode, uint8_t delivery_mode) +{ + union { + struct { + u32 vector : 8, delivery_mode : 3, + dest_mode_logical : 1, reserved : 2, + active_low : 1, is_level : 1; + }; + uint32_t as_uint32; + } data =3D { 0 }; + union { + struct { + u32 reserved_0 : 2, dest_mode_logical : 1, + redirect_hint : 1, reserved_1 : 1, + virt_destid_8_14 : 7, destid_0_7 : 8, + base_address : 12; + }; + uint32_t as_uint32; + } address_lo =3D { 0 }; + union { + struct { + u32 reserved : 8, destid_8_31 : 24; + }; + uint32_t as_uint32; + } address_hi =3D { 0 }; + + /* Fixed 0xfee (see Intel SDM "Message Address Register Format") */ + address_lo.base_address =3D 0xfee; + + address_lo.destid_0_7 =3D dest_id & 0xff; + if (use_x2apic_format) + address_hi.destid_8_31 =3D (dest_id & 0xffffff00) >> 8; + + data.vector =3D vector; + address_lo.dest_mode_logical =3D dest_mode; + data.is_level =3D trig_mode; + data.delivery_mode =3D delivery_mode & 0b111; + address_lo.redirect_hint =3D msi_redir_hint; + + kvm_gsi_routing_msi_add(table, gsi, address_lo.as_uint32, + address_hi.as_uint32, data.as_uint32); +} + +/** + * Sets up KVM irqfd in @vm + * + * @gsi: irqchip pin toggled by this event + */ +static void set_irqfd(struct kvm_vm *vm, int fd, uint32_t gsi, bool assign) +{ + struct kvm_irqfd ifd =3D { + .fd =3D fd, + .gsi =3D gsi, + .flags =3D assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN, + .resamplefd =3D 0, + }; + + vm_ioctl(vm, KVM_IRQFD, &ifd); +} + +static void setup_interrupt_count_per_vector(struct kvm_vm *vm) +{ + vm_vaddr_t gva; + int npages; + + npages =3D round_up(sizeof(*interrupt_count_per_vector), PAGE_SIZE); + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + INTERRUPT_COUNT_GPA, + INTERRUPT_COUNT_MEMSLOT, npages, 0); + vm->memslots[MEM_REGION_TDX_SHARED_DATA] =3D INTERRUPT_COUNT_MEMSLOT; + + gva =3D vm_vaddr_alloc_shared(vm, sizeof(*interrupt_count_per_vector), + KVM_UTIL_MIN_VADDR, + MEM_REGION_TDX_SHARED_DATA); + + interrupt_count_per_vector =3D addr_gva2hva(vm, gva); + memset(interrupt_count_per_vector, 0, + sizeof(*interrupt_count_per_vector)); + + write_guest_global(vm, interrupt_count_per_vector, + (uint32_t(*)[NUM_INTERRUPTS])gva); +} + +static void handle_vcpu_exit(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + break; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + default: + TEST_FAIL("Unexpected exit: %s", + exit_reason_str(vcpu->run->exit_reason)); + } +} + +void map_gsis_to_vectors(struct kvm_vm *vm, struct kvm_vcpu *vcpu, int *ev= entfds) +{ + struct kvm_irq_routing *table; + uint32_t vector_and_gsi; + int efd; + + /* Flush table first. */ + table =3D kvm_gsi_routing_create(); + kvm_gsi_routing_write(vm, table); + + /* Writing frees table, so we have to create another one. */ + table =3D kvm_gsi_routing_create(); + + /* Map vectors to gsis 1 to 1 */ + for (vector_and_gsi =3D 32; vector_and_gsi < NUM_INTERRUPTS; + ++vector_and_gsi) { + gsi_route_add(table, vector_and_gsi, + /*use_x2apic_format=3D*/true, + /*dest_id=3D*/vcpu->id, + /*vector=3D*/vector_and_gsi, + /*msi_redir_hint=3D*/false, + /*dest_mode=3D*/false, + /*trig_mode=3D*/false, + /*delivery_mode=3D*/0b000); + + efd =3D eventfd(0, EFD_NONBLOCK); + set_irqfd(vm, efd, vector_and_gsi, true); + + eventfds[vector_and_gsi] =3D efd; + } + + /* Configure KVM. Writing frees table. */ + kvm_gsi_routing_write(vm, table); + +} + +int main(int argc, char *argv[]) +{ + int eventfds[NUM_INTERRUPTS] =3D { 0 }; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int vector, migration; + + TEST_REQUIRE(kvm_check_cap(KVM_CAP_SPLIT_IRQCHIP)); + + setbuf(stdout, NULL); + + vm =3D td_create(); + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); + + vcpu =3D td_vcpu_add(vm, 0, guest_code); + + for (vector =3D 0; vector < NUM_INTERRUPTS; ++vector) { + vm_install_exception_handler(vm, vector, + interrupt_handler_increment_count); + } + + setup_interrupt_count_per_vector(vm); + + td_finalize(vm); + + map_gsis_to_vectors(vm, vcpu, eventfds); + + tdx_run(vcpu); + handle_vcpu_exit(vcpu); + + for (migration =3D 0; migration < MIGRATION_LOOPS; ++migration) { + struct kvm_vcpu *next_vcpu; + struct kvm_vm *next_vm; + + next_vm =3D td_create(); + tdx_enable_capabilities(next_vm); + next_vcpu =3D vm_vcpu_recreate(next_vm, 0); + + /* Inject on source VM. */ + for (vector =3D 32; vector < NUM_INTERRUPTS; ++vector) + TEST_ASSERT_EQ(eventfd_write(eventfds[vector], 1), 0); + + map_gsis_to_vectors(next_vm, next_vcpu, eventfds); + + vcpu =3D next_vcpu; + + tdx_migrate_from(next_vm, vm); + kvm_vm_free(vm); + vm =3D next_vm; + + tdx_run(vcpu); + handle_vcpu_exit(vcpu); + + for (vector =3D 32; vector < NUM_INTERRUPTS; ++vector) + TEST_ASSERT_EQ((*interrupt_count_per_vector)[vector], + migration + 1); + } + + kvm_vm_free(vm); + for (vector =3D 32; vector < NUM_INTERRUPTS; ++vector) + close(eventfds[vector]); + return 0; +} diff --git a/tools/testing/selftests/kvm/x86/tdx_migrate_tests.c b/tools/te= sting/selftests/kvm/x86/tdx_migrate_tests.c index e15da2aa0437..498e42f37697 100644 --- a/tools/testing/selftests/kvm/x86/tdx_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86/tdx_migrate_tests.c @@ -10,27 +10,6 @@ #define NR_MIGRATE_TEST_VMS 10 #define TDX_IOEXIT_TEST_PORT 0x50 =20 -static int __tdx_migrate_from(int dst_fd, int src_fd) -{ - struct kvm_enable_cap cap =3D { - .cap =3D KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, - .args =3D { src_fd } - }; - - return ioctl(dst_fd, KVM_ENABLE_CAP, &cap); -} - - -static void tdx_migrate_from(struct kvm_vm *dst_vm, struct kvm_vm *src_vm) -{ - int ret; - - vm_migrate_mem_regions(dst_vm, src_vm); - ret =3D __tdx_migrate_from(dst_vm->fd, src_vm->fd); - TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno); - src_vm->enc_migrated =3D true; -} - void guest_code(void) { int ret; --=20 2.50.0.rc1.591.g9c95f17f64-goog