Message ID | 20231212204647.2170650-11-sagis@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:bcd1:0:b0:403:3b70:6f57 with SMTP id r17csp7993405vqy; Tue, 12 Dec 2023 12:47:53 -0800 (PST) X-Google-Smtp-Source: AGHT+IH4nB1PeRj/9lzOTYgrNALiSeCaGOK1269wcp8sl6I15bVHjGtU/B3x2E35wor1vnc/4XI4 X-Received: by 2002:a17:902:8682:b0:1d0:cd9e:424b with SMTP id g2-20020a170902868200b001d0cd9e424bmr6402002plo.43.1702414073204; Tue, 12 Dec 2023 12:47:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1702414073; cv=none; d=google.com; s=arc-20160816; b=T8ECTCrBivHc15Z50qbTQvFQnt09t0FjeAFQy+5TUv5qKnuEr9kRh7TMl48XOlO4it nL3oN7TArIlGSKo7rMUc442a6Ofed2xK9cErR0t3MiY+H65P1COPnkz2zLQYd2CFT9+V g42hzopA14970qtcbuKgfZNOpVGaPQtlaXKiKv8ikOg7vrqoQVt21Xas3yKKYqt4qR7D fwaNiW7ZKpI/oAJMNsWzAjiVFxFgkc1fG7gMfoiNECv9O7fd1Xy09v8NHyXFPKckW2Hj qtnvfjxjYgwEL/BvpdIm0W0d/itmiF1fJqVLxsvHIZlGll365GaENzXNOdehBFyiNYf4 OuAg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=XMXRsZ7PnaagoSZjHTHBbcv9aekrkY1R/86PgELFK84=; fh=Y5ua58y+ybdOPwRkMynUdu+Hv1LrozBumh8skcuOhBI=; b=lCSv1OgN7oeLbB5Xl5CWbEZrTJSq5wPn5p4jRXbWZC7IQt3F4SLXIb7bpdQ8LtZr9Q vuhwj06TIESBRqOt0RyeJsXFt6UQEg+cYVVWrFf3rHnRWlianloytsBxnk1JzbgJMGYl +/Qoxq9p4fKAhgzrF2mLhu4e2lpcEDtSE2jwAqw2/9se+FdfoEZ3abbXPsMqHjweo8hK cdqP3LItLfnl8SvzldHjit32rEZuehPG/MxTZ+DcL3fnYKwIo394itrIY1rMvplPUX4V uijApldIh6UlKwZoAg1+8prXhHCfqALlXlpENhk1rtKRPzrv+lm616h1A4OmSLlWuDpF pOWw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=fh0buOwF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id em9-20020a17090b014900b0028ad088026asi764679pjb.76.2023.12.12.12.47.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 Dec 2023 12:47:53 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=fh0buOwF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id EC08D80B2322; Tue, 12 Dec 2023 12:47:51 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377302AbjLLUrk (ORCPT <rfc822;dexuan.linux@gmail.com> + 99 others); Tue, 12 Dec 2023 15:47:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54690 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1377253AbjLLUrP (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 12 Dec 2023 15:47:15 -0500 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0083CD for <linux-kernel@vger.kernel.org>; Tue, 12 Dec 2023 12:47:15 -0800 (PST) Received: by mail-pl1-x649.google.com with SMTP id d9443c01a7336-1d33751a322so5236095ad.3 for <linux-kernel@vger.kernel.org>; Tue, 12 Dec 2023 12:47:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1702414035; x=1703018835; 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=XMXRsZ7PnaagoSZjHTHBbcv9aekrkY1R/86PgELFK84=; b=fh0buOwFBJxvTVVrcGQW2OIX3FM/IByL12fG8HL57mw4E5H+dSmwJFgZvjzKg+2OgP iQ2tVsGP5j2M5ElR9E74cbb3o0wC1CYxat6fAAMwFXXqXxv4ZQq3LbBba54O1t7TQIHA EvBAWRR/vQn1ShO0NIzcAAwLIWcdQ05SI4J7jBya1B5CFQFI3Ri0t9iX5GWXsQSSEdzc 3S9eVQN17rIh+yfLVxM2JxAGW+YNi5Io6ppy/ErhOFpPu7G8u7bzuEOLFVNeuvzfE52+ P1OsY/Rb47MaIFPySrfyyVYaoHOs3N5NXedH0m8qkXBKPrSg0m9cr9ncNjsmyLDO7OfA G2DA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702414035; x=1703018835; 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=XMXRsZ7PnaagoSZjHTHBbcv9aekrkY1R/86PgELFK84=; b=RJqp8Ox8JRRApZp9wPhzE0K54hDaRNvEiqFzWl8L7pqtOU4tywVNR14YV965uGQZ7I 48GukclKCvcw/1554jI1GIuOPKHH8fjmnkcOVl+rz3nTRfgkLM9jb+zWKQAUBys/Fmxf GgrUNXu/kjdXWsvlojEnu0Tevt1YSfHcmMedhgOzKNBWvTC4VLzfrwDl5RGLj4QQYOOX a2mMOKX3Qx4dcstGckACQohpSa9YH1U/hFRm9kKwZiFtseu3dvvpCNMpzldVyQp4sr16 VCDXc52OVUco06yznPkRY0EVJ3Om7mTrpYRqIPPNLZQyClh9oZ4W9xJ9o3bw4L5Axbn1 F52w== X-Gm-Message-State: AOJu0YwKb1TFwDB65IQKRmkoLmEQwJknrIU4htcgVGmLw191cEBE/7yQ 77kbisWA0Ov18/QQ5wvDpg/pcEpT4A== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:902:b712:b0:1d3:46f4:7f1e with SMTP id d18-20020a170902b71200b001d346f47f1emr4985pls.1.1702414035248; Tue, 12 Dec 2023 12:47:15 -0800 (PST) Date: Tue, 12 Dec 2023 12:46:25 -0800 In-Reply-To: <20231212204647.2170650-1-sagis@google.com> Mime-Version: 1.0 References: <20231212204647.2170650-1-sagis@google.com> X-Mailer: git-send-email 2.43.0.472.g3155946c3a-goog Message-ID: <20231212204647.2170650-11-sagis@google.com> Subject: [RFC PATCH v5 10/29] KVM: selftests: TDX: Adding test case for TDX port IO From: Sagi Shahar <sagis@google.com> To: linux-kselftest@vger.kernel.org, Ackerley Tng <ackerleytng@google.com>, Ryan Afranji <afranji@google.com>, Erdem Aktas <erdemaktas@google.com>, Sagi Shahar <sagis@google.com>, Isaku Yamahata <isaku.yamahata@intel.com> Cc: Sean Christopherson <seanjc@google.com>, Paolo Bonzini <pbonzini@redhat.com>, Shuah Khan <shuah@kernel.org>, Peter Gonda <pgonda@google.com>, Haibo Xu <haibo1.xu@intel.com>, Chao Peng <chao.p.peng@linux.intel.com>, Vishal Annapurve <vannapurve@google.com>, Roger Wang <runanwang@google.com>, Vipin Sharma <vipinsh@google.com>, jmattson@google.com, dmatlack@google.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-mm@kvack.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE, USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Tue, 12 Dec 2023 12:47:52 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1785110538915602380 X-GMAIL-MSGID: 1785110538915602380 |
Series |
TDX KVM selftests
|
|
Commit Message
Sagi Shahar
Dec. 12, 2023, 8:46 p.m. UTC
From: Erdem Aktas <erdemaktas@google.com> Verifies TDVMCALL<INSTRUCTION.IO> READ and WRITE operations. Signed-off-by: Erdem Aktas <erdemaktas@google.com> Signed-off-by: Sagi Shahar <sagis@google.com> Signed-off-by: Ackerley Tng <ackerleytng@google.com> Signed-off-by: Ryan Afranji <afranji@google.com> --- .../kvm/include/x86_64/tdx/test_util.h | 34 ++++++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 82 +++++++++++++++++++ 2 files changed, 116 insertions(+)
Comments
On 12/13/2023 4:46 AM, Sagi Shahar wrote: > From: Erdem Aktas <erdemaktas@google.com> > > Verifies TDVMCALL<INSTRUCTION.IO> READ and WRITE operations. > > Signed-off-by: Erdem Aktas <erdemaktas@google.com> > Signed-off-by: Sagi Shahar <sagis@google.com> > Signed-off-by: Ackerley Tng <ackerleytng@google.com> > Signed-off-by: Ryan Afranji <afranji@google.com> > --- > .../kvm/include/x86_64/tdx/test_util.h | 34 ++++++++ > .../selftests/kvm/x86_64/tdx_vm_tests.c | 82 +++++++++++++++++++ > 2 files changed, 116 insertions(+) One nit comment below. Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> > > diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > index 6d69921136bd..95a5d5be7f0b 100644 > --- a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > @@ -9,6 +9,40 @@ > #define TDX_TEST_SUCCESS_PORT 0x30 > #define TDX_TEST_SUCCESS_SIZE 4 > > +/** > + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() was > + * called in the guest. > + */ > +#define TDX_TEST_ASSERT_IO(VCPU, PORT, SIZE, DIR) \ > + do { \ > + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_IO) && \ > + ((VCPU)->run->io.port == (PORT)) && \ > + ((VCPU)->run->io.size == (SIZE)) && \ > + ((VCPU)->run->io.direction == (DIR)), \ > + "Got unexpected IO exit values: %u (%s) %d %d %d\n", \ > + (VCPU)->run->exit_reason, \ > + exit_reason_str((VCPU)->run->exit_reason), \ > + (VCPU)->run->io.port, (VCPU)->run->io.size, \ > + (VCPU)->run->io.direction); \ > + } while (0) > + > +/** > + * Check and report if there was some failure in the guest, either an exception > + * like a triple fault, or if a tdx_test_fatal() was hit. > + */ > +#define TDX_TEST_CHECK_GUEST_FAILURE(VCPU) \ > + do { \ > + if ((VCPU)->run->exit_reason == KVM_EXIT_SYSTEM_EVENT) \ > + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", \ > + (VCPU)->run->system_event.data[1], \ > + (VCPU)->run->system_event.data[1]); \ > + } while (0) > + > /** > * Assert that tdx_test_success() was called in the guest. > */ > diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > index 8638c7bbedaa..75467c407ca7 100644 > --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > @@ -2,6 +2,7 @@ > > #include <signal.h> > #include "kvm_util_base.h" > +#include "tdx/tdcall.h" > #include "tdx/tdx.h" > #include "tdx/tdx_util.h" > #include "tdx/test_util.h" > @@ -74,6 +75,86 @@ void verify_report_fatal_error(void) > 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, delta; > + uint64_t ret; > + > + data_out = 0xAB; > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE, > + &data_out); > + if (ret) > + tdx_test_fatal(ret); > + > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_READ, > + &data_in); > + if (ret) > + tdx_test_fatal(ret); > + > + delta = data_in - data_out; > + if (delta != 1) Nit: Is it more direct to compare data_in with 0xAC? > + tdx_test_fatal(ret); > + > + tdx_test_success(); > +} > + > +void verify_td_ioexit(void) > +{ > + struct kvm_vm *vm; > + struct kvm_vcpu *vcpu; > + > + uint32_t port_data; > + > + vm = td_create(); > + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); > + vcpu = td_vcpu_add(vm, 0, guest_ioexit); > + td_finalize(vm); > + > + printf("Verifying TD IO Exit:\n"); > + > + /* Wait for guest to do a IO write */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); > + port_data = *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); > + > + printf("\t ... IO WRITE: OK\n"); > + > + /* > + * Wait for the guest to do a IO read. Provide the previous written data > + * + 1 back to the guest > + */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_READ); > + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) = port_data + 1; > + > + printf("\t ... IO READ: OK\n"); > + > + /* > + * Wait for the guest to complete execution successfully. The read > + * value is checked within the guest. > + */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > + TDX_TEST_ASSERT_SUCCESS(vcpu); > + > + printf("\t ... IO verify read/write values: OK\n"); > + kvm_vm_free(vm); > + printf("\t ... PASSED\n"); > +} > + > int main(int argc, char **argv) > { > setbuf(stdout, NULL); > @@ -85,6 +166,7 @@ int main(int argc, char **argv) > > run_in_new_process(&verify_td_lifecycle); > run_in_new_process(&verify_report_fatal_error); > + run_in_new_process(&verify_td_ioexit); > > return 0; > }
On Tue, Dec 12, 2023 at 12:46:25PM -0800, Sagi Shahar wrote: > From: Erdem Aktas <erdemaktas@google.com> > > Verifies TDVMCALL<INSTRUCTION.IO> READ and WRITE operations. > > Signed-off-by: Erdem Aktas <erdemaktas@google.com> > Signed-off-by: Sagi Shahar <sagis@google.com> > Signed-off-by: Ackerley Tng <ackerleytng@google.com> > Signed-off-by: Ryan Afranji <afranji@google.com> > --- > .../kvm/include/x86_64/tdx/test_util.h | 34 ++++++++ > .../selftests/kvm/x86_64/tdx_vm_tests.c | 82 +++++++++++++++++++ > 2 files changed, 116 insertions(+) > > diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > index 6d69921136bd..95a5d5be7f0b 100644 > --- a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > @@ -9,6 +9,40 @@ > #define TDX_TEST_SUCCESS_PORT 0x30 > #define TDX_TEST_SUCCESS_SIZE 4 > > +/** > + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() was > + * called in the guest. > + */ > +#define TDX_TEST_ASSERT_IO(VCPU, PORT, SIZE, DIR) \ > + do { \ > + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_IO) && \ > + ((VCPU)->run->io.port == (PORT)) && \ > + ((VCPU)->run->io.size == (SIZE)) && \ > + ((VCPU)->run->io.direction == (DIR)), \ > + "Got unexpected IO exit values: %u (%s) %d %d %d\n", \ > + (VCPU)->run->exit_reason, \ > + exit_reason_str((VCPU)->run->exit_reason), \ > + (VCPU)->run->io.port, (VCPU)->run->io.size, \ > + (VCPU)->run->io.direction); \ > + } while (0) > + > +/** > + * Check and report if there was some failure in the guest, either an exception > + * like a triple fault, or if a tdx_test_fatal() was hit. > + */ > +#define TDX_TEST_CHECK_GUEST_FAILURE(VCPU) \ > + do { \ > + if ((VCPU)->run->exit_reason == KVM_EXIT_SYSTEM_EVENT) \ > + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", \ > + (VCPU)->run->system_event.data[1], \ > + (VCPU)->run->system_event.data[1]); \ > + } while (0) > + > /** > * Assert that tdx_test_success() was called in the guest. > */ > diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > index 8638c7bbedaa..75467c407ca7 100644 > --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > @@ -2,6 +2,7 @@ > > #include <signal.h> > #include "kvm_util_base.h" > +#include "tdx/tdcall.h" > #include "tdx/tdx.h" > #include "tdx/tdx_util.h" > #include "tdx/test_util.h" > @@ -74,6 +75,86 @@ void verify_report_fatal_error(void) > 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, delta; > + uint64_t ret; > + > + data_out = 0xAB; > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE, > + &data_out); > + if (ret) > + tdx_test_fatal(ret); > + > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_READ, > + &data_in); > + if (ret) > + tdx_test_fatal(ret); > + > + delta = data_in - data_out; > + if (delta != 1) > + tdx_test_fatal(ret); > + > + tdx_test_success(); > +} > + > +void verify_td_ioexit(void) > +{ > + struct kvm_vm *vm; > + struct kvm_vcpu *vcpu; > + > + uint32_t port_data; > + > + vm = td_create(); > + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); > + vcpu = td_vcpu_add(vm, 0, guest_ioexit); > + td_finalize(vm); > + > + printf("Verifying TD IO Exit:\n"); > + > + /* Wait for guest to do a IO write */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); This check is a vain, because the first VMExit from vcpu run is always KVM_EXIT_IO caused by tdg_vp_vmcall_instruction_io(). > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); > + port_data = *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); > + > + printf("\t ... IO WRITE: OK\n"); So, even if there's an error in emulating writing of TDX_IOEXIT_TEST_PORT, and guest would then find a failure and trigger tdx_test_fatal(), this line will still print "IO WRITE: OK", which is not right. > + > + /* > + * Wait for the guest to do a IO read. Provide the previous written data > + * + 1 back to the guest > + */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); This check is a vain, too, as in write case. > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > + TDG_VP_VMCALL_INSTRUCTION_IO_READ); > + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) = port_data + 1; > + > + printf("\t ... IO READ: OK\n"); Same as in write case, this line should not be printed until after guest finishing checking return code. > + > + /* > + * Wait for the guest to complete execution successfully. The read > + * value is checked within the guest. > + */ > + td_vcpu_run(vcpu); > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > + TDX_TEST_ASSERT_SUCCESS(vcpu); > + > + printf("\t ... IO verify read/write values: OK\n"); > + kvm_vm_free(vm); > + printf("\t ... PASSED\n"); > +} > + > int main(int argc, char **argv) > { > setbuf(stdout, NULL); > @@ -85,6 +166,7 @@ int main(int argc, char **argv) > > run_in_new_process(&verify_td_lifecycle); > run_in_new_process(&verify_report_fatal_error); > + run_in_new_process(&verify_td_ioexit); > > return 0; > } > -- > 2.43.0.472.g3155946c3a-goog > >
On 3/4/2024 10:19 AM, Yan Zhao wrote: > On Tue, Dec 12, 2023 at 12:46:25PM -0800, Sagi Shahar wrote: >> From: Erdem Aktas <erdemaktas@google.com> >> >> Verifies TDVMCALL<INSTRUCTION.IO> READ and WRITE operations. >> >> Signed-off-by: Erdem Aktas <erdemaktas@google.com> >> Signed-off-by: Sagi Shahar <sagis@google.com> >> Signed-off-by: Ackerley Tng <ackerleytng@google.com> >> Signed-off-by: Ryan Afranji <afranji@google.com> >> --- >> .../kvm/include/x86_64/tdx/test_util.h | 34 ++++++++ >> .../selftests/kvm/x86_64/tdx_vm_tests.c | 82 +++++++++++++++++++ >> 2 files changed, 116 insertions(+) >> >> diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h >> index 6d69921136bd..95a5d5be7f0b 100644 >> --- a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h >> +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h >> @@ -9,6 +9,40 @@ >> #define TDX_TEST_SUCCESS_PORT 0x30 >> #define TDX_TEST_SUCCESS_SIZE 4 >> >> +/** >> + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() was >> + * called in the guest. >> + */ >> +#define TDX_TEST_ASSERT_IO(VCPU, PORT, SIZE, DIR) \ >> + do { \ >> + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_IO) && \ >> + ((VCPU)->run->io.port == (PORT)) && \ >> + ((VCPU)->run->io.size == (SIZE)) && \ >> + ((VCPU)->run->io.direction == (DIR)), \ >> + "Got unexpected IO exit values: %u (%s) %d %d %d\n", \ >> + (VCPU)->run->exit_reason, \ >> + exit_reason_str((VCPU)->run->exit_reason), \ >> + (VCPU)->run->io.port, (VCPU)->run->io.size, \ >> + (VCPU)->run->io.direction); \ >> + } while (0) >> + >> +/** >> + * Check and report if there was some failure in the guest, either an exception >> + * like a triple fault, or if a tdx_test_fatal() was hit. >> + */ >> +#define TDX_TEST_CHECK_GUEST_FAILURE(VCPU) \ >> + do { \ >> + if ((VCPU)->run->exit_reason == KVM_EXIT_SYSTEM_EVENT) \ >> + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", \ >> + (VCPU)->run->system_event.data[1], \ >> + (VCPU)->run->system_event.data[1]); \ >> + } while (0) >> + >> /** >> * Assert that tdx_test_success() was called in the guest. >> */ >> diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c >> index 8638c7bbedaa..75467c407ca7 100644 >> --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c >> +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c >> @@ -2,6 +2,7 @@ >> >> #include <signal.h> >> #include "kvm_util_base.h" >> +#include "tdx/tdcall.h" >> #include "tdx/tdx.h" >> #include "tdx/tdx_util.h" >> #include "tdx/test_util.h" >> @@ -74,6 +75,86 @@ void verify_report_fatal_error(void) >> 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, delta; >> + uint64_t ret; >> + >> + data_out = 0xAB; >> + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, >> + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE, >> + &data_out); >> + if (ret) >> + tdx_test_fatal(ret); >> + >> + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, >> + TDG_VP_VMCALL_INSTRUCTION_IO_READ, >> + &data_in); >> + if (ret) >> + tdx_test_fatal(ret); >> + >> + delta = data_in - data_out; >> + if (delta != 1) >> + tdx_test_fatal(ret); >> + >> + tdx_test_success(); >> +} >> + >> +void verify_td_ioexit(void) >> +{ >> + struct kvm_vm *vm; >> + struct kvm_vcpu *vcpu; >> + >> + uint32_t port_data; >> + >> + vm = td_create(); >> + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); >> + vcpu = td_vcpu_add(vm, 0, guest_ioexit); >> + td_finalize(vm); >> + >> + printf("Verifying TD IO Exit:\n"); >> + >> + /* Wait for guest to do a IO write */ >> + td_vcpu_run(vcpu); >> + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > This check is a vain, because the first VMExit from vcpu run is always > KVM_EXIT_IO caused by tdg_vp_vmcall_instruction_io(). I think tdg_vp_vmcall_instruction_io() could fail if RCX (GPR select) doesn't meet the requirement (some bits must be 0). Although RCX is set by guest code (in selftest, it set in __tdx_hypercall()) and it will not trigger the error, it still can be used as a guard to make sure guest doesn't pass a invalid RCX. > > >> + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, >> + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); >> + port_data = *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); >> + >> + printf("\t ... IO WRITE: OK\n"); > So, even if there's an error in emulating writing of TDX_IOEXIT_TEST_PORT, > and guest would then find a failure and trigger tdx_test_fatal(), this line > will still print "IO WRITE: OK", which is not right. > >> + >> + /* >> + * Wait for the guest to do a IO read. Provide the previous written data >> + * + 1 back to the guest >> + */ >> + td_vcpu_run(vcpu); >> + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > This check is a vain, too, as in write case. > >> + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, >> + TDG_VP_VMCALL_INSTRUCTION_IO_READ); >> + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) = port_data + 1; >> + >> + printf("\t ... IO READ: OK\n"); > Same as in write case, this line should not be printed until after guest > finishing checking return code. > >> + >> + /* >> + * Wait for the guest to complete execution successfully. The read >> + * value is checked within the guest. >> + */ >> + td_vcpu_run(vcpu); >> + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); >> + TDX_TEST_ASSERT_SUCCESS(vcpu); >> + >> + printf("\t ... IO verify read/write values: OK\n"); >> + kvm_vm_free(vm); >> + printf("\t ... PASSED\n"); >> +} >> + >> int main(int argc, char **argv) >> { >> setbuf(stdout, NULL); >> @@ -85,6 +166,7 @@ int main(int argc, char **argv) >> >> run_in_new_process(&verify_td_lifecycle); >> run_in_new_process(&verify_report_fatal_error); >> + run_in_new_process(&verify_td_ioexit); >> >> return 0; >> } >> -- >> 2.43.0.472.g3155946c3a-goog >> >>
On Mon, Mar 04, 2024 at 05:16:53PM +0800, Binbin Wu wrote: > > > On 3/4/2024 10:19 AM, Yan Zhao wrote: > > On Tue, Dec 12, 2023 at 12:46:25PM -0800, Sagi Shahar wrote: > > > From: Erdem Aktas <erdemaktas@google.com> > > > > > > Verifies TDVMCALL<INSTRUCTION.IO> READ and WRITE operations. > > > > > > Signed-off-by: Erdem Aktas <erdemaktas@google.com> > > > Signed-off-by: Sagi Shahar <sagis@google.com> > > > Signed-off-by: Ackerley Tng <ackerleytng@google.com> > > > Signed-off-by: Ryan Afranji <afranji@google.com> > > > --- > > > .../kvm/include/x86_64/tdx/test_util.h | 34 ++++++++ > > > .../selftests/kvm/x86_64/tdx_vm_tests.c | 82 +++++++++++++++++++ > > > 2 files changed, 116 insertions(+) > > > > > > diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > > > index 6d69921136bd..95a5d5be7f0b 100644 > > > --- a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > > > +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h > > > @@ -9,6 +9,40 @@ > > > #define TDX_TEST_SUCCESS_PORT 0x30 > > > #define TDX_TEST_SUCCESS_SIZE 4 > > > +/** > > > + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() was > > > + * called in the guest. > > > + */ > > > +#define TDX_TEST_ASSERT_IO(VCPU, PORT, SIZE, DIR) \ > > > + do { \ > > > + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_IO) && \ > > > + ((VCPU)->run->io.port == (PORT)) && \ > > > + ((VCPU)->run->io.size == (SIZE)) && \ > > > + ((VCPU)->run->io.direction == (DIR)), \ > > > + "Got unexpected IO exit values: %u (%s) %d %d %d\n", \ > > > + (VCPU)->run->exit_reason, \ > > > + exit_reason_str((VCPU)->run->exit_reason), \ > > > + (VCPU)->run->io.port, (VCPU)->run->io.size, \ > > > + (VCPU)->run->io.direction); \ > > > + } while (0) > > > + > > > +/** > > > + * Check and report if there was some failure in the guest, either an exception > > > + * like a triple fault, or if a tdx_test_fatal() was hit. > > > + */ > > > +#define TDX_TEST_CHECK_GUEST_FAILURE(VCPU) \ > > > + do { \ > > > + if ((VCPU)->run->exit_reason == KVM_EXIT_SYSTEM_EVENT) \ > > > + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", \ > > > + (VCPU)->run->system_event.data[1], \ > > > + (VCPU)->run->system_event.data[1]); \ > > > + } while (0) > > > + > > > /** > > > * Assert that tdx_test_success() was called in the guest. > > > */ > > > diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > > > index 8638c7bbedaa..75467c407ca7 100644 > > > --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > > > +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c > > > @@ -2,6 +2,7 @@ > > > #include <signal.h> > > > #include "kvm_util_base.h" > > > +#include "tdx/tdcall.h" > > > #include "tdx/tdx.h" > > > #include "tdx/tdx_util.h" > > > #include "tdx/test_util.h" > > > @@ -74,6 +75,86 @@ void verify_report_fatal_error(void) > > > 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, delta; > > > + uint64_t ret; > > > + > > > + data_out = 0xAB; > > > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > > > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE, > > > + &data_out); > > > + if (ret) > > > + tdx_test_fatal(ret); > > > + > > > + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, > > > + TDG_VP_VMCALL_INSTRUCTION_IO_READ, > > > + &data_in); > > > + if (ret) > > > + tdx_test_fatal(ret); > > > + > > > + delta = data_in - data_out; > > > + if (delta != 1) > > > + tdx_test_fatal(ret); > > > + > > > + tdx_test_success(); > > > +} > > > + > > > +void verify_td_ioexit(void) > > > +{ > > > + struct kvm_vm *vm; > > > + struct kvm_vcpu *vcpu; > > > + > > > + uint32_t port_data; > > > + > > > + vm = td_create(); > > > + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); > > > + vcpu = td_vcpu_add(vm, 0, guest_ioexit); > > > + td_finalize(vm); > > > + > > > + printf("Verifying TD IO Exit:\n"); > > > + > > > + /* Wait for guest to do a IO write */ > > > + td_vcpu_run(vcpu); > > > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > > This check is a vain, because the first VMExit from vcpu run is always > > KVM_EXIT_IO caused by tdg_vp_vmcall_instruction_io(). > > I think tdg_vp_vmcall_instruction_io() could fail if RCX (GPR select) > doesn't > meet the requirement (some bits must be 0). > Although RCX is set by guest code (in selftest, it set in __tdx_hypercall()) > and it will not trigger the error, it still can be used as a guard to make > sure guest doesn't pass a invalid RCX. > Right. This check can be kept in case an failure is delivered to TD in host kernel directly, though it cannot guard if the failure will trigger an exit to user space (e.g. if kernel TDX code has a bug). > > > > > > > > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > > > + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); > > > + port_data = *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); > > > + > > > + printf("\t ... IO WRITE: OK\n"); > > So, even if there's an error in emulating writing of TDX_IOEXIT_TEST_PORT, > > and guest would then find a failure and trigger tdx_test_fatal(), this line > > will still print "IO WRITE: OK", which is not right. > > > > > + > > > + /* > > > + * Wait for the guest to do a IO read. Provide the previous written data > > > + * + 1 back to the guest > > > + */ > > > + td_vcpu_run(vcpu); > > > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > > This check is a vain, too, as in write case. > > > > > + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, > > > + TDG_VP_VMCALL_INSTRUCTION_IO_READ); > > > + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) = port_data + 1; > > > + > > > + printf("\t ... IO READ: OK\n"); > > Same as in write case, this line should not be printed until after guest > > finishing checking return code. > > > > > + > > > + /* > > > + * Wait for the guest to complete execution successfully. The read > > > + * value is checked within the guest. > > > + */ > > > + td_vcpu_run(vcpu); > > > + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); > > > + TDX_TEST_ASSERT_SUCCESS(vcpu); > > > + > > > + printf("\t ... IO verify read/write values: OK\n"); > > > + kvm_vm_free(vm); > > > + printf("\t ... PASSED\n"); > > > +} > > > + > > > int main(int argc, char **argv) > > > { > > > setbuf(stdout, NULL); > > > @@ -85,6 +166,7 @@ int main(int argc, char **argv) > > > run_in_new_process(&verify_td_lifecycle); > > > run_in_new_process(&verify_report_fatal_error); > > > + run_in_new_process(&verify_td_ioexit); > > > return 0; > > > } > > > -- > > > 2.43.0.472.g3155946c3a-goog > > > > > > >
diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h index 6d69921136bd..95a5d5be7f0b 100644 --- a/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/test_util.h @@ -9,6 +9,40 @@ #define TDX_TEST_SUCCESS_PORT 0x30 #define TDX_TEST_SUCCESS_SIZE 4 +/** + * Assert that some IO operation involving tdg_vp_vmcall_instruction_io() was + * called in the guest. + */ +#define TDX_TEST_ASSERT_IO(VCPU, PORT, SIZE, DIR) \ + do { \ + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_IO) && \ + ((VCPU)->run->io.port == (PORT)) && \ + ((VCPU)->run->io.size == (SIZE)) && \ + ((VCPU)->run->io.direction == (DIR)), \ + "Got unexpected IO exit values: %u (%s) %d %d %d\n", \ + (VCPU)->run->exit_reason, \ + exit_reason_str((VCPU)->run->exit_reason), \ + (VCPU)->run->io.port, (VCPU)->run->io.size, \ + (VCPU)->run->io.direction); \ + } while (0) + +/** + * Check and report if there was some failure in the guest, either an exception + * like a triple fault, or if a tdx_test_fatal() was hit. + */ +#define TDX_TEST_CHECK_GUEST_FAILURE(VCPU) \ + do { \ + if ((VCPU)->run->exit_reason == KVM_EXIT_SYSTEM_EVENT) \ + TEST_FAIL("Guest reported error. error code: %lld (0x%llx)\n", \ + (VCPU)->run->system_event.data[1], \ + (VCPU)->run->system_event.data[1]); \ + } while (0) + /** * Assert that tdx_test_success() was called in the guest. */ diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 8638c7bbedaa..75467c407ca7 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -2,6 +2,7 @@ #include <signal.h> #include "kvm_util_base.h" +#include "tdx/tdcall.h" #include "tdx/tdx.h" #include "tdx/tdx_util.h" #include "tdx/test_util.h" @@ -74,6 +75,86 @@ void verify_report_fatal_error(void) 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, delta; + uint64_t ret; + + data_out = 0xAB; + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE, + &data_out); + if (ret) + tdx_test_fatal(ret); + + ret = tdg_vp_vmcall_instruction_io(TDX_IOEXIT_TEST_PORT, 1, + TDG_VP_VMCALL_INSTRUCTION_IO_READ, + &data_in); + if (ret) + tdx_test_fatal(ret); + + delta = data_in - data_out; + if (delta != 1) + tdx_test_fatal(ret); + + tdx_test_success(); +} + +void verify_td_ioexit(void) +{ + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + + uint32_t port_data; + + vm = td_create(); + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); + vcpu = td_vcpu_add(vm, 0, guest_ioexit); + td_finalize(vm); + + printf("Verifying TD IO Exit:\n"); + + /* Wait for guest to do a IO write */ + td_vcpu_run(vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); + port_data = *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + printf("\t ... IO WRITE: OK\n"); + + /* + * Wait for the guest to do a IO read. Provide the previous written data + * + 1 back to the guest + */ + td_vcpu_run(vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_IO(vcpu, TDX_IOEXIT_TEST_PORT, 1, + TDG_VP_VMCALL_INSTRUCTION_IO_READ); + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) = port_data + 1; + + printf("\t ... IO READ: OK\n"); + + /* + * Wait for the guest to complete execution successfully. The read + * value is checked within the guest. + */ + td_vcpu_run(vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_SUCCESS(vcpu); + + printf("\t ... IO verify read/write values: OK\n"); + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { setbuf(stdout, NULL); @@ -85,6 +166,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_td_lifecycle); run_in_new_process(&verify_report_fatal_error); + run_in_new_process(&verify_td_ioexit); return 0; }