From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3F465C4332F for ; Tue, 12 Dec 2023 20:48:19 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5222C6B039D; Tue, 12 Dec 2023 15:47:52 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 4D2066B039C; Tue, 12 Dec 2023 15:47:52 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3241E6B039D; Tue, 12 Dec 2023 15:47:52 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 1B3E46B039B for ; Tue, 12 Dec 2023 15:47:52 -0500 (EST) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id F3F27A2031 for ; Tue, 12 Dec 2023 20:47:51 +0000 (UTC) X-FDA: 81559352742.14.65383BB Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) by imf17.hostedemail.com (Postfix) with ESMTP id 256244000E for ; Tue, 12 Dec 2023 20:47:49 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=IAd+G524; spf=pass (imf17.hostedemail.com: domain of 39cZ4ZQUKCJgK28AK8GG8D6.4GEDAFMP-EECN24C.GJ8@flex--sagis.bounces.google.com designates 209.85.214.202 as permitted sender) smtp.mailfrom=39cZ4ZQUKCJgK28AK8GG8D6.4GEDAFMP-EECN24C.GJ8@flex--sagis.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1702414070; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=8feJMu0CtGp4ESzuqj7WG5RYqMN4mFy6cD8e9ssBGqo=; b=nGvk3o8tZ2ekIH6irsQK8Y9YxMiqg7VYD7cCIpmBcnKm+OS1rxoB0tUDv2HuouwVAxrhPO xJs23DOXkUTECi0ZKe4eay4AZi+xCw6jLEdtoDC+nx31J1GoMgKm9Fz2yUBkGI4jcL0tR1 gotBnwEZKnDtLIXl583igUwFl0hzHkg= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1702414070; a=rsa-sha256; cv=none; b=yR9uusqaaYAYhxsp/n4MPIf1qybc7/pkrm3u0v8hU7eDTH+ERCoFY7n+WKUjc+MpOT1w32 H9RGsLuXzNyA5kbwNRULMNq563KmurBK+N2oWFeaniVkzSbLFt6Ji8oGlzWmPAoMLEArim DY+rpEMutKrkS+cwoJCWKq4KR1rITvA= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=IAd+G524; spf=pass (imf17.hostedemail.com: domain of 39cZ4ZQUKCJgK28AK8GG8D6.4GEDAFMP-EECN24C.GJ8@flex--sagis.bounces.google.com designates 209.85.214.202 as permitted sender) smtp.mailfrom=39cZ4ZQUKCJgK28AK8GG8D6.4GEDAFMP-EECN24C.GJ8@flex--sagis.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-1d04ce0214dso54522295ad.1 for ; Tue, 12 Dec 2023 12:47:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1702414069; x=1703018869; darn=kvack.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=8feJMu0CtGp4ESzuqj7WG5RYqMN4mFy6cD8e9ssBGqo=; b=IAd+G524/g07tf9fNoTRkK7zguG89nSby8dCR3YOXzrdsgGM/uq3zdNXWxYiwVYVmB nE9Qcw5QOpJDwOSvBXHXgZvnr9EpNEP8CiOlULVWjKrd0JZDbQE4flTIRAyq065oJHcK eEBlwrGambjYqRW+WIsFbHnTNGKCoHTkMv/I+YqUIlz+dkg9Q8zP2di2mEogIXEySdaJ 3aTmnBbBy5EwQQLNteoFM7yBvMM/vGCXmrGwAkUOwW+iy9c5MQmv5YdVRfI9gFACok8S iKOQP5+OvSeIb3RLmJlm/aIw1Z81Zweyhwi/Bbqv6lvSklWmBNeTKEmMzRdt4hkFMsvT UH8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1702414069; x=1703018869; 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=8feJMu0CtGp4ESzuqj7WG5RYqMN4mFy6cD8e9ssBGqo=; b=e86PmklHhVBAIXQGe/RGXq6ydkzsxcO/4luvkbVhhKX52nsyjU+xFUeIQGdCWakiJw z4EzUFD/A55C+bMS/mZL04cqjwv3LKwarV4PDi4ihxoEgICjvDhhHeETqvhwk2w2Zi5D DQpC1os8kUik/rq+Ux1+mv/jmeOzleqUmxFMTCV3nayC6LjuJgIrHwcuZEmMTCYWOD9c dhkrGFLJsTMHzzHtPb8jVUKlNCmESUEkFMRVjjrywjigta1EFoKWn8bE23d3zBe0sbDi U5V7yrlPmWldtglonqRs+qKNIokYOv5g7Q6RCYIoVqdQbPcny2sLxQbkc0TgeYP15jZ7 +5LA== X-Gm-Message-State: AOJu0Yw5GVsrkh7NcpXJPgHCxNiO3Ak1ByHuKN3T3tD0nBylXq1j1vsv qDiaM1l7vm1ux0xz5dPZ8w3rlMDarg== X-Google-Smtp-Source: AGHT+IFSk4F5+db5SoAoHbJjlttnLeiqRFEHGfqkJz5ocdw6pONiskwlwErk+BrOwZyHXHpPwhjJrT5LdQ== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:903:41cf:b0:1d0:80cd:4c44 with SMTP id u15-20020a17090341cf00b001d080cd4c44mr51797ple.10.1702414069034; Tue, 12 Dec 2023 12:47:49 -0800 (PST) Date: Tue, 12 Dec 2023 12:46:43 -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-29-sagis@google.com> Subject: [RFC PATCH v5 28/29] KVM: selftests: TDX: Add TDX UPM selftest From: Sagi Shahar To: linux-kselftest@vger.kernel.org, Ackerley Tng , Ryan Afranji , Erdem Aktas , Sagi Shahar , Isaku Yamahata Cc: Sean Christopherson , Paolo Bonzini , Shuah Khan , Peter Gonda , Haibo Xu , Chao Peng , Vishal Annapurve , Roger Wang , Vipin Sharma , 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-Stat-Signature: tc9rt79izej83s5t7dy6zyuo7wan3te7 X-Rspamd-Server: rspam10 X-Rspamd-Queue-Id: 256244000E X-Rspam-User: X-HE-Tag: 1702414069-853807 X-HE-Meta: U2FsdGVkX19GSyflsAF1PAre19GfzgjRytXH0+z41D71WXiXQHhZS5P0xt8zcSXW49Y4TAlLh6DJ4/cbd6nBMwwKxB+nUmipzGFic9s+pU2FmCvgRmFmqvamAiXegp56G37YZtjvN7WNBJBX4oM2JQUceoGhWTzqxFytRWN4M6uf6I53CrgnqVnHUoPfwRGAiEgtAE1knZZFP/5OthZXJNO+biRXLme7c5+WDjTJJC5UiE+toJ0Ah8VEMpsniqxfNF1NGdPe/GsxYAwE6WbGibmuaFaGb1PK1poyhJmat8MrgFJHA7db7gNOPXd9QXq8yF0mVy/z9s4ADER6FuYPNDcoQxDIkMTHQ0fnLSgPgr1sHxl9fBAVLqMZf4xWmez+MqLwzoNOdksuBII5TAHx43o0dL+Cc9EaWARXOrxwFToEyIdQvzwF2E43gtAmyVerB7+MAtzMNsLsWW85OyRe3Ps+4m4XDxFcv5JBl+EoOA+iurwiLibYC54gswC9I70kj1VnG44fYVfVv77FFvMe+rndAKU97aJU/SHE+WQClUI/nylCqzR7XXkQOxReBmRMXiz/kNd+WX9atxmXzXEevc2G/K5LuIqk0/r5X0exhsLFdt0h0abq3zLpsf4kOzRbyVZuOM1fIMlcwLogCEq4QO5s+ndEtEShVq7FoxWbSvg/Ftr45PTdDqRvGJm6gcmAC8giaUNNx/cHce/QUHrHpPeNRjzVjscnMYICj4FpFeJu6duV6lPK8lscSqHIqFWsKqrX13z81WYZL4tFwdzbX3qmoh4dP4kZrHEhwovNtowPoKMj28OmPMQDqvs5d6o/lMyNBPSv8CcfziGjQ1xj0TB1koq5HAaDv5ZxQjQ5yeL5FQZinrsSGVyeg2/5pxuDL2bbRtvlYiFSWp1CfRQkx+kCrkrv3SqvbgK4YUTfAXFdPsJ19A64HzNQG7cKrNOhPdepmexS5IeetafVnKE elHNtnBR if/T+u7MZElXxagtkWvWPZ532A2AJJS6omMHfxfY8BMQkMeJAJYovdd6ghVF0BajtC7KlxsJYBd5ZYRh9RpDZTqzBMExE7qK4jr3rU8TRu5qbSX/AwHRMDIi3JFkadI62/6hDWlaTyQyA0eginGsUrsm6zCcrgBxKHQSE7S8LXd18RIylRoGsV8BpeGkVoYcxbHE/5LvgzgUjrT2HuFuwqlAKavEA6biSQXHuUame/zGm8LQkpdy4mhNH+l4pDCMDpPVhrh962xMrDh9lSblPpftR1+L9uSDXT1mVCAaBdQgoi2ZJzK5Zsa/SRUDNCF24DmZP02uKKcnX9udzVP8jDhgPtKMhvGYwTkEUMp/r/U3yjgZYLZnshRbIMpFc74J89pbmiJr0zXK4Pg5wFZKPE1Z5CElGXacY4KNJe2EcdrZhM/6/eo8ub7+Yuu3bBg8Qq7gqGXXRSbGOlZZHEY98P6BRF7BM1XXjwKkbg3vEfyNXs4DEEPPoE3HbSMNlRAOzcRuhxcrm5VtTTAUZSyJNGkopLjORNkdveT/J7k7Ewq3o7qaNORx5F76glHEkLBihjD0K7Le8dJOfbdNeKGuUl9rzh34jOEJML6UT X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Ackerley Tng This tests the use of guest memory with explicit MapGPA calls. Signed-off-by: Ackerley Tng Signed-off-by: Ryan Afranji Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/tdx_upm_test.c | 401 ++++++++++++++++++ 2 files changed, 402 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/tdx_upm_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 8c0a6b395ee5..2f2669af15d6 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -157,6 +157,7 @@ TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test TEST_GEN_PROGS_x86_64 += system_counter_offset_test TEST_GEN_PROGS_x86_64 += x86_64/tdx_vm_tests TEST_GEN_PROGS_x86_64 += x86_64/tdx_shared_mem_test +TEST_GEN_PROGS_x86_64 += x86_64/tdx_upm_test # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/x86_64/tdx_upm_test.c b/tools/testing/selftests/kvm/x86_64/tdx_upm_test.c new file mode 100644 index 000000000000..44671874a4f1 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/tdx_upm_test.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include + +#include "kvm_util_base.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" + +/* TDX UPM test patterns */ +#define PATTERN_CONFIDENCE_CHECK (0x11) +#define PATTERN_HOST_FOCUS (0x22) +#define PATTERN_GUEST_GENERAL (0x33) +#define PATTERN_GUEST_FOCUS (0x44) + +/* + * 0x80000000 is arbitrarily selected. The selected address need not be the same + * as TDX_UPM_TEST_AREA_GVA_PRIVATE, but it should not overlap with selftest + * code or boot page. + */ +#define TDX_UPM_TEST_AREA_GPA (0x80000000) +/* Test area GPA is arbitrarily selected */ +#define TDX_UPM_TEST_AREA_GVA_PRIVATE (0x90000000) +/* Select any bit that can be used as a flag */ +#define TDX_UPM_TEST_AREA_GVA_SHARED_BIT (32) +/* + * TDX_UPM_TEST_AREA_GVA_SHARED is used to map the same GPA twice into the + * guest, once as shared and once as private + */ +#define TDX_UPM_TEST_AREA_GVA_SHARED \ + (TDX_UPM_TEST_AREA_GVA_PRIVATE | \ + BIT_ULL(TDX_UPM_TEST_AREA_GVA_SHARED_BIT)) + +/* The test area is 2MB in size */ +#define TDX_UPM_TEST_AREA_SIZE (2 << 20) +/* 0th general area is 1MB in size */ +#define TDX_UPM_GENERAL_AREA_0_SIZE (1 << 20) +/* Focus area is 40KB in size */ +#define TDX_UPM_FOCUS_AREA_SIZE (40 << 10) +/* 1st general area is the rest of the space in the test area */ +#define TDX_UPM_GENERAL_AREA_1_SIZE \ + (TDX_UPM_TEST_AREA_SIZE - TDX_UPM_GENERAL_AREA_0_SIZE - \ + TDX_UPM_FOCUS_AREA_SIZE) + +/* + * The test memory area is set up as two general areas, sandwiching a focus + * area. The general areas act as control areas. After they are filled, they + * are not expected to change throughout the tests. The focus area is memory + * permissions change from private to shared and vice-versa. + * + * The focus area is intentionally small, and sandwiched to test that when the + * focus area's permissions change, the other areas' permissions are not + * affected. + */ +struct __packed tdx_upm_test_area { + uint8_t general_area_0[TDX_UPM_GENERAL_AREA_0_SIZE]; + uint8_t focus_area[TDX_UPM_FOCUS_AREA_SIZE]; + uint8_t general_area_1[TDX_UPM_GENERAL_AREA_1_SIZE]; +}; + +static void fill_test_area(struct tdx_upm_test_area *test_area_base, + uint8_t pattern) +{ + memset(test_area_base, pattern, sizeof(*test_area_base)); +} + +static void fill_focus_area(struct tdx_upm_test_area *test_area_base, + uint8_t pattern) +{ + memset(test_area_base->focus_area, pattern, + sizeof(test_area_base->focus_area)); +} + +static bool check_area(uint8_t *base, uint64_t size, uint8_t expected_pattern) +{ + size_t i; + + for (i = 0; i < size; i++) { + if (base[i] != expected_pattern) + return false; + } + + return true; +} + +static bool check_general_areas(struct tdx_upm_test_area *test_area_base, + uint8_t expected_pattern) +{ + return (check_area(test_area_base->general_area_0, + sizeof(test_area_base->general_area_0), + expected_pattern) && + check_area(test_area_base->general_area_1, + sizeof(test_area_base->general_area_1), + expected_pattern)); +} + +static bool check_focus_area(struct tdx_upm_test_area *test_area_base, + uint8_t expected_pattern) +{ + return check_area(test_area_base->focus_area, + sizeof(test_area_base->focus_area), expected_pattern); +} + +static bool check_test_area(struct tdx_upm_test_area *test_area_base, + uint8_t expected_pattern) +{ + return (check_general_areas(test_area_base, expected_pattern) && + check_focus_area(test_area_base, expected_pattern)); +} + +static bool fill_and_check(struct tdx_upm_test_area *test_area_base, uint8_t pattern) +{ + fill_test_area(test_area_base, pattern); + + return check_test_area(test_area_base, pattern); +} + +#define TDX_UPM_TEST_ASSERT(x) \ + do { \ + if (!(x)) \ + tdx_test_fatal(__LINE__); \ + } while (0) + +/* + * Shared variables between guest and host + */ +static struct tdx_upm_test_area *test_area_gpa_private; +static struct tdx_upm_test_area *test_area_gpa_shared; + +/* + * Test stages for syncing with host + */ +enum { + SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST = 1, + SYNC_CHECK_READ_SHARED_MEMORY_FROM_HOST, + SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST_AGAIN, +}; + +#define TDX_UPM_TEST_ACCEPT_PRINT_PORT 0x87 + +/** + * Does vcpu_run, and also manages memory conversions if requested by the TD. + */ +void vcpu_run_and_manage_memory_conversions(struct kvm_vm *vm, + struct kvm_vcpu *vcpu) +{ + for (;;) { + vcpu_run(vcpu); + if (vcpu->run->exit_reason == KVM_EXIT_TDX && + vcpu->run->tdx.type == KVM_EXIT_TDX_VMCALL && + vcpu->run->tdx.u.vmcall.subfunction == TDG_VP_VMCALL_MAP_GPA) { + struct kvm_tdx_vmcall *vmcall_info = &vcpu->run->tdx.u.vmcall; + uint64_t gpa = vmcall_info->in_r12 & ~vm->arch.s_bit; + + handle_memory_conversion(vm, gpa, vmcall_info->in_r13, + !(vm->arch.s_bit & vmcall_info->in_r12)); + vmcall_info->status_code = 0; + continue; + } else if ( + vcpu->run->exit_reason == KVM_EXIT_IO && + vcpu->run->io.port == TDX_UPM_TEST_ACCEPT_PRINT_PORT) { + uint64_t gpa = tdx_test_read_64bit( + vcpu, TDX_UPM_TEST_ACCEPT_PRINT_PORT); + printf("\t ... guest accepting 1 page at GPA: 0x%lx\n", gpa); + continue; + } + + break; + } +} + +static void guest_upm_explicit(void) +{ + uint64_t ret = 0; + uint64_t failed_gpa; + + struct tdx_upm_test_area *test_area_gva_private = + (struct tdx_upm_test_area *)TDX_UPM_TEST_AREA_GVA_PRIVATE; + struct tdx_upm_test_area *test_area_gva_shared = + (struct tdx_upm_test_area *)TDX_UPM_TEST_AREA_GVA_SHARED; + + /* Check: host reading private memory does not modify guest's view */ + fill_test_area(test_area_gva_private, PATTERN_GUEST_GENERAL); + + tdx_test_report_to_user_space(SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST); + + TDX_UPM_TEST_ASSERT( + check_test_area(test_area_gva_private, PATTERN_GUEST_GENERAL)); + + /* Remap focus area as shared */ + ret = tdg_vp_vmcall_map_gpa((uint64_t)test_area_gpa_shared->focus_area, + sizeof(test_area_gpa_shared->focus_area), + &failed_gpa); + TDX_UPM_TEST_ASSERT(!ret); + + /* General areas should be unaffected by remapping */ + TDX_UPM_TEST_ASSERT( + check_general_areas(test_area_gva_private, PATTERN_GUEST_GENERAL)); + + /* + * Use memory contents to confirm that the memory allocated using mmap + * is used as backing memory for shared memory - PATTERN_CONFIDENCE_CHECK + * was written by the VMM at the beginning of this test. + */ + TDX_UPM_TEST_ASSERT( + check_focus_area(test_area_gva_shared, PATTERN_CONFIDENCE_CHECK)); + + /* Guest can use focus area after remapping as shared */ + fill_focus_area(test_area_gva_shared, PATTERN_GUEST_FOCUS); + + tdx_test_report_to_user_space(SYNC_CHECK_READ_SHARED_MEMORY_FROM_HOST); + + /* Check that guest has the same view of shared memory */ + TDX_UPM_TEST_ASSERT( + check_focus_area(test_area_gva_shared, PATTERN_HOST_FOCUS)); + + /* Remap focus area back to private */ + ret = tdg_vp_vmcall_map_gpa((uint64_t)test_area_gpa_private->focus_area, + sizeof(test_area_gpa_private->focus_area), + &failed_gpa); + TDX_UPM_TEST_ASSERT(!ret); + + /* General areas should be unaffected by remapping */ + TDX_UPM_TEST_ASSERT( + check_general_areas(test_area_gva_private, PATTERN_GUEST_GENERAL)); + + /* Focus area should be zeroed after remapping */ + TDX_UPM_TEST_ASSERT(check_focus_area(test_area_gva_private, 0)); + + tdx_test_report_to_user_space(SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST_AGAIN); + + /* Check that guest can use private memory after focus area is remapped as private */ + TDX_UPM_TEST_ASSERT( + fill_and_check(test_area_gva_private, PATTERN_GUEST_GENERAL)); + + tdx_test_success(); +} + +static void run_selftest(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + struct tdx_upm_test_area *test_area_base_hva) +{ + vcpu_run(vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_IO(vcpu, TDX_TEST_REPORT_PORT, TDX_TEST_REPORT_SIZE, + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); + TEST_ASSERT_EQ(*(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset), + SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST); + + /* + * Check that host should read PATTERN_CONFIDENCE_CHECK from guest's + * private memory. This confirms that regular memory (userspace_addr in + * struct kvm_userspace_memory_region) is used to back the host's view + * of private memory, since PATTERN_CONFIDENCE_CHECK was written to that + * memory before starting the guest. + */ + TEST_ASSERT(check_test_area(test_area_base_hva, PATTERN_CONFIDENCE_CHECK), + "Host should read PATTERN_CONFIDENCE_CHECK from guest's private memory."); + + vcpu_run_and_manage_memory_conversions(vm, vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_IO(vcpu, TDX_TEST_REPORT_PORT, TDX_TEST_REPORT_SIZE, + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); + TEST_ASSERT_EQ(*(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset), + SYNC_CHECK_READ_SHARED_MEMORY_FROM_HOST); + + TEST_ASSERT(check_focus_area(test_area_base_hva, PATTERN_GUEST_FOCUS), + "Host should have the same view of shared memory as guest."); + TEST_ASSERT(check_general_areas(test_area_base_hva, PATTERN_CONFIDENCE_CHECK), + "Host's view of private memory should still be backed by regular memory."); + + /* Check that host can use shared memory */ + fill_focus_area(test_area_base_hva, PATTERN_HOST_FOCUS); + TEST_ASSERT(check_focus_area(test_area_base_hva, PATTERN_HOST_FOCUS), + "Host should be able to use shared memory."); + + vcpu_run_and_manage_memory_conversions(vm, vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_IO(vcpu, TDX_TEST_REPORT_PORT, TDX_TEST_REPORT_SIZE, + TDG_VP_VMCALL_INSTRUCTION_IO_WRITE); + TEST_ASSERT_EQ(*(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset), + SYNC_CHECK_READ_PRIVATE_MEMORY_FROM_HOST_AGAIN); + + TEST_ASSERT(check_general_areas(test_area_base_hva, PATTERN_CONFIDENCE_CHECK), + "Host's view of private memory should be backed by regular memory."); + TEST_ASSERT(check_focus_area(test_area_base_hva, PATTERN_HOST_FOCUS), + "Host's view of private memory should be backed by regular memory."); + + vcpu_run(vcpu); + TDX_TEST_CHECK_GUEST_FAILURE(vcpu); + TDX_TEST_ASSERT_SUCCESS(vcpu); + + printf("\t ... PASSED\n"); +} + +static bool address_between(uint64_t addr, void *lo, void *hi) +{ + return (uint64_t)lo <= addr && addr < (uint64_t)hi; +} + +static void guest_ve_handler(struct ex_regs *regs) +{ + uint64_t ret; + struct ve_info ve; + + ret = tdg_vp_veinfo_get(&ve); + TDX_UPM_TEST_ASSERT(!ret); + + /* For this test, we will only handle EXIT_REASON_EPT_VIOLATION */ + TDX_UPM_TEST_ASSERT(ve.exit_reason == EXIT_REASON_EPT_VIOLATION); + + /* Validate GPA in fault */ + TDX_UPM_TEST_ASSERT( + address_between(ve.gpa, + test_area_gpa_private->focus_area, + test_area_gpa_private->general_area_1)); + + tdx_test_send_64bit(TDX_UPM_TEST_ACCEPT_PRINT_PORT, ve.gpa); + +#define MEM_PAGE_ACCEPT_LEVEL_4K 0 +#define MEM_PAGE_ACCEPT_LEVEL_2M 1 + ret = tdg_mem_page_accept(ve.gpa, MEM_PAGE_ACCEPT_LEVEL_4K); + TDX_UPM_TEST_ASSERT(!ret); +} + +static void verify_upm_test(void) +{ + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + + vm_vaddr_t test_area_gva_private; + struct tdx_upm_test_area *test_area_base_hva; + uint64_t test_area_npages; + + vm = td_create(); + td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); + vcpu = td_vcpu_add(vm, 0, guest_upm_explicit); + + vm_install_exception_handler(vm, VE_VECTOR, guest_ve_handler); + + /* + * 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_area_npages = TDX_UPM_TEST_AREA_SIZE / vm->page_size; + vm_userspace_mem_region_add(vm, + VM_MEM_SRC_ANONYMOUS, TDX_UPM_TEST_AREA_GPA, + 3, test_area_npages, KVM_MEM_PRIVATE); + + test_area_gva_private = ____vm_vaddr_alloc( + vm, TDX_UPM_TEST_AREA_SIZE, TDX_UPM_TEST_AREA_GVA_PRIVATE, + TDX_UPM_TEST_AREA_GPA, 3, true); + TEST_ASSERT_EQ(test_area_gva_private, TDX_UPM_TEST_AREA_GVA_PRIVATE); + + test_area_gpa_private = (struct tdx_upm_test_area *) + addr_gva2gpa(vm, test_area_gva_private); + virt_map_shared(vm, TDX_UPM_TEST_AREA_GVA_SHARED, + (uint64_t)test_area_gpa_private, + test_area_npages); + TEST_ASSERT_EQ(addr_gva2gpa(vm, TDX_UPM_TEST_AREA_GVA_SHARED), + (vm_paddr_t)test_area_gpa_private); + + test_area_base_hva = addr_gva2hva(vm, TDX_UPM_TEST_AREA_GVA_PRIVATE); + + TEST_ASSERT(fill_and_check(test_area_base_hva, PATTERN_CONFIDENCE_CHECK), + "Failed to mark memory intended as backing memory for TD shared memory"); + + sync_global_to_guest(vm, test_area_gpa_private); + test_area_gpa_shared = (struct tdx_upm_test_area *) + ((uint64_t)test_area_gpa_private | BIT_ULL(vm->pa_bits - 1)); + sync_global_to_guest(vm, test_area_gpa_shared); + + td_finalize(vm); + + printf("Verifying UPM functionality: explicit MapGPA\n"); + + run_selftest(vm, vcpu, test_area_base_hva); + + kvm_vm_free(vm); +} + +int main(int argc, char **argv) +{ + /* Disable stdout buffering */ + setbuf(stdout, NULL); + + if (!is_tdx_enabled()) { + printf("TDX is not supported by the KVM\n" + "Skipping the TDX tests.\n"); + return 0; + } + + run_in_new_process(&verify_upm_test); +} -- 2.43.0.472.g3155946c3a-goog