From nobody Fri Oct 10 13:44:19 2025 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.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 DD5D82BF06F for ; Fri, 13 Jun 2025 19:14:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749842071; cv=none; b=K6MjqMwdcx75YlLkJl29QMxJ2Umloq9fXi+w/kHg7Me4FTHnapjNvQojCd/0fPj5MS9zNYFuriWBxT8/hRNIPjTdXvZaDp16iVeaN5UaTiW1PzW3Dd5igEqNmibs9SfAJZSJIzvjvK2ggDZZuPYuwG403UHR3DuJETL2f7kIS4A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749842071; c=relaxed/simple; bh=uqIxOmX3BYXbbCv1CMHqHbbyU277l6eBkNwagdau+oY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=J/YXni4OuGFPRwBEgD08Dw3bPqzjNDzi+zQ2bJwHMfJLqTj7w9SMZp7tHcn1hWGUijpON/7q97Vw8PhZDvhSICcj+8jaNwEdP/2HM4xBIiaxzQMxXcZ2+HlkYZAPdkF0TmQlklERZ1IhIZf7ufzr37W4p29s14llgAVeojYegTU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--sagis.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=uZ9DKfe2; arc=none smtp.client-ip=209.85.210.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--sagis.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="uZ9DKfe2" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-748764d84feso3135764b3a.2 for ; Fri, 13 Jun 2025 12:14:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749842069; x=1750446869; 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=N/svNuuxjLlsSpnXIsQtll5AlQK2Oa/4goaN4sSAXj0=; b=uZ9DKfe2jk/5QcYfSeiGO/YcrkPJfSHJXc8I2ZqyYvpKaWdIWbq1cbQpO3C7P5lFoe YbE8BHtpRlRU1KOx8xAHXKVh61gaMckS9KqUE87V0Xzf8s6HzI2tnP9M/g47RKBi7rc2 hMLRIraYsHd6DqGIRzI0rCqxjTc1L6Sue9WLkKG06cdfx5QUaLdfqeFQsJtpgv6RCE7A iHKgairVLxDJExdiLARgkexbIwt/iTmOeTpH9iPO8Fbx7P1NTNkweQo8ajqTPDasw+Dm wPi54FVFkS1lat1ksCNu4wrU/6Kicc8S+/OI89Ku/TM1THYW/pIU36GJ2ZrMemkYBQoa P0rg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749842069; x=1750446869; 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=N/svNuuxjLlsSpnXIsQtll5AlQK2Oa/4goaN4sSAXj0=; b=CjoXg00EsIdLR6k+KvMACFEuLAE5c5atEyGc/aYcWxpnw/S91M93awR4dA8wXQpd3i uRRnOcPrhekJGienG8/TCTfeZuzh3+bq81X1nLAkJ9H60theWfVb74B6xySngYbPzvL5 g3RX6Y8yuDLfzofW6M5bCDx0sNJnUuTpbwL4KIg04MV0LxJgn1oIHbEFWxzpJHgqiIQf YfQPnwj+2up2IulKk9B+HSzb3Kol0jsvy/mtWOo3vaZ9c535fgY6IK/BMLIXdP7/jJSE QtvghdGUy6/tQ1YjgdRAm377TOi3iCKuu1Rh0o30Yc3oJdiyIG96+AzmoDAX2dpnR0gD MtSA== X-Gm-Message-State: AOJu0YwTJ8PlTmKxwpoz7dERvQnmfa97CqXdyLWDJstMAFY2extdnD2D Ye+v13Df2axi57sFpOGxmoXZX0fl8C59zAu4/KUhr1Xz8pU+rqvVQjAdLKcqounvJUVR2Jnd0VO o4g== X-Google-Smtp-Source: AGHT+IFsYD1YyKIZHNpOeAVzaehTtViz3NuufMHX1K/2IHUCVmKQpLnEvTjx4pMeMGAWKjwf/SjSKMjEtA== X-Received: from pfuv8.prod.google.com ([2002:a05:6a00:1488:b0:747:b76c:ab92]) (user=sagis job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3a19:b0:746:2ae9:fc3d with SMTP id d2e1a72fcca58-7489cffb6bbmr654798b3a.23.1749842069428; Fri, 13 Jun 2025 12:14:29 -0700 (PDT) Date: Fri, 13 Jun 2025 12:13:38 -0700 In-Reply-To: <20250613191359.35078-1-sagis@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250613191359.35078-1-sagis@google.com> X-Mailer: git-send-email 2.50.0.rc2.692.g299adb8693-goog Message-ID: <20250613191359.35078-12-sagis@google.com> Subject: [PATCH v7 11/30] KVM: selftests: TDX: Adding test case for TDX port IO From: Sagi Shahar To: linux-kselftest@vger.kernel.org, Paolo Bonzini , Shuah Khan , Sean Christopherson , Ackerley Tng , Ryan Afranji , Andrew Jones , Isaku Yamahata , Erdem Aktas , Rick Edgecombe , Sagi Shahar , Roger Wang , Binbin Wu , Oliver Upton , "Pratik R. Sampat" , Reinette Chatre Cc: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Verifies TDVMCALL READ and WRITE operations. Signed-off-by: Sagi Shahar --- .../selftests/kvm/include/x86/tdx/test_util.h | 20 +++++ .../selftests/kvm/lib/x86/tdx/test_util.c | 35 +++++++++ tools/testing/selftests/kvm/x86/tdx_vm_test.c | 78 ++++++++++++++++++- 3 files changed, 130 insertions(+), 3 deletions(-) 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 dafeee9af1dc..cf11955d56d6 100644 --- a/tools/testing/selftests/kvm/include/x86/tdx/test_util.h +++ b/tools/testing/selftests/kvm/include/x86/tdx/test_util.h @@ -13,6 +13,19 @@ #define PORT_READ 0 #define PORT_WRITE 1 =20 +/* + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() = was + * called in the guest. + */ +void tdx_test_assert_io(struct kvm_vcpu *vcpu, uint16_t port, uint8_t size, + uint8_t direction); + +/* + * Run the tdx vcpu and check if there was some failure in the guest, eith= er + * an exception like a triple fault, or if a tdx_test_fatal() was hit. + */ +void tdx_run(struct kvm_vcpu *vcpu); + /* * Run a test in a new process. * @@ -57,4 +70,11 @@ void tdx_test_fatal(uint64_t error_code); */ void tdx_test_fatal_with_data(uint64_t error_code, uint64_t data_gpa); =20 +/* + * Assert on @error and report the @error to userspace. + * Return value from tdg_vp_vmcall_report_fatal_error() is ignored since e= xecution + * is not expected to continue beyond this point. + */ +void tdx_assert_error(uint64_t error); + #endif // SELFTEST_TDX_TEST_UTIL_H 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 6c82a0c3bd37..4ccc5298ba25 100644 --- a/tools/testing/selftests/kvm/lib/x86/tdx/test_util.c +++ b/tools/testing/selftests/kvm/lib/x86/tdx/test_util.c @@ -8,8 +8,37 @@ =20 #include "kvm_util.h" #include "tdx/tdx.h" +#include "tdx/tdx_util.h" #include "tdx/test_util.h" =20 +void tdx_test_assert_io(struct kvm_vcpu *vcpu, uint16_t port, uint8_t size, + uint8_t direction) +{ + TEST_ASSERT(vcpu->run->exit_reason =3D=3D KVM_EXIT_IO, + "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", + vcpu->run->exit_reason, + exit_reason_str(vcpu->run->exit_reason)); + + TEST_ASSERT(vcpu->run->exit_reason =3D=3D KVM_EXIT_IO && + vcpu->run->io.port =3D=3D port && + vcpu->run->io.size =3D=3D size && + vcpu->run->io.direction =3D=3D direction, + "Got unexpected IO exit values: %u (%s) %u %u %u\n", + vcpu->run->exit_reason, + exit_reason_str(vcpu->run->exit_reason), + vcpu->run->io.port, vcpu->run->io.size, + vcpu->run->io.direction); +} + +void tdx_run(struct kvm_vcpu *vcpu) +{ + td_vcpu_run(vcpu); + if (vcpu->run->exit_reason =3D=3D KVM_EXIT_SYSTEM_EVENT) + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", + vcpu->run->system_event.data[12], + vcpu->run->system_event.data[13]); +} + int run_in_new_process(void (*func)(void)) { int wstatus; @@ -69,3 +98,9 @@ void tdx_test_fatal(uint64_t error_code) { tdx_test_fatal_with_data(error_code, 0); } + +void tdx_assert_error(uint64_t error) +{ + if (error) + tdx_test_fatal(error); +} diff --git a/tools/testing/selftests/kvm/x86/tdx_vm_test.c b/tools/testing/= selftests/kvm/x86/tdx_vm_test.c index 7d6d71602761..97330e28f236 100644 --- a/tools/testing/selftests/kvm/x86/tdx_vm_test.c +++ b/tools/testing/selftests/kvm/x86/tdx_vm_test.c @@ -3,6 +3,7 @@ #include =20 #include "kvm_util.h" +#include "tdx/tdcall.h" #include "tdx/tdx.h" #include "tdx/tdx_util.h" #include "tdx/test_util.h" @@ -25,7 +26,7 @@ static void verify_td_lifecycle(void) =20 printf("Verifying TD lifecycle:\n"); =20 - td_vcpu_run(vcpu); + tdx_run(vcpu); tdx_test_assert_success(vcpu); =20 kvm_vm_free(vm); @@ -69,9 +70,78 @@ void verify_report_fatal_error(void) TEST_ASSERT_EQ(vcpu->run->system_event.data[12], 0x0BAAAAAD00000000); TEST_ASSERT_EQ(vcpu->run->system_event.data[13], 0); =20 - td_vcpu_run(vcpu); + tdx_run(vcpu); + tdx_test_assert_success(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + +#define TDX_IOEXIT_TEST_PORT 0x50 + +/* + * Verifies IO functionality by writing a |value| to a predefined port. + * Verifies that the read value is |value| + 1 from the same port. + * If all the tests are passed then write a value to port TDX_TEST_PORT + */ +void guest_ioexit(void) +{ + uint64_t data_out, data_in; + uint64_t ret; + + data_out =3D 0xAB; + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + PORT_WRITE, &data_out); + tdx_assert_error(ret); + + ret =3D tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + PORT_READ, &data_in); + tdx_assert_error(ret); + + if (data_in !=3D 0xAC) + tdx_test_fatal(data_in); + + tdx_test_success(); +} + +void verify_td_ioexit(void) +{ + struct kvm_vcpu *vcpu; + uint32_t port_data; + struct kvm_vm *vm; + + vm =3D td_create(); + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); + vcpu =3D td_vcpu_add(vm, 0, guest_ioexit); + td_finalize(vm); + + printf("Verifying TD IO Exit:\n"); + + /* Wait for guest to do a IO write */ + tdx_run(vcpu); + tdx_test_assert_io(vcpu, TDX_IOEXIT_TEST_PORT, 1, PORT_WRITE); + port_data =3D *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + printf("\t ... IO WRITE: DONE\n"); + + /* + * Wait for the guest to do a IO read. Provide the previous written data + * + 1 back to the guest + */ + tdx_run(vcpu); + tdx_test_assert_io(vcpu, TDX_IOEXIT_TEST_PORT, 1, PORT_READ); + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) =3D port_data= + 1; + + printf("\t ... IO READ: DONE\n"); + + /* + * Wait for the guest to complete execution successfully. The read + * value is checked within the guest. + */ + tdx_run(vcpu); tdx_test_assert_success(vcpu); =20 + printf("\t ... IO verify read/write values: OK\n"); kvm_vm_free(vm); printf("\t ... PASSED\n"); } @@ -83,11 +153,13 @@ int main(int argc, char **argv) if (!is_tdx_enabled()) ksft_exit_skip("TDX is not supported by the KVM. Exiting.\n"); =20 - ksft_set_plan(2); + ksft_set_plan(3); ksft_test_result(!run_in_new_process(&verify_td_lifecycle), "verify_td_lifecycle\n"); ksft_test_result(!run_in_new_process(&verify_report_fatal_error), "verify_report_fatal_error\n"); + ksft_test_result(!run_in_new_process(&verify_td_ioexit), + "verify_td_ioexit\n"); =20 ksft_finished(); return 0; --=20 2.50.0.rc2.692.g299adb8693-goog