From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82770ECAAD5 for ; Tue, 30 Aug 2022 22:20:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231898AbiH3WUZ (ORCPT ); Tue, 30 Aug 2022 18:20:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231788AbiH3WUL (ORCPT ); Tue, 30 Aug 2022 18:20:11 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C67C225EBB for ; Tue, 30 Aug 2022 15:20:07 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id rj3-20020a17090b3e8300b001fae0be4dc4so11810616pjb.7 for ; Tue, 30 Aug 2022 15:20:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=/1/sdSVljrZtE+cOlvr7FEjtfDcy2AsBCQfMmau9WfQ=; b=Hl5NJHIIf9AjxMn6KkyCTnFp1wbi9nT9TChdGDiN1QnlBXWMcbuTu/orvkNm/XT6X6 x+yi9M5RODBfwi/1eZg7fqFXu8DstSIpVwVVk1PZHjDV8IhyrpZvy2K4WYJft72eyPfZ AnwR8ehdBDS5R5ohZHvImQuYc3s6Nj3pMj5WlsPhC9RssJcPIZkhF+OODAeStTz2b/iJ 1yN1+NJPHEf+wblVhbTKJ1CAbiPm7LtWcpo8+sfVTLwsded6UwMxIrSmWG35wtNUiMAq DNUn2AjMXNEWMoAfEivES+z26jvGelo4VfDMKN/KRE7q0o66Vbgg7cGEXiaWnk3g7+jK dKMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=/1/sdSVljrZtE+cOlvr7FEjtfDcy2AsBCQfMmau9WfQ=; b=gfSx85FuV5fiK+7NqdcUjA0jObXQekQ9+0spoxyXrjou1IBXwnfcKYvL45yi2Ru+Pi nRsCMn4i5Os19ViuVos9fnyAi6oU0lTpKXD13EgXMHbHztwSsENZdZ46Jn3qrJuSiFot uKeWDu2UNU//QHHwbArglIP9adIVfSimddtuwrageKFn/srjmcdWhT0lHGHzDicAvK7v oYpjefbZpUlH/+D6frH53jmr4cywwCvxnRV7uaYCQKxXbTnmIiYqNdBDNybGxJuYXV0d iTBz1/9gCtWZoSZQ0wUvIwu340/iqnnuBQsclAgYBuYJY7cVxAeFZDNSUnw0WJYcUp2m HgMg== X-Gm-Message-State: ACgBeo1bc81tEQku3v7/Ab1hCX0BSzXA6r7QyPMUGg8GoTNiWCyamloj WRDcoLWiJGLR5J27nquaslBTDibFmg== X-Google-Smtp-Source: AA6agR6eeDtQGXqnkPM1B1p4L+32NSn7HTIayprlj+H2vAC0mW1iQTGm+kZwcup5REG0kEuCvw/zSq/9hQ== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:902:c613:b0:174:7a32:f76 with SMTP id r19-20020a170902c61300b001747a320f76mr15784815plr.165.1661898007252; Tue, 30 Aug 2022 15:20:07 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:44 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-2-sagis@google.com> Subject: [RFC PATCH v2 01/17] KVM: selftests: Add support for creating non-default type VMs From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Erdem Aktas Currently vm_create function only creates KVM_VM_TYPE_DEFAULT type VMs. Adding type parameter to ____vm_create to create new VM types. Signed-off-by: Erdem Aktas Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- tools/testing/selftests/kvm/include/kvm_util_base.h | 6 ++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/te= sting/selftests/kvm/include/kvm_util_base.h index 24fde97f6121..2de7a7a2e56b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -26,6 +26,8 @@ =20 #define NSEC_PER_SEC 1000000000L =20 +#define KVM_VM_TYPE_DEFAULT 0 + typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ =20 @@ -642,13 +644,13 @@ vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); * __vm_create() does NOT create vCPUs, @nr_runnable_vcpus is used purely = to * calculate the amount of memory needed for per-vCPU data, e.g. stacks. */ -struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages); +struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages, i= nt type); struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_v= cpus, uint64_t nr_extra_pages); =20 static inline struct kvm_vm *vm_create_barebones(void) { - return ____vm_create(VM_MODE_DEFAULT, 0); + return ____vm_create(VM_MODE_DEFAULT, 0, KVM_VM_TYPE_DEFAULT); } =20 static inline struct kvm_vm *vm_create(uint32_t nr_runnable_vcpus) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 9889fe0d8919..ac10ad8919a6 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -143,7 +143,7 @@ const struct vm_guest_mode_params vm_guest_mode_params[= ] =3D { _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_pa= rams) =3D=3D NUM_VM_MODES, "Missing new mode params?"); =20 -struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages) +struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages, i= nt type) { struct kvm_vm *vm; =20 @@ -159,7 +159,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode, u= int64_t nr_pages) hash_init(vm->regions.slot_hash); =20 vm->mode =3D mode; - vm->type =3D 0; + vm->type =3D type; =20 vm->pa_bits =3D vm_guest_mode_params[mode].pa_bits; vm->va_bits =3D vm_guest_mode_params[mode].va_bits; @@ -294,7 +294,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uin= t32_t nr_runnable_vcpus, nr_extra_pages); struct kvm_vm *vm; =20 - vm =3D ____vm_create(mode, nr_pages); + vm =3D ____vm_create(mode, nr_pages, KVM_VM_TYPE_DEFAULT); =20 kvm_vm_elf_load(vm, program_invocation_name); =20 --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 546ECECAAD4 for ; Tue, 30 Aug 2022 22:20:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231481AbiH3WUT (ORCPT ); Tue, 30 Aug 2022 18:20:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51906 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231771AbiH3WUM (ORCPT ); Tue, 30 Aug 2022 18:20:12 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6BF66237D6 for ; Tue, 30 Aug 2022 15:20:09 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id q14-20020a6557ce000000b0041da9c3c244so6135324pgr.22 for ; Tue, 30 Aug 2022 15:20:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=3HxxuVLsYM4LbX1ZJk6AwjOjKvaVUee6Ed1CIvyPobo=; b=ou2LC/uznCmojGsu2adFtZe9ePHLlOlZT45KWYzgyOLWJL73xJXhtKjtgBdciisqhP ScwjqvFEJKos9r6Y3kW0lEu9v46WdkMQY08oTqT/fxBVf5J6e4aeoD8weV0XQhbt1Bu9 kmlglab9XdK/Qm1WvyOQ4+Ut04RZnKRS/mp/4SFwWgEL694sWRl50uxjBTB9wmILwPu+ WTE6dn2LZe6E7SM+iM5hpIfjSpFbc8rYLhQ5oUgA8Nw/V3Oi9NHlXpcuLzvRTezzGHmI I7henPdIjV18lhNZ+o4e8jTb0LEzaSaPlluwdcMHBZ1PQzirZ/4uArlWNtSIHcopDC38 agAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=3HxxuVLsYM4LbX1ZJk6AwjOjKvaVUee6Ed1CIvyPobo=; b=pOmDozRkE7nQtNUyBJhxzNwqRVIpaN4v6+5sv9H1ksvUsuW9LkCt93eLpt/wxgZBSx XnrR9A9Mi66T97XxSyn0Dslr1JF0t2eQZ40kra9v+AV1wZhoB6kqtq0dSc2d/cVxe5lh 7/JOwNWapvUm2LdII6PtlX1MZk6ph5sqKx5CiZSGpJTF+UToX3xRQ35b56+sUFqUSVlK ic7wouPtiwH3pR7h+tliSx5K8ydIpFatwc1YaTCbqrBUZ3oMCVXcQVpQa+/g+qyk042I a0gCHQpM1C+q5S1surgjcVfo9odiO5hxJf3HonfosjY2VYNzftLr+lWj5P8+ohtvYMG3 bPqg== X-Gm-Message-State: ACgBeo3HHkpW9wG5sTxbzzYt5oImzqsz622E4RzErf/5I4/zCBbmhPu9 l2aogufD26RU6RIWISCYz9Td8MvLVg== X-Google-Smtp-Source: AA6agR7JKD3ejKHzD2l9L7o0rtelwuqyQp4z5d7G1KXA0pvoNS1VYeQut5119tJCIi9ypTXiSbUw5mnSBw== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a63:8a4b:0:b0:42b:576a:bc2 with SMTP id y72-20020a638a4b000000b0042b576a0bc2mr20133311pgd.450.1661898008841; Tue, 30 Aug 2022 15:20:08 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:45 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-3-sagis@google.com> Subject: [RFC PATCH v2 02/17] KVM: selftest: Add helper functions to create TDX VMs From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Erdem Aktas TDX requires additional IOCTLs to initialize VM and vCPUs, to add private memory and to finalize the VM memory. Also additional utility functions are provided to create a guest image that will include test code. TDX enabled VM's memory is encrypted and cannot be modified or observed by the VMM. We need to create a guest image that includes the testing code. When TDX is enabled, vCPUs will enter guest mode with 32 bit mode with paging disabled. TDX requires the CPU to run on long mode with paging enabled. The guest image should have transition code from 32 bit to 64 bit, enable paging and run the testing code. There has to be predifined offset values for each data structure that will be used by the guest code. The guest image layout is as following: | Page Tables | GDTR | GDT | Stack | Testing Code | Transition Boot Code | Guest image will be loaded to the bottom of the first 4GB of the memory. Signed-off-by: Erdem Aktas Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/kvm_util_base.h | 6 + .../selftests/kvm/include/x86_64/processor.h | 1 + .../selftests/kvm/lib/x86_64/processor.c | 27 ++ tools/testing/selftests/kvm/lib/x86_64/tdx.h | 86 +++++ .../selftests/kvm/lib/x86_64/tdx_lib.c | 338 ++++++++++++++++++ 6 files changed, 459 insertions(+) create mode 100644 tools/testing/selftests/kvm/lib/x86_64/tdx.h create mode 100644 tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index 690b499c3471..ad4d60dadc06 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -52,6 +52,7 @@ LIBKVM_x86_64 +=3D lib/x86_64/handlers.S LIBKVM_x86_64 +=3D lib/x86_64/perf_test_util.c LIBKVM_x86_64 +=3D lib/x86_64/processor.c LIBKVM_x86_64 +=3D lib/x86_64/svm.c +LIBKVM_x86_64 +=3D lib/x86_64/tdx_lib.c LIBKVM_x86_64 +=3D lib/x86_64/ucall.c LIBKVM_x86_64 +=3D lib/x86_64/vmx.c =20 diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/te= sting/selftests/kvm/include/kvm_util_base.h index 2de7a7a2e56b..8d3bcf1719c6 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -653,6 +653,12 @@ static inline struct kvm_vm *vm_create_barebones(void) return ____vm_create(VM_MODE_DEFAULT, 0, KVM_VM_TYPE_DEFAULT); } =20 +/* TDX VMs are always created with no memory and memory is added later */ +static inline struct kvm_vm *vm_create_tdx(void) +{ + return ____vm_create(VM_MODE_DEFAULT, 0, KVM_X86_TDX_VM); +} + static inline struct kvm_vm *vm_create(uint32_t nr_runnable_vcpus) { return __vm_create(VM_MODE_DEFAULT, nr_runnable_vcpus, 0); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools= /testing/selftests/kvm/include/x86_64/processor.h index 45edf45821d0..57bbab7d025c 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -855,6 +855,7 @@ enum pg_level { #define PG_SIZE_1G PG_LEVEL_SIZE(PG_LEVEL_1G) =20 void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int = level); +struct kvm_vcpu *vm_vcpu_add_tdx(struct kvm_vm *vm, uint32_t vcpu_id); =20 /* * Basic CPU control in CR0 diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/tes= ting/selftests/kvm/lib/x86_64/processor.c index f35626df1dea..2a6e28c769f2 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -8,6 +8,7 @@ #include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "tdx.h" =20 #ifndef NUM_INTERRUPTS #define NUM_INTERRUPTS 256 @@ -641,6 +642,32 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, u= int32_t vcpu_id, return vcpu; } =20 +/* + * Adds a vCPU to a TD (Trusted Domain) with minimum defaults. It will no= t set + * up any general purpose registers as they will be initialized by the TDX= . In + * TDX, vCPUs RIP is set to 0xFFFFFFF0. See Intel TDX EAS Section "Initial= State + * of Guest GPRs" for more information on vCPUs initial register values wh= en + * entering the TD first time. + * + * Input Args: + * vm - Virtual Machine + * vcpuid - The id of the VCPU to add to the VM. + */ +struct kvm_vcpu *vm_vcpu_add_tdx(struct kvm_vm *vm, uint32_t vcpu_id) +{ + struct kvm_mp_state mp_state; + struct kvm_vcpu *vcpu; + + vcpu =3D __vm_vcpu_add(vm, vcpu_id); + initialize_td_vcpu(vcpu); + + /* Setup the MP state */ + mp_state.mp_state =3D 0; + vcpu_mp_state_set(vcpu, &mp_state); + + return vcpu; +} + struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id) { struct kvm_vcpu *vcpu =3D __vm_vcpu_add(vm, vcpu_id); diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h new file mode 100644 index 000000000000..61b997dfc420 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef KVM_LIB_TDX_H_ +#define KVM_LIB_TDX_H_ + +#include +#include "processor.h" + +/* + * Max page size for the guest image. + */ +#define TDX_GUEST_MAX_NR_PAGES 10000 + +/* + * Page Table Address used when paging is enabled. + */ +#define TDX_GUEST_PT_FIXED_ADDR (0xFFFFFFFF -\ + (TDX_GUEST_MAX_NR_PAGES * PAGE_SIZE) + 1) + +/* + * Max Page Table Size + * To map 4GB memory region with 2MB pages, there needs to be 1 page for P= ML4, + * 1 Page for PDPT, 4 pages for PD. Reserving 6 pages for PT. + */ +#define TDX_GUEST_NR_PT_PAGES (1 + 1 + 4) + +/* + * Predefined GDTR values. + */ +#define TDX_GUEST_GDTR_ADDR (TDX_GUEST_PT_FIXED_ADDR + (TDX_GUEST_NR_PT_PA= GES *\ + PAGE_SIZE)) +#define TDX_GUEST_GDTR_BASE (TDX_GUEST_GDTR_ADDR + PAGE_SIZE) +#define TDX_GUEST_LINEAR_CODE64_SEL 0x38 + +#define TDX_GUEST_STACK_NR_PAGES (3) +#define TDX_GUEST_STACK_BASE (TDX_GUEST_GDTR_BASE + (TDX_GUEST_STACK_NR_PA= GES *\ + PAGE_SIZE) - 1) +/* + * Reserving some pages to copy the test code. This is an arbitrary number= for + * now to simplify to guest image layout calculation. + * TODO: calculate the guest code dynamcially. + */ +#define TDX_GUEST_CODE_ENTRY (TDX_GUEST_GDTR_BASE + (TDX_GUEST_STACK_NR_PA= GES *\ + PAGE_SIZE)) + +#define KVM_MAX_CPUID_ENTRIES 256 + +/* + * TODO: Move page attributes to processor.h file. + */ +#define _PAGE_PRESENT (1UL<<0) /* is present */ +#define _PAGE_RW (1UL<<1) /* writeable */ +#define _PAGE_PS (1UL<<7) /* page size bit*/ + +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + +struct tdx_cpuid_data { + struct kvm_cpuid2 cpuid; + struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; +}; + +struct __packed tdx_gdtr { + uint16_t limit; + uint32_t base; +}; + +struct page_table { + uint64_t pml4[512]; + uint64_t pdpt[512]; + uint64_t pd[4][512]; +}; + +void add_td_memory(struct kvm_vm *vm, void *source_page, + uint64_t gpa, int size); +void finalize_td_memory(struct kvm_vm *vm); +void initialize_td(struct kvm_vm *vm); +void initialize_td_vcpu(struct kvm_vcpu *vcpu); +void prepare_source_image(struct kvm_vm *vm, void *guest_code, + size_t guest_code_size, + uint64_t guest_code_signature); + +#endif // KVM_LIB_TDX_H_ diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c b/tools/testi= ng/selftests/kvm/lib/x86_64/tdx_lib.c new file mode 100644 index 000000000000..72bf2ff24a29 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "asm/kvm.h" +#include "tdx.h" +#include +#include +#include "processor.h" +#include + +char *tdx_cmd_str[] =3D { + "KVM_TDX_CAPABILITIES", + "KVM_TDX_INIT_VM", + "KVM_TDX_INIT_VCPU", + "KVM_TDX_INIT_MEM_REGION", + "KVM_TDX_FINALIZE_VM" +}; + +#define TDX_MAX_CMD_STR (ARRAY_SIZE(tdx_cmd_str)) +#define EIGHT_INT3_INSTRUCTIONS 0xCCCCCCCCCCCCCCCC + +#define XFEATURE_LBR 15 +#define XFEATURE_XTILECFG 17 +#define XFEATURE_XTILEDATA 18 +#define XFEATURE_MASK_LBR (1 << XFEATURE_LBR) +#define XFEATURE_MASK_XTILECFG (1 << XFEATURE_XTILECFG) +#define XFEATURE_MASK_XTILEDATA (1 << XFEATURE_XTILEDATA) +#define XFEATURE_MASK_XTILE (XFEATURE_MASK_XTILECFG | XFEATURE_MASK_XTILED= ATA) + + +static void tdx_ioctl(int fd, int ioctl_no, uint32_t flags, void *data) +{ + struct kvm_tdx_cmd tdx_cmd; + int r; + + TEST_ASSERT(ioctl_no < TDX_MAX_CMD_STR, "Unknown TDX CMD : %d\n", + ioctl_no); + + memset(&tdx_cmd, 0x0, sizeof(tdx_cmd)); + tdx_cmd.id =3D ioctl_no; + tdx_cmd.flags =3D flags; + tdx_cmd.data =3D (uint64_t)data; + r =3D ioctl(fd, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd); + TEST_ASSERT(r =3D=3D 0, "%s failed: %d %d", tdx_cmd_str[ioctl_no], r, + errno); +} + +static struct tdx_cpuid_data get_tdx_cpuid_data(struct kvm_vm *vm) +{ + static struct tdx_cpuid_data cpuid_data; + int ret, i; + + if (cpuid_data.cpuid.nent) + return cpuid_data; + + memset(&cpuid_data, 0, sizeof(cpuid_data)); + cpuid_data.cpuid.nent =3D KVM_MAX_CPUID_ENTRIES; + ret =3D ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data); + if (ret) { + TEST_FAIL("KVM_GET_SUPPORTED_CPUID failed %d %d\n", + ret, errno); + cpuid_data.cpuid.nent =3D 0; + return cpuid_data; + } + + for (i =3D 0; i < KVM_MAX_CPUID_ENTRIES; i++) { + struct kvm_cpuid_entry2 *e =3D &cpuid_data.entries[i]; + + /* TDX doesn't support LBR and AMX features yet. + * Disable those bits from the XCR0 register. + */ + if (e->function =3D=3D 0xd && (e->index =3D=3D 0)) { + e->eax &=3D ~XFEATURE_MASK_LBR; + e->eax &=3D ~XFEATURE_MASK_XTILE; + } + } + + return cpuid_data; +} + +/* + * Initialize a VM as a TD. + * + */ +void initialize_td(struct kvm_vm *vm) +{ + struct tdx_cpuid_data cpuid_data; + int rc; + + /* No guest VMM controlled cpuid information yet. */ + struct kvm_tdx_init_vm init_vm; + + rc =3D kvm_check_cap(KVM_CAP_X2APIC_API); + TEST_ASSERT(rc, "TDX: KVM_CAP_X2APIC_API is not supported!"); + rc =3D kvm_check_cap(KVM_CAP_SPLIT_IRQCHIP); + TEST_ASSERT(rc, "TDX: KVM_CAP_SPLIT_IRQCHIP is not supported!"); + + vm_enable_cap(vm, KVM_CAP_X2APIC_API, + KVM_X2APIC_API_USE_32BIT_IDS | + KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK); + vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24); + + /* Allocate and setup memoryfor the td guest. */ + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + TDX_GUEST_PT_FIXED_ADDR, + 0, TDX_GUEST_MAX_NR_PAGES, 0); + + memset(&init_vm, 0, sizeof(init_vm)); + + cpuid_data =3D get_tdx_cpuid_data(vm); + + init_vm.max_vcpus =3D 1; + init_vm.attributes =3D 0; + memcpy(&init_vm.cpuid, &cpuid_data, sizeof(cpuid_data)); + tdx_ioctl(vm->fd, KVM_TDX_INIT_VM, 0, &init_vm); +} + + +void initialize_td_vcpu(struct kvm_vcpu *vcpu) +{ + struct tdx_cpuid_data cpuid_data; + + cpuid_data =3D get_tdx_cpuid_data(vcpu->vm); + vcpu_init_cpuid(vcpu, (struct kvm_cpuid2 *) &cpuid_data); + tdx_ioctl(vcpu->fd, KVM_TDX_INIT_VCPU, 0, NULL); +} + +void add_td_memory(struct kvm_vm *vm, void *source_pages, + uint64_t gpa, int size) +{ + struct kvm_tdx_init_mem_region mem_region =3D { + .source_addr =3D (uint64_t)source_pages, + .gpa =3D gpa, + .nr_pages =3D size / PAGE_SIZE, + }; + uint32_t metadata =3D KVM_TDX_MEASURE_MEMORY_REGION; + + TEST_ASSERT((mem_region.nr_pages > 0) && + ((mem_region.nr_pages * PAGE_SIZE) =3D=3D size), + "Cannot add partial pages to the guest memory.\n"); + TEST_ASSERT(((uint64_t)source_pages & (PAGE_SIZE - 1)) =3D=3D 0, + "Source memory buffer is not page aligned\n"); + tdx_ioctl(vm->fd, KVM_TDX_INIT_MEM_REGION, metadata, &mem_region); +} + +void finalize_td_memory(struct kvm_vm *vm) +{ + tdx_ioctl(vm->fd, KVM_TDX_FINALIZE_VM, 0, NULL); +} + +void build_gdtr_table(void *gdtr_target, void *gdt_target) +{ + uint64_t gdt_table[] =3D { + GDT_ENTRY(0, 0, 0), // NULL_SEL + GDT_ENTRY(0xc093, 0, 0xfffff), // LINEAR_DATA32_SEL + GDT_ENTRY(0xc09b, 0, 0xfffff), // LINEAR_CODE32_SEL + GDT_ENTRY(0, 0, 0), // NULL_SEL + GDT_ENTRY(0, 0, 0), // NULL_SEL + GDT_ENTRY(0, 0, 0), // NULL_SEL + GDT_ENTRY(0, 0, 0), // NULL_SEL + GDT_ENTRY(0xa09b, 0, 0xfffff) // LINEAR_CODE64_SEL + }; + + struct tdx_gdtr gdtr; + + gdtr.limit =3D sizeof(gdt_table) - 1; + gdtr.base =3D TDX_GUEST_GDTR_BASE; + + memcpy(gdt_target, gdt_table, sizeof(gdt_table)); + memcpy(gdtr_target, &gdtr, sizeof(gdtr)); +} + + +/* + * Constructing 1:1 mapping for the lowest 4GB address space using 2MB pag= es + * which will be used by the TDX guest when paging is enabled. + * TODO: use virt_pg_map() functions to dynamically allocate the page tabl= es. + */ +void build_page_tables(void *pt_target, uint64_t pml4_base_address) +{ + uint64_t i; + struct page_table *pt; + + pt =3D malloc(sizeof(struct page_table)); + TEST_ASSERT(pt !=3D NULL, "Could not allocate memory for page tables!\n"); + memset((void *) &(pt->pml4[0]), 0, sizeof(pt->pml4)); + memset((void *) &(pt->pdpt[0]), 0, sizeof(pt->pdpt)); + for (i =3D 0; i < 4; i++) + memset((void *) &(pt->pd[i][0]), 0, sizeof(pt->pd[i])); + + pt->pml4[0] =3D (pml4_base_address + PAGE_SIZE) | + _PAGE_PRESENT | _PAGE_RW; + for (i =3D 0; i < 4; i++) + pt->pdpt[i] =3D (pml4_base_address + (i + 2) * PAGE_SIZE) | + _PAGE_PRESENT | _PAGE_RW; + + uint64_t *pde =3D &(pt->pd[0][0]); + + for (i =3D 0; i < sizeof(pt->pd) / sizeof(pt->pd[0][0]); i++, pde++) + *pde =3D (i << 21) | _PAGE_PRESENT | _PAGE_RW | _PAGE_PS; + memcpy(pt_target, pt, 6 * PAGE_SIZE); +} + +static void +__attribute__((__flatten__, section("guest_boot_section"))) guest_boot(voi= d) +{ + asm volatile(" .code32\n\t;" + "main_32:\n\t;" + " cli\n\t;" + " movl $" __stringify(TDX_GUEST_STACK_BASE) ", %%esp\n\t;" + " movl $" __stringify(TDX_GUEST_GDTR_ADDR) ", %%eax\n\t;" + " lgdt (%%eax)\n\t;" + " movl $0x660, %%eax\n\t;" + " movl %%eax, %%cr4\n\t;" + " movl $" __stringify(TDX_GUEST_PT_FIXED_ADDR) ", %%eax\n\t;" + " movl %%eax, %%cr3\n\t;" + " movl $0x80000023, %%eax\n\t;" + " movl %%eax, %%cr0\n\t;" + " ljmp $" __stringify(TDX_GUEST_LINEAR_CODE64_SEL) + ", $" __stringify(TDX_GUEST_CODE_ENTRY) "\n\t;" + /* + * This is where the CPU will start running. + * Do not remove any int3 instruction below. + */ + "reset_vector:\n\t;" + " jmp main_32\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + " int3\n\t;" + ".code64\n\t" + :::"rax"); +} + +extern char *__start_guest_boot_section; +extern char *__stop_guest_boot_section; +#define GUEST_BOOT_SIZE ((uint64_t)&__stop_guest_boot_section -\ + (uint64_t)&__start_guest_boot_section) + +/* + * Copies the guest code to the guest image. If signature value is not 0, = it + * will verify that the guest code ends with the signature provided. We mi= ght + * need to check the signature to prevent compiler to add additional instr= uction + * to the end of the guest code which might create problems in some cases = ie + * when copying code for resetvector. + */ +void copy_guest_code(void *target, void *guest_function, size_t code_size, + uint64_t signature) +{ + uint64_t *end; + + TEST_ASSERT((target !=3D NULL) && (guest_function !=3D NULL) && + (code_size > 0), "Invalid inputs to copy guest code\n"); + if (signature) { + while (code_size >=3D sizeof(signature)) { + end =3D guest_function + code_size - sizeof(signature); + if (*end =3D=3D signature) + break; + /* Trimming the unwanted code at the end added by + * compiler. We need to add nop instruction to the + * begginning of the buffer to make sure that the guest + * code is aligned from the bottom and top as expected + * based on the original code size. This is important + * for reset vector which is copied to the bottom of + * the first 4GB memory. + */ + code_size--; + *(unsigned char *)target =3D 0x90; + target++; + } + TEST_ASSERT(code_size >=3D sizeof(signature), + "Guest code does not end with the signature: %lx\n" + , signature); + } + + memcpy(target, guest_function, code_size); +} + +void prepare_source_image(struct kvm_vm *vm, void *guest_code, + size_t guest_code_size, uint64_t guest_code_signature) +{ + void *source_mem, *pt_address, *code_address, *gdtr_address, + *gdt_address, *guest_code_base; + int number_of_pages; + + number_of_pages =3D (GUEST_BOOT_SIZE + guest_code_size) / PAGE_SIZE + 1 + + TDX_GUEST_NR_PT_PAGES + TDX_GUEST_STACK_NR_PAGES; + TEST_ASSERT(number_of_pages < TDX_GUEST_MAX_NR_PAGES, + "Initial image does not fit to the memory"); + + source_mem =3D memalign(PAGE_SIZE, + (TDX_GUEST_MAX_NR_PAGES * PAGE_SIZE)); + TEST_ASSERT(source_mem !=3D NULL, + "Could not allocate memory for guest image\n"); + + pt_address =3D source_mem; + gdtr_address =3D source_mem + (TDX_GUEST_NR_PT_PAGES * PAGE_SIZE); + gdt_address =3D gdtr_address + PAGE_SIZE; + code_address =3D source_mem + (TDX_GUEST_MAX_NR_PAGES * PAGE_SIZE) - + GUEST_BOOT_SIZE; + guest_code_base =3D gdt_address + (TDX_GUEST_STACK_NR_PAGES * + PAGE_SIZE); + + build_page_tables(pt_address, TDX_GUEST_PT_FIXED_ADDR); + build_gdtr_table(gdtr_address, gdt_address); + + /* reset vector code should end with int3 instructions. + * The unused bytes at the reset vector with int3 to trigger triple + * fault shutdown if the guest manages to get into the unused code. + * Using the last 8 int3 instruction as a signature to find the function + * end offset for guest boot code that includes the instructions for + * reset vector. + * TODO: Using signature to find the exact size is a little strange but + * compiler might add additional bytes to the end of the function which + * makes it hard to calculate the offset addresses correctly. + * Alternatively, we can construct the jmp instruction for the reset + * vector manually to prevent any offset mismatch when copying the + * compiler generated code. + */ + copy_guest_code(code_address, guest_boot, GUEST_BOOT_SIZE, + EIGHT_INT3_INSTRUCTIONS); + if (guest_code) + copy_guest_code(guest_code_base, guest_code, guest_code_size, + guest_code_signature); + + add_td_memory(vm, source_mem, TDX_GUEST_PT_FIXED_ADDR, + (TDX_GUEST_MAX_NR_PAGES * PAGE_SIZE)); + free(source_mem); +} --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE5DBECAAA1 for ; Tue, 30 Aug 2022 22:20:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231790AbiH3WUd (ORCPT ); Tue, 30 Aug 2022 18:20:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51912 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231776AbiH3WUN (ORCPT ); Tue, 30 Aug 2022 18:20:13 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21BF1220E1 for ; Tue, 30 Aug 2022 15:20:11 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id r13-20020a17090a454d00b001f04dfc6195so5412140pjm.2 for ; Tue, 30 Aug 2022 15:20:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=T9yOZxwNH1Vwea4FbMMjM8N2gmoqmFgTmVLKZvXCyGw=; b=eOlvFAgZHsItzGfjv1tWpFsZXrOJO22R3iWXR8OZBM91PKIkAjTfnCHMDNUvt+SdhZ Bm6lmB7UOemd4FkIOLnGeMo6bCoB6YH2EvQJiroRFzf8w0AfjL8GSBHSQDD1a7Q084dB 2LHamFKzMB7cIe94d4EsxfRHbl0zxq7TTcNYGFq2r2o5TJWSQkMVnMxPxEuoPYgKpCQ9 ST35fHZqFlS03jmaCfdmYLlJJchkR4S+iPX+2JSVH2IKBkdMPPod97mx5tS3rgEWa3kd GY08Y4z9mbP5elCtcrPjQPNzQbKoZsjDT0/qh7F5wRv2WKNtye4tdGj/3cp0R0E+iedR 00Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=T9yOZxwNH1Vwea4FbMMjM8N2gmoqmFgTmVLKZvXCyGw=; b=ukPRkdXSjvHFV2NVNHilJGDDnWJuCWkOjdJUFZHdqkNBwWvw78gqe9KTw3/Tp69CGR EOZKXS/5z6eO/ZdRJ0DUv6GgRHnborNTre6rnT/NZpXFMWdeuYFpsjm8YRaP9H3dXNsP VsQI0fLu4jmYGG+0Myzkf4Cl3iaQTb3Eiqa1CKUVVRGmsbSKYgKdVacMYM3WAz8ec328 myy3FYsloj6K7MhexrCuHUK6gIiIr7kCEiRgYkKdwQeOG7iqh8YshPIoLKX5/4j7yq6w h+j/Wp+rmqFFUDQ8esrBP79olCWbR3cHU/5i1tYeR3lWLZNS8r/V6gDjgkLw4Fy9hpvi vaKA== X-Gm-Message-State: ACgBeo16aC5sBNTIO8XIMYPGYe8it5ajaLCK04Wl2CZBlPSOzjhntdip yvAoxHybHzDmdJXKaN4J4vE8Hj+mZQ== X-Google-Smtp-Source: AA6agR49dftSu7HryzIxwzZ7zqElJ1O/VcP3iP5eNArJd97RI7PeT9sdyt8bgBBm02Y5j1XhYfDwyGnqGA== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a63:fb56:0:b0:429:983f:b91e with SMTP id w22-20020a63fb56000000b00429983fb91emr19753498pgj.399.1661898010578; Tue, 30 Aug 2022 15:20:10 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:46 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-4-sagis@google.com> Subject: [RFC PATCH v2 03/17] KVM: selftest: Adding TDX life cycle test. From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Erdem Aktas Adding a test to verify TDX lifecycle by creating a TD and running a dummy TDVMCALL inside it. Signed-off-by: Erdem Aktas Signed-off-by: Sagi Shahar Signed-off-by: Ryan Afranji --- tools/testing/selftests/kvm/Makefile | 1 + tools/testing/selftests/kvm/lib/x86_64/tdx.h | 149 ++++++++++++++++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 104 ++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index ad4d60dadc06..208e0cc30048 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -140,6 +140,7 @@ TEST_GEN_PROGS_x86_64 +=3D set_memory_region_test TEST_GEN_PROGS_x86_64 +=3D steal_time TEST_GEN_PROGS_x86_64 +=3D kvm_binary_stats_test TEST_GEN_PROGS_x86_64 +=3D system_counter_offset_test +TEST_GEN_PROGS_x86_64 +=3D x86_64/tdx_vm_tests =20 # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86_64 +=3D x86_64/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 61b997dfc420..d5de52657112 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -51,6 +51,12 @@ #define _PAGE_RW (1UL<<1) /* writeable */ #define _PAGE_PS (1UL<<7) /* page size bit*/ =20 +#define TDX_INSTRUCTION_IO 30 + +#define TDX_SUCCESS_PORT 0x30 +#define TDX_IO_READ 0 +#define TDX_IO_WRITE 1 + #define GDT_ENTRY(flags, base, limit) \ ((((base) & 0xff000000ULL) << (56-24)) | \ (((flags) & 0x0000f0ffULL) << 40) | \ @@ -83,4 +89,147 @@ void prepare_source_image(struct kvm_vm *vm, void *gues= t_code, size_t guest_code_size, uint64_t guest_code_signature); =20 +/* + * Generic TDCALL function that can be used to communicate with TDX module= or + * VMM. + * Input operands: rax, rbx, rcx, rdx, r8-r15, rbp, rsi, rdi + * Output operands: rax, r8-r15, rbx, rdx, rdi, rsi + * rcx is actually a bitmap to tell TDX module which register values will = be + * exposed to the VMM. + * XMM0-XMM15 registers can be used as input operands but the current + * implementation does not support it yet. + */ +static inline void tdcall(struct kvm_regs *regs) +{ + asm volatile ( + "mov %13, %%rax;\n\t" + "mov %14, %%rbx;\n\t" + "mov %15, %%rcx;\n\t" + "mov %16, %%rdx;\n\t" + "mov %17, %%r8;\n\t" + "mov %18, %%r9;\n\t" + "mov %19, %%r10;\n\t" + "mov %20, %%r11;\n\t" + "mov %21, %%r12;\n\t" + "mov %22, %%r13;\n\t" + "mov %23, %%r14;\n\t" + "mov %24, %%r15;\n\t" + "mov %25, %%rbp;\n\t" + "mov %26, %%rsi;\n\t" + "mov %27, %%rdi;\n\t" + ".byte 0x66, 0x0F, 0x01, 0xCC;\n\t" + "mov %%rax, %0;\n\t" + "mov %%rbx, %1;\n\t" + "mov %%rdx, %2;\n\t" + "mov %%r8, %3;\n\t" + "mov %%r9, %4;\n\t" + "mov %%r10, %5;\n\t" + "mov %%r11, %6;\n\t" + "mov %%r12, %7;\n\t" + "mov %%r13, %8;\n\t" + "mov %%r14, %9;\n\t" + "mov %%r15, %10;\n\t" + "mov %%rsi, %11;\n\t" + "mov %%rdi, %12;\n\t" + : "=3Dm" (regs->rax), "=3Dm" (regs->rbx), "=3Dm" (regs->rdx), + "=3Dm" (regs->r8), "=3Dm" (regs->r9), "=3Dm" (regs->r10), + "=3Dm" (regs->r11), "=3Dm" (regs->r12), "=3Dm" (regs->r13), + "=3Dm" (regs->r14), "=3Dm" (regs->r15), "=3Dm" (regs->rsi), + "=3Dm" (regs->rdi) + : "m" (regs->rax), "m" (regs->rbx), "m" (regs->rcx), + "m" (regs->rdx), "m" (regs->r8), "m" (regs->r9), + "m" (regs->r10), "m" (regs->r11), "m" (regs->r12), + "m" (regs->r13), "m" (regs->r14), "m" (regs->r15), + "m" (regs->rbp), "m" (regs->rsi), "m" (regs->rdi) + : "rax", "rbx", "rcx", "rdx", "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", "rbp", "rsi", "rdi"); +} + + +/* + * Do a TDVMCALL IO request + * + * Input Args: + * port - IO port to do read/write + * size - Number of bytes to read/write. 1=3D1byte, 2=3D2bytes, 4=3D4byte= s. + * write - 1=3DIO write 0=3DIO read + * data - pointer for the data to write + * + * Output Args: + * data - pointer for data to be read + * + * Return: + * On success, return 0. For Invalid-IO-Port error, returns -1. + * + * Does an IO operation using the following tdvmcall interface. + * + * TDG.VP.VMCALL-Input Operands + * R11 30 for IO + * + * R12 Size of access. 1=3D1byte, 2=3D2bytes, 4=3D4bytes. + * R13 Direction. 0=3DRead, 1=3DWrite. + * R14 Port number + * R15 Data to write, if R13 is 1. + * + * TDG.VP.VMCALL-Output Operands + * R10 TDG.VP.VMCALL-return code. + * R11 Data to read, if R13 is 0. + * + * TDG.VP.VMCALL-Status Codes + * Error Code Value Description + * TDG.VP.VMCALL_SUCCESS 0x0 TDG.VP.VMCALL is successful + * TDG.VP.VMCALL_INVALID_OPERAND 0x80000000 00000000 Invalid-IO-Port access + */ +static inline uint64_t tdvmcall_io(uint64_t port, uint64_t size, + uint64_t write, uint64_t *data) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_IO; + regs.r12 =3D size; + regs.r13 =3D write; + regs.r14 =3D port; + if (write) { + regs.r15 =3D *data; + regs.rcx =3D 0xFC00; + } else { + regs.rcx =3D 0x7C00; + } + tdcall(®s); + if (!write) + *data =3D regs.r11; + return regs.r10; +} + +/* + * Report test success to user space. + */ +static inline void tdvmcall_success(void) +{ + uint64_t code =3D 0; + + tdvmcall_io(TDX_SUCCESS_PORT, /*size=3D*/4, TDX_IO_WRITE, &code); +} + + +#define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\ + (uint64_t)&__start_sec_ ## name) \ + +#define TDX_GUEST_FUNCTION__(name, section_name) \ +extern char *__start_sec_ ## name ; \ +extern char *__stop_sec_ ## name ; \ +static void \ +__attribute__((__flatten__, section(section_name))) name(void *arg) + + +#define STRINGIFY2(x) #x +#define STRINGIFY(x) STRINGIFY2(x) +#define CONCAT2(a, b) a##b +#define CONCAT(a, b) CONCAT2(a, b) + + +#define TDX_GUEST_FUNCTION(name) \ +TDX_GUEST_FUNCTION__(name, STRINGIFY(CONCAT(sec_, name))) + #endif // KVM_LIB_TDX_H_ diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c new file mode 100644 index 000000000000..590e45aa7570 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include "../lib/x86_64/tdx.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHECK_GUEST_COMPLETION(VCPU) \ + (TEST_ASSERT( \ + ((VCPU)->run->exit_reason =3D=3D KVM_EXIT_IO) && \ + ((VCPU)->run->io.port =3D=3D TDX_SUCCESS_PORT) && \ + ((VCPU)->run->io.size =3D=3D 4) && \ + ((VCPU)->run->io.direction =3D=3D TDX_IO_WRITE), \ + "Unexpected exit values while waiting for test complition: %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)) + +/* + * There might be multiple tests we are running and if one test fails, it = will + * prevent the subsequent tests to run due to how tests are failing with + * TEST_ASSERT function. The run_in_new_process function will run a test i= n a + * new process context and wait for it to finish or fail to prevent TEST_A= SSERT + * to kill the main testing process. + */ +void run_in_new_process(void (*func)(void)) +{ + if (fork() =3D=3D 0) { + func(); + exit(0); + } + wait(NULL); +} + +/* + * Verify that the TDX is supported by the KVM. + */ +bool is_tdx_enabled(void) +{ + return !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM)); +} + +/* + * Do a dummy io exit to verify that the TD has been initialized correctly= and + * guest can run some code inside. + */ +TDX_GUEST_FUNCTION(guest_dummy_exit) +{ + tdvmcall_success(); +} + +/* + * TD lifecycle test will create a TD which runs a dumy IO exit to verify = that + * the guest TD has been created correctly. + */ +void verify_td_lifecycle(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + printf("Verifying TD lifecycle:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_dummy_exit, + TDX_FUNCTION_SIZE(guest_dummy_exit), 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + 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(&verify_td_lifecycle); + + return 0; +} --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19714ECAAD5 for ; Tue, 30 Aug 2022 22:20:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231776AbiH3WUk (ORCPT ); Tue, 30 Aug 2022 18:20:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231954AbiH3WUP (ORCPT ); Tue, 30 Aug 2022 18:20:15 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F31B2B27D for ; Tue, 30 Aug 2022 15:20:12 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id s13-20020a056a00194d00b005385093da2dso2905877pfk.13 for ; Tue, 30 Aug 2022 15:20:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=4HErFRuZWnvNea+crcpmX3JHa78L1TL3m4q9Khg/Jh4=; b=cDKvhJ6cjRi3/088MY6el/echJAjDXJyz87g+GLLGuxePVe7haWbP1mmqlJRdw8xAB ulPMlNP0Q84T5Whq/9d+LuwLsemViGiwbEZFwfvEv7jcTxYt6r549vumV8rRze0ajjo6 d66T4t3NqHaks1m7FwWmV+1aiUaKk+ZYCXeqXCBkDUzjO/DzHndVZKBaFBuDVEIbyKAT +pqk6gIdjXXXURpds3lOB/jPE9lqkusocO7BoFTelzCFxjeBoxSJSivWVYBTXlW3Xyqf eLc4OIWy3ajLwJAp+lyZdNq2em2r6Trqbg3vHRH1SsE4qlQRPmf522lj1lt+dPy3LkTG NL/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=4HErFRuZWnvNea+crcpmX3JHa78L1TL3m4q9Khg/Jh4=; b=ffzLAfPq/ATamHsikEzZ4690srp3LULyj5z/CfkRQbJ8yvKy1QuIu0bQlAc7SMBteC vfn6WNQwW062ng7vhKnrjwLR+KSR1MyJu2bkUyc0oszHX4B1jYckh1B50RGdd3G5Qpvq OcGkh3KvbmsNETnj+RwKSKg3jZkwKyiJKrjj7hE6L1AXZ4nOM2WoPGaxsFXOFH5mlWst 8qCyrWViP4vKoeEYCRwfJS69hQiVL+0JefTw6bxwNcIurQ8HJpvREEOIyE3+n4OHNZob g5kfRUz5ThHu5bN6YSf0kp8dGUveO+ZljVyuM0O/dgxDEGvS34A9uhNeyr8LnsXkpgaY JApw== X-Gm-Message-State: ACgBeo2UhXy5DIpV2/fWMgGQzxPw2+TALG/O8YSjN1bJBHBR0MP0/CHj iwviDQGhANcTQRcrV9YoV5iNvtioGQ== X-Google-Smtp-Source: AA6agR5PbnmN6dYRh+nCwvlvex+8uK7KW+7p/GMZAdg4ZLuyXW4YoUw+I5NpPIWIM/6fxg2v1OZsZWYjvA== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:b8b:b0:536:71f7:4ce3 with SMTP id g11-20020a056a000b8b00b0053671f74ce3mr23113027pfj.74.1661898012331; Tue, 30 Aug 2022 15:20:12 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:47 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-5-sagis@google.com> Subject: [RFC PATCH v2 04/17] KVM: selftest: TDX: Add report_fatal_error test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test checks report_fatal_error functionality. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 17 ++++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 55 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index d5de52657112..351ece3e80e2 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -51,6 +51,7 @@ #define _PAGE_RW (1UL<<1) /* writeable */ #define _PAGE_PS (1UL<<7) /* page size bit*/ =20 +#define TDX_REPORT_FATAL_ERROR 0x10003 #define TDX_INSTRUCTION_IO 30 =20 #define TDX_SUCCESS_PORT 0x30 @@ -212,6 +213,22 @@ static inline void tdvmcall_success(void) tdvmcall_io(TDX_SUCCESS_PORT, /*size=3D*/4, TDX_IO_WRITE, &code); } =20 +/* + * Report an error to user space. + * data_gpa may point to an optional shared guest memory holding the error= string. + * Return value from tdvmcall is ignored since execution is not expected to + * continue beyond this point. + */ +static inline void tdvmcall_fatal(uint64_t error_code) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_REPORT_FATAL_ERROR; + regs.r12 =3D error_code; + regs.rcx =3D 0x1C00; + tdcall(®s); +} =20 #define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\ (uint64_t)&__start_sec_ ## name) \ diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 590e45aa7570..1db5400ca5ef 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -91,6 +91,60 @@ void verify_td_lifecycle(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies TDX_REPORT_FATAL_ERROR functionality. + */ +TDX_GUEST_FUNCTION(guest_code_report_fatal_error) +{ + uint64_t err; + /* Note: err should follow the GHCI spec definition: + * bits 31:0 should be set to 0. + * bits 62:32 are used for TD-specific extended error code. + * bit 63 is used to mark additional information in shared memory. + */ + err =3D 0x0BAAAAAD00000000; + + if (err) + tdvmcall_fatal(err); + + tdvmcall_success(); +} + +void verify_report_fatal_error(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + printf("Verifying report_fatal_error:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_code_report_fatal_error, + TDX_FUNCTION_SIZE(guest_code_report_fatal_error), + 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_SYSTEM_EVENT); + ASSERT_EQ(vcpu->run->system_event.ndata, 3); + ASSERT_EQ(vcpu->run->system_event.data[0], TDX_REPORT_FATAL_ERROR); + ASSERT_EQ(vcpu->run->system_event.data[1], 0x0BAAAAAD00000000); + ASSERT_EQ(vcpu->run->system_event.data[2], 0); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -99,6 +153,7 @@ int main(int argc, char **argv) } =20 run_in_new_process(&verify_td_lifecycle); + run_in_new_process(&verify_report_fatal_error); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CEB2DC0502A for ; Tue, 30 Aug 2022 22:20:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231402AbiH3WUr (ORCPT ); Tue, 30 Aug 2022 18:20:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52392 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231965AbiH3WUR (ORCPT ); Tue, 30 Aug 2022 18:20:17 -0400 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 4A4712E9DE for ; Tue, 30 Aug 2022 15:20:15 -0700 (PDT) Received: by mail-pl1-x649.google.com with SMTP id n1-20020a170902d2c100b0017520dd4a0eso1724605plc.8 for ; Tue, 30 Aug 2022 15:20:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=t1EJEc3ehuP8VgtxlwMAMy4e8zFNWLY0+qkN4qZlgjo=; b=OBDHMiVsduqJn82HBATnhpkGshEMFhpVZd04lCP+8vCRmGXewLCmigJbYMcHR2G1Wg +1Jp0anvPji+d03Qe1im6ULPefCWNZxTRGuYy1fmOcQDpL+aa60iN43yHrmxPsTe47Lz n0ZFXEzIqvp6UzBWc088o439BDnM4TCo/tLCOgVz8zadA67XwGMERiEPcIyK+BRZpsLi AxREiplpSLOHm7UHaBzpEo0sw0HIKQ3Gsv1eW/xGP6Tf9RDyUF55ezGrN/oO204ZnPif E2kdK9vpGN5AC9zHWegVB8elrEBJDwd6bK7V8/y9BJ0ywKUFP2pPlVZ3S8T9TdzVsk5M Ol8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=t1EJEc3ehuP8VgtxlwMAMy4e8zFNWLY0+qkN4qZlgjo=; b=34PHLdqf72TzlqUH4a/HzF3rQZK7rGs6QPsSBcVJXmUOv7tEw0bpFynLZ4XsQMUbeB arl46+aXVwY3g+xTh6W6LVpX7b1tn/w3QRlqFjSINqV727O9mX0vTPWEULjv8occKwoi VpZEg+rOYICiB7Okjdg+JIWFl2c7kaB0v/3TbiczdOFQIs9fUToBE0YTMFZjRueJOd0r LV/anZKy9eKjPpra5fjA8R7NudQin1MFL+sWn1yoCcNnO1kD4JnACwbimZ6iuTnVO0y/ iJZTTETyRr2W+HXyzllimhjcAmRAnpqSC9hDRT2W/1lFXeaqX2fDMUKN0f8OtSS8Kn9r 6VAA== X-Gm-Message-State: ACgBeo3zTFi2g0hHKUWkPdsPNI056IqKJ8rrT23BpapnjLuSkIGZxHLp d7p3nU3wMgaUECKAYsehCz5IbHmn2w== X-Google-Smtp-Source: AA6agR5cOKhbp+QG6nKAHLfE4O20IypU//wy/qm51Rv1hI/FjyPUOXD4nlx1Iu9RD3DCdgvkY7550GjkVg== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:1a89:b0:536:5dca:a673 with SMTP id e9-20020a056a001a8900b005365dcaa673mr23237123pfv.71.1661898014056; Tue, 30 Aug 2022 15:20:14 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:48 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-6-sagis@google.com> Subject: [RFC PATCH v2 05/17] KVM: selftest: Adding test case for TDX port IO From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Erdem Aktas Verifies TDVMCALL READ and WRITE operations. Signed-off-by: Erdem Aktas Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 1 + .../selftests/kvm/x86_64/tdx_vm_tests.c | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 351ece3e80e2..c78dba1af14f 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -55,6 +55,7 @@ #define TDX_INSTRUCTION_IO 30 =20 #define TDX_SUCCESS_PORT 0x30 +#define TDX_TEST_PORT 0x31 #define TDX_IO_READ 0 #define TDX_IO_WRITE 1 =20 diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 1db5400ca5ef..a93629cfd13f 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -27,6 +27,32 @@ (VCPU)->run->exit_reason, exit_reason_str((VCPU)->run->exit_reason), \ (VCPU)->run->io.port, (VCPU)->run->io.size, (VCPU)->run->io.direction)) =20 +#define CHECK_IO(VCPU, PORT, SIZE, DIR) \ + do { \ + 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 (DIR)), \ + "Got an 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) + +#define CHECK_GUEST_FAILURE(VCPU) \ + do { \ + 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[1], \ + (VCPU)->run->system_event.data[1]); \ + } while (0) + /* * There might be multiple tests we are running and if one test fails, it = will * prevent the subsequent tests to run due to how tests are failing with @@ -145,6 +171,87 @@ void verify_report_fatal_error(void) printf("\t ... PASSED\n"); } =20 +/* + * 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 + */ +TDX_GUEST_FUNCTION(guest_io_exit) +{ + uint64_t data_out, data_in, delta; + uint64_t ret; + + data_out =3D 0xAB; + + ret =3D tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_WRITE, &data_out); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_READ, &data_in); + if (ret) + tdvmcall_fatal(ret); + + delta =3D data_in - data_out; + if (delta !=3D 1) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void verify_td_ioexit(void) +{ + struct kvm_vcpu *vcpu; + uint32_t port_data; + struct kvm_vm *vm; + + printf("Verifying TD IO Exit:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_io_exit, + TDX_FUNCTION_SIZE(guest_io_exit), 0); + finalize_td_memory(vm); + + /* Wait for guest to do a IO write */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 1, TDX_IO_WRITE); + port_data =3D *(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 previos written data + * + 1 back to the guest + */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 1, TDX_IO_READ); + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) =3D 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. + */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + printf("\t ... IO verify read/write values: OK\n"); + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -154,6 +261,7 @@ int main(int argc, char **argv) =20 run_in_new_process(&verify_td_lifecycle); run_in_new_process(&verify_report_fatal_error); + run_in_new_process(&verify_td_ioexit); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35637ECAAD4 for ; Tue, 30 Aug 2022 22:20:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232257AbiH3WUw (ORCPT ); Tue, 30 Aug 2022 18:20:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232021AbiH3WUX (ORCPT ); Tue, 30 Aug 2022 18:20:23 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D9B4140E03 for ; Tue, 30 Aug 2022 15:20:17 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id i1-20020a170902cf0100b001730caeec78so8655617plg.7 for ; Tue, 30 Aug 2022 15:20:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=sMSKVgYi+NQVBY9S65ltrEDvFSNwWuSwBWyaYR7CUj4=; b=OJS0Nn/GPz/gpL1O+Y6+R1pzOQuvLM9Zfw1WHuhf1AmdkfMk9ofK2yVxApO6yyyCmm 9PUADX4nZ9qN6FCMXondDy/69esGmzAqfLt1PIfqSOLlQ8frQ1rDlqVZTAiKJsaI7Z4C Bg1ek3U/Nwupy+YXNHJ4Y6sejApfs94fxiU6b104D8s8GuC/iO9Taa0iQaUVumtoqf6j Jyqa5QteTfvPIE0VQDpoidenyc72nKGaP4+wbnDRZTz0t49pI7GZFvfzDbD5SWyr08Qb oKRRHzZMm55T0d69G1REstnG0jd4lwpfacsIIjTVjuDa7SyCRV08BQVd7l8eWQ88LFKg 8j3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=sMSKVgYi+NQVBY9S65ltrEDvFSNwWuSwBWyaYR7CUj4=; b=h04Gb6bTGLWWi0+V1i0U7SoOM4We05syQZL7pciUSeiXF+TVWXr0QWvXPJsG9FsoXi geHKN0xXJiHMwVyvSLChJsuWiLcRqbNdcuT5jlIZLPMD2rf/y2MP+JFggDpjsqtgkwJi eOwfJsNgcSXW/NkoqckXTW0vO0Q/0mlyPj3Lq5NJlPz8Lw4QiKEkn9BYBWeLA4S61RrF lzz/32qd5+bpYMSWC8gJZnK4QChEdwaIuajSQrgrgw1eau5n65WbjGMi/q8qG763ZKEV FfZp3f6Dcm193UY7RWb2UIybjUaGKWGm7pDxiuWkVCRHIlj371WJPABx2Z8wkdo4OE25 6ArQ== X-Gm-Message-State: ACgBeo0y6VDAZUP3vAJNixXibia23MLD9FtCRvBe97I2e6urllFDgND4 TzVMWoUFOEzhh/gOzWarAPtO+iSPJA== X-Google-Smtp-Source: AA6agR67quWcW4kBcXZag7XBF+W0FktEv/vP+E2ojRFsmYh9WrvWOPXiyQxu5VZVsCvqrZ5OVKvXx7OH4w== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:90a:249:b0:1e0:a8a3:3c6c with SMTP id t9-20020a17090a024900b001e0a8a33c6cmr1010pje.0.1661898015842; Tue, 30 Aug 2022 15:20:15 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:49 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-7-sagis@google.com> Subject: [RFC PATCH v2 06/17] KVM: selftest: TDX: Add basic TDX CPUID test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test reads CPUID values from inside a TD VM and compare them to expected values. The test targets CPUID values which are virtualized as "As Configured", "As Configured (if Native)", "Calculated", "Fixed" and "Native" according to the TDX spec. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 13 ++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 132 ++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index c78dba1af14f..a28d15417d3e 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -56,6 +56,7 @@ =20 #define TDX_SUCCESS_PORT 0x30 #define TDX_TEST_PORT 0x31 +#define TDX_DATA_REPORT_PORT 0x32 #define TDX_IO_READ 0 #define TDX_IO_WRITE 1 =20 @@ -231,6 +232,18 @@ static inline void tdvmcall_fatal(uint64_t error_code) tdcall(®s); } =20 +/* + * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. + * Data is reported on port TDX_DATA_REPORT_PORT. + */ +static inline uint64_t tdvm_report_to_user_space(uint32_t data) +{ + // Need to upcast data to match tdvmcall_io signature. + uint64_t data_64 =3D data; + + return tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=3D*/4, TDX_IO_WRITE, &dat= a_64); +} + #define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\ (uint64_t)&__start_sec_ ## name) \ =20 diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index a93629cfd13f..3f51f936ea5a 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -77,6 +77,27 @@ bool is_tdx_enabled(void) return !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM)); } =20 +/* + * Find a specific CPUID entry. + */ +static struct kvm_cpuid_entry2 * +find_cpuid_entry(struct tdx_cpuid_data cpuid_data, uint32_t function, + uint32_t index) +{ + struct kvm_cpuid_entry2 *e; + int i; + + for (i =3D 0; i < cpuid_data.cpuid.nent; i++) { + e =3D &cpuid_data.entries[i]; + + if (e->function =3D=3D function && + (e->index =3D=3D index || + !(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX))) + return e; + } + return NULL; +} + /* * Do a dummy io exit to verify that the TD has been initialized correctly= and * guest can run some code inside. @@ -251,6 +272,116 @@ void verify_td_ioexit(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies CPUID functionality by reading CPUID values in guest. The guest + * will then send the values to userspace using an IO write to be checked + * against the expected values. + */ +TDX_GUEST_FUNCTION(guest_code_cpuid) +{ + uint64_t err; + uint32_t eax, ebx, edx, ecx; + + // Read CPUID leaf 0x1. + cpuid(1, &eax, &ebx, &ecx, &edx); + + err =3D tdvm_report_to_user_space(ebx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_to_user_space(ecx); + if (err) + tdvmcall_fatal(err); + + tdvmcall_success(); +} + +void verify_td_cpuid(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint32_t ebx, ecx; + struct kvm_cpuid_entry2 *cpuid_entry; + struct tdx_cpuid_data cpuid_data; + uint32_t guest_clflush_line_size; + uint32_t guest_max_addressable_ids, host_max_addressable_ids; + uint32_t guest_sse3_enabled; + uint32_t guest_fma_enabled; + uint32_t guest_initial_apic_id; + int ret; + + printf("Verifying TD CPUID:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_code_cpuid, + TDX_FUNCTION_SIZE(guest_code_cpuid), 0); + finalize_td_memory(vm); + + /* Wait for guest to report ebx value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + ebx =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + /* Wait for guest to report either ecx value or error */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + ecx =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + /* Wait for guest to complete execution */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + /* Verify the CPUID values we got from the guest. */ + printf("\t ... Verifying CPUID values from guest\n"); + + /* Get KVM CPUIDs for reference */ + memset(&cpuid_data, 0, sizeof(cpuid_data)); + cpuid_data.cpuid.nent =3D KVM_MAX_CPUID_ENTRIES; + ret =3D ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data); + TEST_ASSERT(!ret, "KVM_GET_SUPPORTED_CPUID failed\n"); + cpuid_entry =3D find_cpuid_entry(cpuid_data, 1, 0); + TEST_ASSERT(cpuid_entry, "CPUID entry missing\n"); + + host_max_addressable_ids =3D (cpuid_entry->ebx >> 16) & 0xFF; + + guest_sse3_enabled =3D ecx & 0x1; // Native + guest_clflush_line_size =3D (ebx >> 8) & 0xFF; // Fixed + guest_max_addressable_ids =3D (ebx >> 16) & 0xFF; // As Configured + guest_fma_enabled =3D (ecx >> 12) & 0x1; // As Configured (if Native) + guest_initial_apic_id =3D (ebx >> 24) & 0xFF; // Calculated + + ASSERT_EQ(guest_sse3_enabled, 1); + ASSERT_EQ(guest_clflush_line_size, 8); + ASSERT_EQ(guest_max_addressable_ids, host_max_addressable_ids); + + /* TODO: This only tests the native value. To properly test + * "As Configured (if Native)" we need to override this value + * in the TD params + */ + ASSERT_EQ(guest_fma_enabled, 1); + + /* TODO: guest_initial_apic_id is calculated based on the number of + * VCPUs in the TD. From the spec: "Virtual CPU index, starting from 0 + * and allocated sequentially on each successful TDH.VP.INIT" + * To test non-trivial values we either need a TD with multiple VCPUs + * or to pick a different calculated value. + */ + ASSERT_EQ(guest_initial_apic_id, 0); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} =20 int main(int argc, char **argv) { @@ -262,6 +393,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); + run_in_new_process(&verify_td_cpuid); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 30E73ECAAD4 for ; Tue, 30 Aug 2022 22:20:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232103AbiH3WUz (ORCPT ); Tue, 30 Aug 2022 18:20:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52942 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232037AbiH3WUX (ORCPT ); Tue, 30 Aug 2022 18:20:23 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E7AD45F57 for ; Tue, 30 Aug 2022 15:20:18 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id oo12-20020a17090b1c8c00b001faa0b549caso11850493pjb.0 for ; Tue, 30 Aug 2022 15:20:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=xND6YprCPZaQfpHo5dST5YbROtuGVFjyk8gKa/6IPBk=; b=ihbMRkP6LsisdZGdDSPBzStuAZmKk3JB59/cYAJtuNTJ2cOdmKtcPsX+9Y9WE4rfpv vgYOKUHpBCwMSlmOerTzfPv4fmUL5At8WQduTf4NtNmYGZpLCyywSQT2Jp+kN6E8uNFV EepkBJ87b4P1IjxdGwbI8BmSnztidDFGgOjsb3LHMBcm9aLfFXt4aSLsE1EilcD7ap5L FTag25ZySHcLIEbgXeHAbmEH2+sO7GmRffsS1/3sNPa7ZllFLqwWJLu8R+ruByRZ4B/V sI3Iieu3p0jj3Y7Rzw4Shshnx2WugrYTDfqwQXnZ6EnaEFapcLFdgAqTEPg6sxK/DduH qkxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=xND6YprCPZaQfpHo5dST5YbROtuGVFjyk8gKa/6IPBk=; b=JIxaz1U3/VIcW7KxKFtSsaXos8h79CjMb96xPrusGxYznyU/xU5s1TfdKczv/AcjSM NxytM13OeX1wpOA3DL94+0zjWm8JpJcGyOXRXfIn47IqNwBGuJ70mH7XP8ofj6db0eqh gTl6FD4LFsDpPpaGwhZRMN3NBi+e0W6jAPvsLFv1FvxIZdoJyqwRkGnIJiA0xQa5gbV0 GIIpQ4WBcTbYTMj3lTnL1lGaGa945ygQblJ0oXe0L4IuzQwgdQwiilmzePqdVKzy8W5u Sd7418BnaJvTwjWVJzjk+g5507dp2aDiBB8Cbd87uc9oh2Zcnh0NE/w3xTwJV5ugqHd3 m1/g== X-Gm-Message-State: ACgBeo0wVr2Lo5zr1UIWr0pVPJQsfOqNQdHSj0qXF7zkwLz7vtcwBUBA atmEVJ4qPW6tCd/151+c+nuCD59lWw== X-Google-Smtp-Source: AA6agR46bO17fnMxZM7TZ/5H7eKsa6pyH2qDyyeilP3PCFJj5Lb/9uX36JbQNKo/PIfxwnLmGVSszRTS6w== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:90a:bb96:b0:1fd:8068:cfd4 with SMTP id v22-20020a17090abb9600b001fd8068cfd4mr186096pjr.114.1661898017506; Tue, 30 Aug 2022 15:20:17 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:50 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-8-sagis@google.com> Subject: [RFC PATCH v2 07/17] KVM: selftest: TDX: Add basic get_td_vmcall_info test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test calls get_td_vmcall_info from the guest and verifies the expected returned values. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 43 +++++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 107 ++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index a28d15417d3e..39b000118e26 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -51,6 +51,7 @@ #define _PAGE_RW (1UL<<1) /* writeable */ #define _PAGE_PS (1UL<<7) /* page size bit*/ =20 +#define TDX_GET_TD_VM_CALL_INFO 0x10000 #define TDX_REPORT_FATAL_ERROR 0x10003 #define TDX_INSTRUCTION_IO 30 =20 @@ -232,6 +233,28 @@ static inline void tdvmcall_fatal(uint64_t error_code) tdcall(®s); } =20 +/* + * Get td vmcall info. + * Used to help request the host VMM enumerate which TDG.VP.VMCALLs are su= pported. + * Returns return in r10 code and leaf-specific output in r11-r14. + */ +static inline uint64_t tdvmcall_get_td_vmcall_info(uint64_t *r11, uint64_t= *r12, + uint64_t *r13, uint64_t *r14) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_GET_TD_VM_CALL_INFO; + regs.r12 =3D 0; + regs.rcx =3D 0x1C00; + tdcall(®s); + *r11 =3D regs.r11; + *r12 =3D regs.r12; + *r13 =3D regs.r13; + *r14 =3D regs.r14; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. @@ -244,6 +267,26 @@ static inline uint64_t tdvm_report_to_user_space(uint3= 2_t data) return tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=3D*/4, TDX_IO_WRITE, &dat= a_64); } =20 +/* + * Reports a 64 bit value from the guest to user space using a TDVM IO cal= l. + * Data is reported on port TDX_DATA_REPORT_PORT. + * Data is sent to host in 2 calls. LSB is sent (and needs to be read) fir= st. + */ +static inline uint64_t tdvm_report_64bit_to_user_space(uint64_t data) +{ + uint64_t err; + uint64_t data_lo =3D data & 0xFFFFFFFF; + uint64_t data_hi =3D (data >> 32) & 0xFFFFFFFF; + + err =3D tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=3D*/4, TDX_IO_WRITE, + &data_lo); + if (err) + return err; + + return tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=3D*/4, TDX_IO_WRITE, + &data_hi); +} + #define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\ (uint64_t)&__start_sec_ ## name) \ =20 diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 3f51f936ea5a..cf8260db1f5b 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -53,6 +53,25 @@ (VCPU)->run->system_event.data[1]); \ } while (0) =20 +static uint64_t read_64bit_from_guest(struct kvm_vcpu *vcpu, uint64_t port) +{ + uint32_t lo, hi; + uint64_t res; + + CHECK_IO(vcpu, port, 4, TDX_IO_WRITE); + lo =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + + CHECK_IO(vcpu, port, 4, TDX_IO_WRITE); + hi =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + res =3D hi; + res =3D (res << 32) | lo; + return res; +} + + /* * There might be multiple tests we are running and if one test fails, it = will * prevent the subsequent tests to run due to how tests are failing with @@ -383,6 +402,93 @@ void verify_td_cpuid(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies get_td_vmcall_info functionality. + */ +TDX_GUEST_FUNCTION(guest_code_get_td_vmcall_info) +{ + uint64_t err; + uint64_t r11, r12, r13, r14; + + err =3D tdvmcall_get_td_vmcall_info(&r11, &r12, &r13, &r14); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r11); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r12); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r13); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r14); + if (err) + tdvmcall_fatal(err); + + tdvmcall_success(); +} + +void verify_get_td_vmcall_info(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint64_t r11, r12, r13, r14; + + printf("Verifying TD get vmcall info:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_code_get_td_vmcall_info, + TDX_FUNCTION_SIZE(guest_code_get_td_vmcall_info), + 0); + finalize_td_memory(vm); + + /* Wait for guest to report r11 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r11 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r12 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r12 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r13 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r13 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r14 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r14 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + ASSERT_EQ(r11, 0); + ASSERT_EQ(r12, 0); + ASSERT_EQ(r13, 0); + ASSERT_EQ(r14, 0); + + /* Wait for guest to complete execution */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -394,6 +500,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_report_fatal_error); run_in_new_process(&verify_td_ioexit); run_in_new_process(&verify_td_cpuid); + run_in_new_process(&verify_get_td_vmcall_info); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CA2DECAAD4 for ; Tue, 30 Aug 2022 22:21:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232201AbiH3WVL (ORCPT ); Tue, 30 Aug 2022 18:21:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53982 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232137AbiH3WUg (ORCPT ); Tue, 30 Aug 2022 18:20:36 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A4635244B for ; Tue, 30 Aug 2022 15:20:20 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id w1-20020a63d741000000b0042c254a4ccdso3375762pgi.15 for ; Tue, 30 Aug 2022 15:20:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=ZKZyychf2ckUAiVIKhV5N5UZMfwgcYI+ar1kxk3E/L4=; b=EApviBTvewlHWbvbESqFcFdkFYfHnAVWK/NKIk8LewMSDM8v9kNk/x3ajoUqcjYrIi flTf9vFfA3VRfld7AapqlhyC6ac7BhSmpLyRq5FRDcH07mjcgdM5tFQy6e+nmXHbknDX 97ykUwvGQ6BDAtBFkJX3cgf87ZBhPYHXYV1cIeEH6gQWDkvbfq37IvDTgNX3bNgG1vFa myR9YHb1sOhKoPNyNSkvToAFa1ijO+sTHKeIEluMZI0XR6UgJEG72KpAwUwBd/FPJPPQ HEmwn51NHQPeWtEHTXH+M+HVZEcxdnywlVv/L1lBhetPph+3AWUopPOTUULyIDolyFNn ILCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=ZKZyychf2ckUAiVIKhV5N5UZMfwgcYI+ar1kxk3E/L4=; b=MOj5sGcX50XjZbiAgWKtLeNAG53nl2KBsk4Csm/WAL1WghFnPqtNhKO2faOSz9lhnk KKThRM+xYn26Sb+LZIBEaEnm5z3y0YJKmj4+XJzykyt4fT/ADoxudw5z0ZU6ZzEizqLb A/3aKwzyzU9tgZokVS3ddK/vOZ5bMYw+spv7W9aIIQ/Isu5HFgWjf45nlV+xyKbfeD7O wSCMCEZwsSmld9tiy0mplJi12RNJwA7fTtEa3npDkeosZoynlEUC7iqCJRghrjRfcuw4 pf/wvq5FWoPBJLMEbc/bPuXfQ/wo2y8UJgXWmw1my6b0YF0yRzTXyGxf5luFCFeKgNH3 X1eA== X-Gm-Message-State: ACgBeo3IFZs4ec1Nhr+b6gbjkRLqXE506YQ12wOW4VmeHzuI1ltAfCag zplzK9WVxlDyx3pRSdc1IDlzoTttgg== X-Google-Smtp-Source: AA6agR6/HMwaZBuWZDYIYWsY99pC+WePM1T6/CYJuVaTJ/QGT5UGOgcVVjOBVq5tri8Ty1s0OI+J3PSXhw== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:90a:e558:b0:1fb:c4b7:1a24 with SMTP id ei24-20020a17090ae55800b001fbc4b71a24mr995pjb.1.1661898018970; Tue, 30 Aug 2022 15:20:18 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:51 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-9-sagis@google.com> Subject: [RFC PATCH v2 08/17] KVM: selftest: TDX: Add TDX IO writes test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies IO writes of various sizes from the guest to the host. Google-Bug-Id: 235407183 Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 3 + .../selftests/kvm/x86_64/tdx_vm_tests.c | 85 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 39b000118e26..f1f44c2ad40e 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -51,6 +51,9 @@ #define _PAGE_RW (1UL<<1) /* writeable */ #define _PAGE_PS (1UL<<7) /* page size bit*/ =20 +#define TDX_VMCALL_SUCCESS 0x0000000000000000 +#define TDX_VMCALL_INVALID_OPERAND 0x8000000000000000 + #define TDX_GET_TD_VM_CALL_INFO 0x10000 #define TDX_REPORT_FATAL_ERROR 0x10003 #define TDX_INSTRUCTION_IO 30 diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index cf8260db1f5b..ee60f77fe38e 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -489,6 +489,90 @@ void verify_get_td_vmcall_info(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies IO functionality by writing values of different sizes + * to the host. + */ +TDX_GUEST_FUNCTION(guest_io_writes) +{ + uint64_t byte_1 =3D 0xAB; + uint64_t byte_2 =3D 0xABCD; + uint64_t byte_4 =3D 0xFFABCDEF; + uint64_t ret; + + ret =3D tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_WRITE, &byte_1); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_io(TDX_TEST_PORT, 2, TDX_IO_WRITE, &byte_2); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_io(TDX_TEST_PORT, 4, TDX_IO_WRITE, &byte_4); + if (ret) + tdvmcall_fatal(ret); + + // Write an invalid number of bytes. + ret =3D tdvmcall_io(TDX_TEST_PORT, 5, TDX_IO_WRITE, &byte_4); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void verify_guest_writes(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint8_t byte_1; + uint16_t byte_2; + uint32_t byte_4; + + printf("Verifying guest writes:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_io_writes, + TDX_FUNCTION_SIZE(guest_io_writes), 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 1, TDX_IO_WRITE); + byte_1 =3D *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 2, TDX_IO_WRITE); + byte_2 =3D *(uint16_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 4, TDX_IO_WRITE); + byte_4 =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + ASSERT_EQ(byte_1, 0xAB); + ASSERT_EQ(byte_2, 0xABCD); + ASSERT_EQ(byte_4, 0xFFABCDEF); + + vcpu_run(vcpu); + ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_SYSTEM_EVENT); + ASSERT_EQ(vcpu->run->system_event.data[1], TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -501,6 +585,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_td_ioexit); run_in_new_process(&verify_td_cpuid); run_in_new_process(&verify_get_td_vmcall_info); + run_in_new_process(&verify_guest_writes); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79512ECAAD5 for ; Tue, 30 Aug 2022 22:21:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232329AbiH3WVQ (ORCPT ); Tue, 30 Aug 2022 18:21:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52942 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232011AbiH3WUi (ORCPT ); Tue, 30 Aug 2022 18:20:38 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E413A58DD5 for ; Tue, 30 Aug 2022 15:20:21 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id s8-20020a170902ea0800b00172e456031eso8664382plg.3 for ; Tue, 30 Aug 2022 15:20:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=4AF1UYLjwIVXmrQJvzJrIG8LzqFDnrR9FyDZEzZ+cxA=; b=BLGMtymfosqoL+BOv1LwQs5tr4NSlaP/SpxDqt3yNRrcO6o4JXX+XCPHk2vXRbtGA+ sMpkWToV2Anu6hegtbXOwvigD8G9kJSB0KajxojvM+GhZDD/5INbIw8CJobpfr+2cDKe +eXhnrrUzrFIsAfYEAHjATunPBBR9lHbGOUe/lmcLCoP+U8QRAxD77rtkBrTXA8UhVnl PkI2bPurJZ36XQdElpU130uGvHicr76h4lVL/z+JjQupAG7njNahc89+zt5Gq8Ovx/kF EE69PgkbCgl6MCCJWFJM1wewVd4IJqa4H31cm2SXygjTyYZGeZd+ttIZJFymsyQGYwoI trJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=4AF1UYLjwIVXmrQJvzJrIG8LzqFDnrR9FyDZEzZ+cxA=; b=eAPcPD4W9RPDdsZ9mnjJlxPGYjRQ3Yxwn1kD73dT/Lzk0x2IUX70BWePC7/BzOkIXE J32PejoXPiLddA8xZiOC+lJMYDCb2Ulee6Ok2QafzS3TwZpDQdbJoCnxDIO0hoHN1zV3 Z7+m5qU89c+YHzpbLQlWhO/50/ByLDf9+TwKj+cMb688UnoY/+/iJLVrMf8RkqMV02vo zS5E2zmW6lvtQ+CIqYkHbXObCgfLXfXevaZIHlsgvnkPMvlKIEV26iKhKOKDnNzIbqAF 6+EY0X0wVEcALOc2MbeV40zZ6DQwlDgBIMiZQQgGEcGPYiXiL42Ylf3HhWhO2jOqRUcl b7TA== X-Gm-Message-State: ACgBeo2I+pI7Z74E1WKXnZ7hXLJ3M+9DZScK5N2P0x88WMbCQ3FFOWOy BesShjKNj0Vrdy6NI/H9Hrm+mTyeSg== X-Google-Smtp-Source: AA6agR4DW4q/2A9ywSd13iCF+ePp48d1hrUtaMUrw4UtWfNqMySae1IrbHzEezfja+68agZoyw6i28qwyg== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:902:e5d2:b0:175:fe0:223b with SMTP id u18-20020a170902e5d200b001750fe0223bmr6245168plf.92.1661898020660; Tue, 30 Aug 2022 15:20:20 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:52 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-10-sagis@google.com> Subject: [RFC PATCH v2 09/17] KVM: selftest: TDX: Add TDX IO reads test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies IO reads of various sizes from the host to the guest. Signed-off-by: Sagi Shahar --- .../selftests/kvm/x86_64/tdx_vm_tests.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index ee60f77fe38e..85b5ab99424e 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only =20 +#include "asm/kvm.h" +#include #include #include #include @@ -573,6 +575,87 @@ void verify_guest_writes(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies IO functionality by reading values of different sizes + * from the host. + */ +TDX_GUEST_FUNCTION(guest_io_reads) +{ + uint64_t data; + uint64_t ret; + + ret =3D tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_READ, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0xAB) + tdvmcall_fatal(1); + + ret =3D tdvmcall_io(TDX_TEST_PORT, 2, TDX_IO_READ, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0xABCD) + tdvmcall_fatal(2); + + ret =3D tdvmcall_io(TDX_TEST_PORT, 4, TDX_IO_READ, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0xFFABCDEF) + tdvmcall_fatal(4); + + // Read an invalid number of bytes. + ret =3D tdvmcall_io(TDX_TEST_PORT, 5, TDX_IO_READ, &data); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void verify_guest_reads(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + printf("Verifying guest reads:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_io_reads, + TDX_FUNCTION_SIZE(guest_io_reads), 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 1, TDX_IO_READ); + *(uint8_t *)((void *)vcpu->run + vcpu->run->io.data_offset) =3D 0xAB; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 2, TDX_IO_READ); + *(uint16_t *)((void *)vcpu->run + vcpu->run->io.data_offset) =3D 0xABCD; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 4, TDX_IO_READ); + *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset) =3D 0xFFABCD= EF; + + vcpu_run(vcpu); + ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_SYSTEM_EVENT); + ASSERT_EQ(vcpu->run->system_event.data[1], TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -586,6 +669,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_td_cpuid); run_in_new_process(&verify_get_td_vmcall_info); run_in_new_process(&verify_guest_writes); + run_in_new_process(&verify_guest_reads); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A2612ECAAD4 for ; Tue, 30 Aug 2022 22:21:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232372AbiH3WVa (ORCPT ); Tue, 30 Aug 2022 18:21:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54050 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232285AbiH3WVH (ORCPT ); Tue, 30 Aug 2022 18:21:07 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3022061B37 for ; Tue, 30 Aug 2022 15:20:25 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id lx1-20020a17090b4b0100b001fd720458c3so1247642pjb.1 for ; Tue, 30 Aug 2022 15:20:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=sOX1XOkMTNP89FeyjTl121MB6xyMNQdWf26YjlGxjkU=; b=EMWJFza8n/pVkMzyp5Egqw1c3Hvb52fwxBRvcKF6phUtBCDb4j8Uov1AabTS5+QokQ uPKX7+HHgyylIliyq7ilBJNtcK+iZWw5sjcllSmaoTwVDX2SAOPtDOjPJpFWUhG5aGzd d+4XlOM52rVG7KZUkm9F8AiZ/nAMrTpasazKOf9boQ/N6y5nFryZN0unfxkz8SpDPQsL yDKNwT7Ypu1kIjibRhTzEULxSan95DscgQ7bujqCUBbyVzRFzSYhOczKOFUtLV2I0yBy uNoRQeLk4I9tKSQY+F8sLzmmKE7r0+9C0SdbwG6K66X0aAdK9qMq9r366f8fJEcLoiZa d6RQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=sOX1XOkMTNP89FeyjTl121MB6xyMNQdWf26YjlGxjkU=; b=O0bnguR8sAEaf1+VUKWMOcpfznPLwdtBUPaGS7cjTo7UCZccvQY1VDjtuR45hMdp+0 JxaX6sx9RHPa7VwNPmizYvzbtWStb7nF3Mq/gYJFfOLq1xkciDg957G4vyyT7ks7K+S5 CdYVzmC9R383SC51+nJkDGbkDc/hEvlok0mXlYKwcKZSx6YDTINjvwTXNBVNizy6wFz/ MjH1uRvvWlf5w9S1bR7znIUtyU9hEPG1TL6tU5bJ7UsBrrLJY+dfMNAF3E2om6xDEUbd YmiFPzRYWzcljn1nlatCfjBSr6fxpHFq8uUCWk6JwzQsAdxsB0hZ63vpmmQWaX2UJ1XG DbMg== X-Gm-Message-State: ACgBeo3j7KKjjS5/Gw1nQEr4KN45/XyoYw0aZy66dz58H3lxSCN5q0Y3 i/8odKHVWMtqZns5N3gDIccwP1C76Q== X-Google-Smtp-Source: AA6agR5JRKYfTjXtUS8ogxmfTte8ySUyffUi2ssKkLp2LZObbA/ZpbSm4YLluSvKI2/Pd1FY7BDRQLJNyg== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:90a:e558:b0:1fb:c4b7:1a24 with SMTP id ei24-20020a17090ae55800b001fbc4b71a24mr1011pjb.1.1661898022646; Tue, 30 Aug 2022 15:20:22 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:53 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-11-sagis@google.com> Subject: [RFC PATCH v2 10/17] KVM: selftest: TDX: Add TDX MSR read/write tests From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies reads and writes for MSR registers with different access level. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 34 +++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 229 ++++++++++++++++++ 2 files changed, 263 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index f1f44c2ad40e..263834979727 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -57,6 +57,8 @@ #define TDX_GET_TD_VM_CALL_INFO 0x10000 #define TDX_REPORT_FATAL_ERROR 0x10003 #define TDX_INSTRUCTION_IO 30 +#define TDX_INSTRUCTION_RDMSR 31 +#define TDX_INSTRUCTION_WRMSR 32 =20 #define TDX_SUCCESS_PORT 0x30 #define TDX_TEST_PORT 0x31 @@ -258,6 +260,38 @@ static inline uint64_t tdvmcall_get_td_vmcall_info(uin= t64_t *r11, uint64_t *r12, return regs.r10; } =20 +/* + * Read MSR register. + */ +static inline uint64_t tdvmcall_rdmsr(uint64_t index, uint64_t *ret_value) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_RDMSR; + regs.r12 =3D index; + regs.rcx =3D 0x1C00; + tdcall(®s); + *ret_value =3D regs.r11; + return regs.r10; +} + +/* + * Write MSR register. + */ +static inline uint64_t tdvmcall_wrmsr(uint64_t index, uint64_t value) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_WRMSR; + regs.r12 =3D index; + regs.r13 =3D value; + regs.rcx =3D 0x3C00; + tdcall(®s); + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 85b5ab99424e..fb3b8de7e5cd 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -55,6 +55,40 @@ (VCPU)->run->system_event.data[1]); \ } while (0) =20 + +/* + * Define a filter which denies all MSR access except the following: + * MTTR_BASE_0: Allow read/write access + * MTTR_BASE_1: Allow read access + * MTTR_BASE_2: Allow write access + */ +static u64 allow_bits =3D 0xFFFFFFFFFFFFFFFF; +#define MTTR_BASE_0 (0x200) +#define MTTR_BASE_1 (0x202) +#define MTTR_BASE_2 (0x204) +struct kvm_msr_filter test_filter =3D { + .flags =3D KVM_MSR_FILTER_DEFAULT_DENY, + .ranges =3D { + { + .flags =3D KVM_MSR_FILTER_READ | + KVM_MSR_FILTER_WRITE, + .nmsrs =3D 1, + .base =3D MTTR_BASE_0, + .bitmap =3D (uint8_t *)&allow_bits, + }, { + .flags =3D KVM_MSR_FILTER_READ, + .nmsrs =3D 1, + .base =3D MTTR_BASE_1, + .bitmap =3D (uint8_t *)&allow_bits, + }, { + .flags =3D KVM_MSR_FILTER_WRITE, + .nmsrs =3D 1, + .base =3D MTTR_BASE_2, + .bitmap =3D (uint8_t *)&allow_bits, + }, + }, +}; + static uint64_t read_64bit_from_guest(struct kvm_vcpu *vcpu, uint64_t port) { uint32_t lo, hi; @@ -656,6 +690,199 @@ void verify_guest_reads(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies MSR read functionality. + */ +TDX_GUEST_FUNCTION(guest_msr_read) +{ + uint64_t data; + uint64_t ret; + + ret =3D tdvmcall_rdmsr(MTTR_BASE_0, &data); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvm_report_64bit_to_user_space(data); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_rdmsr(MTTR_BASE_1, &data); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvm_report_64bit_to_user_space(data); + if (ret) + tdvmcall_fatal(ret); + + /* We expect this call to fail since MTTR_BASE_2 is write only */ + ret =3D tdvmcall_rdmsr(MTTR_BASE_2, &data); + if (ret) { + ret =3D tdvm_report_64bit_to_user_space(ret); + if (ret) + tdvmcall_fatal(ret); + } else { + tdvmcall_fatal(-99); + } + + tdvmcall_success(); +} + +void verify_guest_msr_reads(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint64_t data; + int ret; + + printf("Verifying guest msr reads:\n"); + + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Set explicit MSR filter map to control access to the MSR registers + * used in the test. + */ + printf("\t ... Setting test MSR filter\n"); + ret =3D kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); + TEST_ASSERT(ret, "KVM_CAP_X86_USER_SPACE_MSR is unavailable"); + vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_FILTER); + + ret =3D kvm_check_cap(KVM_CAP_X86_MSR_FILTER); + TEST_ASSERT(ret, "KVM_CAP_X86_MSR_FILTER is unavailable"); + + ret =3D ioctl(vm->fd, KVM_X86_SET_MSR_FILTER, &test_filter); + TEST_ASSERT(ret =3D=3D 0, + "KVM_X86_SET_MSR_FILTER failed, ret: %i errno: %i (%s)", + ret, errno, strerror(errno)); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_msr_read, + TDX_FUNCTION_SIZE(guest_msr_read), 0); + finalize_td_memory(vm); + + printf("\t ... Setting test MTTR values\n"); + /* valid values for mttr type are 0, 1, 4, 5, 6 */ + vcpu_set_msr(vcpu, MTTR_BASE_0, 4); + vcpu_set_msr(vcpu, MTTR_BASE_1, 5); + vcpu_set_msr(vcpu, MTTR_BASE_2, 6); + + printf("\t ... Running guest\n"); + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, 4); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, 5); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + +/* + * Verifies MSR write functionality. + */ +TDX_GUEST_FUNCTION(guest_msr_write) +{ + uint64_t ret; + + ret =3D tdvmcall_wrmsr(MTTR_BASE_0, 4); + if (ret) + tdvmcall_fatal(ret); + + /* We expect this call to fail since MTTR_BASE_1 is read only */ + ret =3D tdvmcall_wrmsr(MTTR_BASE_1, 5); + if (ret) { + ret =3D tdvm_report_64bit_to_user_space(ret); + if (ret) + tdvmcall_fatal(ret); + } else { + tdvmcall_fatal(-99); + } + + + ret =3D tdvmcall_wrmsr(MTTR_BASE_2, 6); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void verify_guest_msr_writes(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint64_t data; + int ret; + + printf("Verifying guest msr writes:\n"); + + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Set explicit MSR filter map to control access to the MSR registers + * used in the test. + */ + printf("\t ... Setting test MSR filter\n"); + ret =3D kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); + TEST_ASSERT(ret, "KVM_CAP_X86_USER_SPACE_MSR is unavailable"); + vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_FILTER); + + ret =3D kvm_check_cap(KVM_CAP_X86_MSR_FILTER); + TEST_ASSERT(ret, "KVM_CAP_X86_MSR_FILTER is unavailable"); + + ret =3D ioctl(vm->fd, KVM_X86_SET_MSR_FILTER, &test_filter); + TEST_ASSERT(ret =3D=3D 0, + "KVM_X86_SET_MSR_FILTER failed, ret: %i errno: %i (%s)", + ret, errno, strerror(errno)); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_msr_write, + TDX_FUNCTION_SIZE(guest_msr_write), 0); + finalize_td_memory(vm); + + printf("\t ... Running guest\n"); + /* Only the write to MTTR_BASE_1 should trigger an exit */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + printf("\t ... Verifying MTTR values writen by guest\n"); + + ASSERT_EQ(vcpu_get_msr(vcpu, MTTR_BASE_0), 4); + ASSERT_EQ(vcpu_get_msr(vcpu, MTTR_BASE_1), 0); + ASSERT_EQ(vcpu_get_msr(vcpu, MTTR_BASE_2), 6); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -670,6 +897,8 @@ int main(int argc, char **argv) run_in_new_process(&verify_get_td_vmcall_info); run_in_new_process(&verify_guest_writes); run_in_new_process(&verify_guest_reads); + run_in_new_process(&verify_guest_msr_reads); + run_in_new_process(&verify_guest_msr_writes); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED4FFECAAD4 for ; Tue, 30 Aug 2022 22:21:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232224AbiH3WVe (ORCPT ); Tue, 30 Aug 2022 18:21:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232291AbiH3WVI (ORCPT ); Tue, 30 Aug 2022 18:21:08 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46A9B61D80 for ; Tue, 30 Aug 2022 15:20:26 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id y21-20020a056a001c9500b0053817f57e8dso3317204pfw.6 for ; Tue, 30 Aug 2022 15:20:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=DuyfC69i2OMiSbHTPcw/27B1qgcnYyIWftYisyD6nW0=; b=dtazo0Jod0alN8kOX/Wvf4oqimm+UjA9lpCOaevAhUcab0kjuhjNKNvP/PcgFpAp7R POn5YpMjv+n4Tg9a6bXeEm297lTYF2PoEjG7xBzS9qHB5DnR/gY8oO3+FGmJF/4dJJUN MtL/CpKNS5OTm66QU16pFanQDbguYR4TlknvcVAvWVuENScXV4RH784UXWkqoPHFUEMW hPLLKTAaF6Qm/Em1LBJIECpQkvyloywGf9eFsDcjMaTF1QRBQUk9YxWJ/4UjlGZ3ViEe spVsVb5BOhpDOOfBvvP2ou3Ynoyovelels5MaTc5eGNWNFnGKk8BxAahixARrespjyNl kMtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=DuyfC69i2OMiSbHTPcw/27B1qgcnYyIWftYisyD6nW0=; b=AMoOKkoHJDVo0L/DgLgjyrKMZZggyMOwXWRMmjPIE6V2qusv6AVLk/UfF0wme9BA96 xO4pRbOaIrIE4VbahPecCJW3wCRjESpif742qqrZdodimyhBgl4GbELoyxuFz/En2jpD cBOLx71Pjsx9LM2f90284cKUllEz7tSqMLwqPcA4+EFyeOnOoA/QKWG6Z1Y/jPyEuQUV fp0n5n46wKzf5j6J1jTBfjvBrw4VqVfoTrgOanh+fdhHxGvSfmXIXs+/JgmeBOaZTxIJ 7SE2T2dxHNzMDMwcRnb++EGyUaDaWo1+T6/DpKP07OUYXGcXLjgvhrWN/i9Rvapmf/TJ 3Jwg== X-Gm-Message-State: ACgBeo24arS6rWTPVWIrA/HcGcHOYeJpNay0AUw1QwPWoXPlqEyvTduf p0DcrhnpGjcmWrBTu2MJ2gVTVfS44w== X-Google-Smtp-Source: AA6agR5Cvo6pmJ9dCM7qTMudSGq7bZQddkeaa+H5ytT2CwJ8GCWxD9HIqhxgpXFTE/KP+c8Lsl01EWbR3A== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:1309:b0:535:d421:1347 with SMTP id j9-20020a056a00130900b00535d4211347mr23761516pfu.5.1661898025004; Tue, 30 Aug 2022 15:20:25 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:54 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-12-sagis@google.com> Subject: [RFC PATCH v2 11/17] KVM: selftest: TDX: Add TDX HLT exit test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies that the guest runs TDVMCALL and the guest vCPU enters to the halted state. Signed-off-by: Erdem Aktas Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 16 ++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 88 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 263834979727..b11200028546 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -56,6 +56,7 @@ =20 #define TDX_GET_TD_VM_CALL_INFO 0x10000 #define TDX_REPORT_FATAL_ERROR 0x10003 +#define TDX_INSTRUCTION_HLT 12 #define TDX_INSTRUCTION_IO 30 #define TDX_INSTRUCTION_RDMSR 31 #define TDX_INSTRUCTION_WRMSR 32 @@ -292,6 +293,21 @@ static inline uint64_t tdvmcall_wrmsr(uint64_t index, = uint64_t value) return regs.r10; } =20 +/* + * Execute HLT instruction. + */ +static inline uint64_t tdvmcall_hlt(uint64_t interrupt_blocked_flag) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_HLT; + regs.r12 =3D interrupt_blocked_flag; + regs.rcx =3D 0x1C00; + tdcall(®s); + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index fb3b8de7e5cd..39604aac54bd 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -883,6 +883,93 @@ void verify_guest_msr_writes(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies HLT functionality. + */ +TDX_GUEST_FUNCTION(guest_hlt) +{ + uint64_t ret; + uint64_t interrupt_blocked_flag; + + interrupt_blocked_flag =3D 0; + ret =3D tdvmcall_hlt(interrupt_blocked_flag); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void _verify_guest_hlt(int signum); + +void wake_me(int interval) +{ + struct sigaction action; + + action.sa_handler =3D _verify_guest_hlt; + sigemptyset(&action.sa_mask); + action.sa_flags =3D 0; + + TEST_ASSERT(sigaction(SIGALRM, &action, NULL) =3D=3D 0, + "Could not set the alarm handler!"); + + alarm(interval); +} + +void _verify_guest_hlt(int signum) +{ + static struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + /* + * This function will also be called by SIGALRM handler to check the + * vCPU MP State. If vm has been initialized, then we are in the signal + * handler. Check the MP state and let the guest run again. + */ + if (vcpu !=3D NULL) { + struct kvm_mp_state mp_state; + + vcpu_mp_state_get(vcpu, &mp_state); + ASSERT_EQ(mp_state.mp_state, KVM_MP_STATE_HALTED); + + /* Let the guest to run and finish the test.*/ + mp_state.mp_state =3D KVM_MP_STATE_RUNNABLE; + vcpu_mp_state_set(vcpu, &mp_state); + return; + } + + printf("Verifying HLT:\n"); + + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_hlt, + TDX_FUNCTION_SIZE(guest_hlt), 0); + finalize_td_memory(vm); + + printf("\t ... Running guest\n"); + + /* Wait 1 second for guest to execute HLT */ + wake_me(1); + vcpu_run(vcpu); + + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + +void verify_guest_hlt(void) +{ + _verify_guest_hlt(0); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -899,6 +986,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_guest_reads); run_in_new_process(&verify_guest_msr_reads); run_in_new_process(&verify_guest_msr_writes); + run_in_new_process(&verify_guest_hlt); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B42A4ECAAA1 for ; Tue, 30 Aug 2022 22:21:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232319AbiH3WVl (ORCPT ); Tue, 30 Aug 2022 18:21:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231997AbiH3WVL (ORCPT ); Tue, 30 Aug 2022 18:21:11 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EE4356E2C3 for ; Tue, 30 Aug 2022 15:20:27 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id cj15-20020a056a00298f00b0053a700f1178so1396076pfb.14 for ; Tue, 30 Aug 2022 15:20:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=3Hb55PPYqJ9GhLXNrzEjW9U1TfsgkxT16tA5j1wTvr0=; b=lOtIGU26iz1lGzz8PGxwebfYTciclQR/ZgZqMjT1sDm6xcmOSU7kFFnxdKTt4q5Ssc Jl92P1U0pIKvRArwiPIAhoifOejXR1RAKNMMgUIrEsd0mt601ry3OkyJ69SbdGSjCoK9 gB5WDN+KstIssgYegKHaGoEkGdGJaJ6kd/x/wLSSWZRamedKb3Zs71O96pmeT1lKxxj2 BYFZbVoLweZlWz32QxV5gtF4JpzPcpNt2Ub/bZ8qWrmQU27ra+MaAAmiaWTcvefsUOc8 27XAGYSi2VBY0E990Jv7NmNmhYC1xqe6hjceMiWojJ9F3KhctMFnapBA6pRKP4kyp76X joTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=3Hb55PPYqJ9GhLXNrzEjW9U1TfsgkxT16tA5j1wTvr0=; b=rkFKbVEVGNKoDxGdf1TYKxie+sm7QaIOeFWsKcEfyaM/fGIbL/wt6Tpzb0IQugrz8l 9xJ8DuJw2JvNwA0oiMETrS4tBwBRTPMM2/aph9+40N1/pFOwwLO3fN4FvalnwiSQfuUm xyf/gNhrqAgGQ41id0RPQGhmaj1s87Ni/WGDbJR82MDV2orNd0LeOzBlPq06Dis8E1cQ IGHpmCXs98DyXipVOrl1b2G7tGa9UR8lOOrkBuhlrprJrTg1G7SqxB1pXZzJZSgMBNmC XsezqVyOv1KXd6ls04hOZ7sTZpQF6O7ovxmjgkLxvMRws5H4g6UwRjfBoPoP2C6PFqUh ZJxw== X-Gm-Message-State: ACgBeo3vMvrqE6mJDvfEMqBPW3s2FhsFiecNpaUQtoe18scJThygRfx0 LIGrn0Jl6BdMhcGcg8cH51NsCi0OWQ== X-Google-Smtp-Source: AA6agR5r9ukQ4wlLG+/DfKVl60d5YWDQENm8K4M7KnBQl9loaE6nhV9tNxkZsIffR8utMom8bm2g3UZNjg== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:174b:b0:52f:c4d1:d130 with SMTP id j11-20020a056a00174b00b0052fc4d1d130mr22924078pfc.23.1661898026592; Tue, 30 Aug 2022 15:20:26 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:55 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-13-sagis@google.com> Subject: [RFC PATCH v2 12/17] KVM: selftest: TDX: Add TDX MMIO reads test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies MMIO reads of various sizes from the host to the guest. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 21 ++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 113 ++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index b11200028546..7045d617dd78 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -60,12 +60,15 @@ #define TDX_INSTRUCTION_IO 30 #define TDX_INSTRUCTION_RDMSR 31 #define TDX_INSTRUCTION_WRMSR 32 +#define TDX_INSTRUCTION_VE_REQUEST_MMIO 48 =20 #define TDX_SUCCESS_PORT 0x30 #define TDX_TEST_PORT 0x31 #define TDX_DATA_REPORT_PORT 0x32 #define TDX_IO_READ 0 #define TDX_IO_WRITE 1 +#define TDX_MMIO_READ 0 +#define TDX_MMIO_WRITE 1 =20 #define GDT_ENTRY(flags, base, limit) \ ((((base) & 0xff000000ULL) << (56-24)) | \ @@ -308,6 +311,24 @@ static inline uint64_t tdvmcall_hlt(uint64_t interrupt= _blocked_flag) return regs.r10; } =20 +/* + * Execute MMIO request instruction for read. + */ +static inline uint64_t tdvmcall_mmio_read(uint64_t address, uint64_t size,= uint64_t *data_out) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_VE_REQUEST_MMIO; + regs.r12 =3D size; + regs.r13 =3D TDX_MMIO_READ; + regs.r14 =3D address; + regs.rcx =3D 0x7C00; + tdcall(®s); + *data_out =3D regs.r11; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 39604aac54bd..963e4feae31a 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only =20 #include "asm/kvm.h" +#include "linux/kernel.h" #include #include #include @@ -47,6 +48,24 @@ (VCPU)->run->io.direction); \ } while (0) =20 +#define CHECK_MMIO(VCPU, ADDR, SIZE, DIR) \ + do { \ + TEST_ASSERT((VCPU)->run->exit_reason =3D=3D KVM_EXIT_MMIO, \ + "Got exit_reason other than KVM_EXIT_MMIO: %u (%s)\n", \ + (VCPU)->run->exit_reason, \ + exit_reason_str((VCPU)->run->exit_reason)); \ + \ + TEST_ASSERT(((VCPU)->run->exit_reason =3D=3D KVM_EXIT_MMIO) && \ + ((VCPU)->run->mmio.phys_addr =3D=3D (ADDR)) && \ + ((VCPU)->run->mmio.len =3D=3D (SIZE)) && \ + ((VCPU)->run->mmio.is_write =3D=3D (DIR)), \ + "Got an unexpected MMIO exit values: %u (%s) %llu %d %d\n", \ + (VCPU)->run->exit_reason, \ + exit_reason_str((VCPU)->run->exit_reason), \ + (VCPU)->run->mmio.phys_addr, (VCPU)->run->mmio.len, \ + (VCPU)->run->mmio.is_write); \ + } while (0) + #define CHECK_GUEST_FAILURE(VCPU) \ do { \ if ((VCPU)->run->exit_reason =3D=3D KVM_EXIT_SYSTEM_EVENT) \ @@ -89,6 +108,8 @@ struct kvm_msr_filter test_filter =3D { }, }; =20 +#define MMIO_VALID_ADDRESS (TDX_GUEST_MAX_NR_PAGES * PAGE_SIZE + 1) + static uint64_t read_64bit_from_guest(struct kvm_vcpu *vcpu, uint64_t port) { uint32_t lo, hi; @@ -970,6 +991,97 @@ void verify_guest_hlt(void) _verify_guest_hlt(0); } =20 +TDX_GUEST_FUNCTION(guest_mmio_reads) +{ + uint64_t data; + uint64_t ret; + + ret =3D tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 1, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0x12) + tdvmcall_fatal(1); + + ret =3D tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 2, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0x1234) + tdvmcall_fatal(2); + + ret =3D tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 4, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0x12345678) + tdvmcall_fatal(4); + + ret =3D tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 8, &data); + if (ret) + tdvmcall_fatal(ret); + if (data !=3D 0x1234567890ABCDEF) + tdvmcall_fatal(8); + + // Read an invalid number of bytes. + ret =3D tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 10, &data); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +/* + * Varifies guest MMIO reads. + */ +void verify_mmio_reads(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + printf("Verifying TD MMIO reads:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_mmio_reads, + TDX_FUNCTION_SIZE(guest_mmio_reads), 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 1, TDX_MMIO_READ); + *(uint8_t *)vcpu->run->mmio.data =3D 0x12; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 2, TDX_MMIO_READ); + *(uint16_t *)vcpu->run->mmio.data =3D 0x1234; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 4, TDX_MMIO_READ); + *(uint32_t *)vcpu->run->mmio.data =3D 0x12345678; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 8, TDX_MMIO_READ); + *(uint64_t *)vcpu->run->mmio.data =3D 0x1234567890ABCDEF; + + vcpu_run(vcpu); + ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_SYSTEM_EVENT); + ASSERT_EQ(vcpu->run->system_event.data[1], TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -987,6 +1099,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_guest_msr_reads); run_in_new_process(&verify_guest_msr_writes); run_in_new_process(&verify_guest_hlt); + run_in_new_process(&verify_mmio_reads); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5995ECAAD5 for ; Tue, 30 Aug 2022 22:22:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232299AbiH3WWK (ORCPT ); Tue, 30 Aug 2022 18:22:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232360AbiH3WV2 (ORCPT ); Tue, 30 Aug 2022 18:21:28 -0400 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 7453780512 for ; Tue, 30 Aug 2022 15:20:45 -0700 (PDT) Received: by mail-pl1-x649.google.com with SMTP id p18-20020a170902a41200b00172b0dc71e0so8696317plq.0 for ; Tue, 30 Aug 2022 15:20:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=XGisEg3sosGxno0TvjO4HvwWJUc+batMd9qgnL8cNT4=; b=NgGqwZ0Dhnd8/j3B3dmrOklRqoBSjTYgA7gn7uLdXSt7kjVtMudI2I2ruWAaUEzK5v zCx59Yw9f0nxh4YXMD0mqG7F6iscqIrcKkv8NAHP7Kbwy137aLKwp9QDEgTpgQBpyL4i siB79DFI3sqHIu3oY7Bj2EcGo1cZ9ZHPoupvdnF7n+vZug3yoTAV53b4UlO+hFpCWXoR uDMJxLSJg8XTjV/ggBxC2baL8GCIkJkQDssYuLNSQCwrcpW9L4bTtoYbEAlYxj8b6DS3 Mm8Tavwzglvn4ef64onkfu1qvM0gvv5DP7SMTP1CrwufJeuJQSlO7caypcXhWeBu/NXT kSAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=XGisEg3sosGxno0TvjO4HvwWJUc+batMd9qgnL8cNT4=; b=RiXLaZ4PTFXgOrnzPx0oXYA8AV2RSj36JCFTxga8kkfckaW2Bz2+CC3Rmu+YXg3vpe Br289A03QBYDuxAW8600ydPxetX3vv+aF5ADrZKQ8W5Wld2KpwC6bqOc/ivFlab479EV 74St7GwFWRKAqBUfoC5yCgaezvjqGQ3+5Bp2d+RsJvLSMGyN+dRhvgl57+0ct8AeJkST ILShsxbiqUVWZd1mi8sOS4ApCeTU7FuFLs2WlemixaG+Y0ejAU5oyHSU2CSAqhebM5QG 6Ad+0zgTeH6zdjMlvnxg3YWFAW52uoymcaQzEJ+p6TBcWgscN5BnlH0oFKKC9O/8ClJ7 +KdQ== X-Gm-Message-State: ACgBeo2X9CdomouEmYa9r2kHFVsGd26NFpEQWfaFpXCHD8ZWTHKP7J+1 MOt3pIHTjIR2DgKBPnY6aen8Jug97g== X-Google-Smtp-Source: AA6agR58PpzfkJaOKL5P3VkvrvMgUaV+8am7rwtsdMFdVRE98wNWCH+lEhFt7dOUm8PMABuN3S3LxXL6AQ== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:16c4:b0:535:890:d52 with SMTP id l4-20020a056a0016c400b0053508900d52mr23444002pfc.9.1661898028220; Tue, 30 Aug 2022 15:20:28 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:56 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-14-sagis@google.com> Subject: [RFC PATCH v2 13/17] KVM: selftest: TDX: Add TDX MMIO writes test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The test verifies MMIO writes of various sizes from the guest to the host. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 18 ++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 92 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 7045d617dd78..17e3649e5729 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -329,6 +329,24 @@ static inline uint64_t tdvmcall_mmio_read(uint64_t add= ress, uint64_t size, uint6 return regs.r10; } =20 +/* + * Execute MMIO request instruction for write. + */ +static inline uint64_t tdvmcall_mmio_write(uint64_t address, uint64_t size= , uint64_t data_in) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_VE_REQUEST_MMIO; + regs.r12 =3D size; + regs.r13 =3D TDX_MMIO_WRITE; + regs.r14 =3D address; + regs.r15 =3D data_in; + regs.rcx =3D 0xFC00; + tdcall(®s); + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 963e4feae31a..382119bd444b 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -1082,6 +1082,97 @@ void verify_mmio_reads(void) printf("\t ... PASSED\n"); } =20 +TDX_GUEST_FUNCTION(guest_mmio_writes) +{ + uint64_t ret; + + ret =3D tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 1, 0x12); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 2, 0x1234); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 4, 0x12345678); + if (ret) + tdvmcall_fatal(ret); + + ret =3D tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 8, 0x1234567890ABCDEF); + if (ret) + tdvmcall_fatal(ret); + + // Write across page boundary. + ret =3D tdvmcall_mmio_write(PAGE_SIZE - 1, 8, 0); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +/* + * Varifies guest MMIO writes. + */ +void verify_mmio_writes(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint8_t byte_1; + uint16_t byte_2; + uint32_t byte_4; + uint64_t byte_8; + + printf("Verifying TD MMIO writes:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_mmio_writes, + TDX_FUNCTION_SIZE(guest_mmio_writes), 0); + finalize_td_memory(vm); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 1, TDX_MMIO_WRITE); + byte_1 =3D *(uint8_t *)(vcpu->run->mmio.data); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 2, TDX_MMIO_WRITE); + byte_2 =3D *(uint16_t *)(vcpu->run->mmio.data); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 4, TDX_MMIO_WRITE); + byte_4 =3D *(uint32_t *)(vcpu->run->mmio.data); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 8, TDX_MMIO_WRITE); + byte_8 =3D *(uint64_t *)(vcpu->run->mmio.data); + + ASSERT_EQ(byte_1, 0x12); + ASSERT_EQ(byte_2, 0x1234); + ASSERT_EQ(byte_4, 0x12345678); + ASSERT_EQ(byte_8, 0x1234567890ABCDEF); + + vcpu_run(vcpu); + ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_SYSTEM_EVENT); + ASSERT_EQ(vcpu->run->system_event.data[1], TDX_VMCALL_INVALID_OPERAND); + + vcpu_run(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -1100,6 +1191,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_guest_msr_writes); run_in_new_process(&verify_guest_hlt); run_in_new_process(&verify_mmio_reads); + run_in_new_process(&verify_mmio_writes); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 979D4ECAAA1 for ; Tue, 30 Aug 2022 22:22:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232312AbiH3WWS (ORCPT ); Tue, 30 Aug 2022 18:22:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232376AbiH3WVc (ORCPT ); Tue, 30 Aug 2022 18:21:32 -0400 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 666767B294 for ; Tue, 30 Aug 2022 15:20:51 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id q128-20020a632a86000000b0042fadb61e4aso1175541pgq.3 for ; Tue, 30 Aug 2022 15:20:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=vMcvJ9jQS2E+g0S4PWnxHHd/lgPl91w8YK5lh2IoNIY=; b=jV6AN7Z+y5CcrU1zuFjC1bs4zOXiI/KNzt8q7rrE/DlpGjqcYKxo1MSZMuDsUKCGPz Xg+wdvoP7BaiKdNcuzzlXsAegakE9fl8EFQEPaImhbwAV6NZcesUVtHLUvkoCAJzwgXD k0QJGr+vksiv0kqz728ku2dXh2yxrk23a2vsm7EHM1hm+d86J/R4uXiMyK2+mV6RXDTu c4WFpu3+KVakDdVZcoJ/HLobUfjQbZd8MixJ3oq6ATLTSsBddVMOqa/ILyw7rF+Jq6pL sNWns12rd1DjHMgQVTHb7HE6U5Gysi2FWA3+kszDCPHaZTdZhPPW+beb8hBSK8uXBbha TX+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=vMcvJ9jQS2E+g0S4PWnxHHd/lgPl91w8YK5lh2IoNIY=; b=OEp8PxqTRefrpuvLZldd52sdngdAdE3nj/3GPYdUcO7kJkiADHKEhi19Cf+cpkYvVm 5JKm7XTe2eP2JWAtjzigvAyYFz8hc02263kdNLA/jAr4FBJ7p0TIMWSq9/cU/bE2Rup3 FvRsJQcrALClP9xbY30jM3LcZB2x1mPri9hFADbBTlkkOs7gmAbZyPURfipYUSIythEf 5B4nAdrda+cj+Jo7SgpaKOTYmqAiuP2ah5GH/HbDI0KLYqG9+EYkoYwFOS3ry5Zd9mwE oDLwkDAVM7d0EnMJpTllKdr9UUlWoylx2O7i9qu3TKUpdWuwqNHpc4UXv4ABMOTSe9qg +Dkw== X-Gm-Message-State: ACgBeo2usnnPU55ljN0BKx7yCfWrnAqnS1KzkCAoB0p1bgWjtW+2OiLs jFPwFwYjNTxBTXKfd7iw2Eo9b7Qj9g== X-Google-Smtp-Source: AA6agR7llbVa2geVxu4+4rCNPnonZfb8yeHEc/Ey8ehBBGcxWv7pm5z0heEP8eSlDFUnGJBumhRsFeUnmw== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:902:7048:b0:172:bc91:56b9 with SMTP id h8-20020a170902704800b00172bc9156b9mr23401051plt.125.1661898029897; Tue, 30 Aug 2022 15:20:29 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:57 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-15-sagis@google.com> Subject: [RFC PATCH v2 14/17] KVM: selftest: TDX: Add TDX CPUID TDVMCALL test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This test issues a CPUID TDVMCALL from inside the guest to get the CPUID values as seen by KVM. Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 23 ++++ .../selftests/kvm/x86_64/tdx_vm_tests.c | 102 ++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 17e3649e5729..3729543a05a3 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -56,6 +56,7 @@ =20 #define TDX_GET_TD_VM_CALL_INFO 0x10000 #define TDX_REPORT_FATAL_ERROR 0x10003 +#define TDX_INSTRUCTION_CPUID 10 #define TDX_INSTRUCTION_HLT 12 #define TDX_INSTRUCTION_IO 30 #define TDX_INSTRUCTION_RDMSR 31 @@ -347,6 +348,28 @@ static inline uint64_t tdvmcall_mmio_write(uint64_t ad= dress, uint64_t size, uint return regs.r10; } =20 +/* + * Execute CPUID instruction. + */ +static inline uint64_t tdvmcall_cpuid(uint32_t eax, uint32_t ecx, + uint32_t *ret_eax, uint32_t *ret_ebx, + uint32_t *ret_ecx, uint32_t *ret_edx) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_INSTRUCTION_CPUID; + regs.r12 =3D eax; + regs.r13 =3D ecx; + regs.rcx =3D 0xFC00; + tdcall(®s); + *ret_eax =3D regs.r12; + *ret_ebx =3D regs.r13; + *ret_ecx =3D regs.r14; + *ret_edx =3D regs.r15; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 382119bd444b..934f2f7a5df9 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -459,6 +459,107 @@ void verify_td_cpuid(void) printf("\t ... PASSED\n"); } =20 +/* + * Verifies CPUID TDVMCALL functionality. + * The guest will then send the values to userspace using an IO write to be + * checked against the expected values. + */ +TDX_GUEST_FUNCTION(guest_code_cpuid_tdcall) +{ + uint64_t err; + uint32_t eax, ebx, ecx, edx; + + // Read CPUID leaf 0x1 from host. + err =3D tdvmcall_cpuid(/*eax=3D*/1, /*ecx=3D*/0, &eax, &ebx, &ecx, &edx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_to_user_space(eax); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_to_user_space(ebx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_to_user_space(ecx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_to_user_space(edx); + if (err) + tdvmcall_fatal(err); + + tdvmcall_success(); +} + +void verify_td_cpuid_tdcall(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint32_t eax, ebx, ecx, edx; + struct kvm_cpuid_entry2 *cpuid_entry; + struct tdx_cpuid_data cpuid_data; + int ret; + + printf("Verifying TD CPUID TDVMCALL:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory.*/ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_code_cpuid_tdcall, + TDX_FUNCTION_SIZE(guest_code_cpuid_tdcall), 0); + finalize_td_memory(vm); + + /* Wait for guest to report CPUID values */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + eax =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + ebx =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + ecx =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE); + edx =3D *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + /* Get KVM CPUIDs for reference */ + memset(&cpuid_data, 0, sizeof(cpuid_data)); + cpuid_data.cpuid.nent =3D KVM_MAX_CPUID_ENTRIES; + ret =3D ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data); + TEST_ASSERT(!ret, "KVM_GET_SUPPORTED_CPUID failed\n"); + cpuid_entry =3D find_cpuid_entry(cpuid_data, 1, 0); + TEST_ASSERT(cpuid_entry, "CPUID entry missing\n"); + + ASSERT_EQ(cpuid_entry->eax, eax); + // Mask lapic ID when comparing ebx. + ASSERT_EQ(cpuid_entry->ebx & ~0xFF000000, ebx & ~0xFF000000); + ASSERT_EQ(cpuid_entry->ecx, ecx); + ASSERT_EQ(cpuid_entry->edx, edx); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + /* * Verifies get_td_vmcall_info functionality. */ @@ -1184,6 +1285,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_report_fatal_error); run_in_new_process(&verify_td_ioexit); run_in_new_process(&verify_td_cpuid); + run_in_new_process(&verify_td_cpuid_tdcall); run_in_new_process(&verify_get_td_vmcall_info); run_in_new_process(&verify_guest_writes); run_in_new_process(&verify_guest_reads); --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0919ECAAA1 for ; Tue, 30 Aug 2022 22:22:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232059AbiH3WWX (ORCPT ); Tue, 30 Aug 2022 18:22:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231801AbiH3WVy (ORCPT ); Tue, 30 Aug 2022 18:21:54 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E61D982D2E for ; Tue, 30 Aug 2022 15:20:56 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id 125-20020a621483000000b0053814ac4b8bso3400638pfu.16 for ; Tue, 30 Aug 2022 15:20:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=2AzASQeU88APEljBXBn0RNVGXW+shwwgUtawD6/ADN8=; b=XxqBa5YUPEuIofhtRPgfQP1Gp7yJBPrhB27iJVTj5hKg2qUgSwojvxOwPl1mqNddVk EvLfXqPC7nzUVlzuvW0kzXSJdPKfu576AOZ5UZcRRd44IzixhkQfNSVGLTbFEsotJ7lH w3kaELzdP+sFBMynBIe9kYmybdDrc3m8ps34xZ5UhYxfLTX0FN/ZbNvQOunYsj/1WVry PC8RvwlhuKpik45jWpSrhGU/4j/BmLkbdRUaMDB4p42YF9ICdlsSwc+afhYAIpKsHdVF dW2yEJqpRTTGVXnkT+Ps0wMPO1gfjvZxwFJXci6mZ2WCAg9f0kkjjIbF/j3X/dSTmaYl RgJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=2AzASQeU88APEljBXBn0RNVGXW+shwwgUtawD6/ADN8=; b=55GLCW+8OnzQ14EES+LghfdLEqtkBnrlWyKLx6wROF8bxm4oeAhC8nArAK7FwtPbQh OhCwCA/ih7KEvpgx5OfNI1xcqiFARIOhhejUpcWw6T3IwiGR4s0W6AMaP3foC7khOQXX OkNAkbdkApukjq2cRhKctkh7JwBJe6chcs/PSvUbHmu2FSVN+4lLpq9SzgyXbeRJN2IA QEXtG6NkCTmihHWZiAsjbUe4/j+LPP4am9KuNSbyXPRKvIjDIgcwNEOhcZtHbXDy3Rgk ca33V9gERUqWtSrhH9xWKjh5bBA5o0ssht/FEnWGxzofz3s/14MMRVHak4uNVURZRaoq YiDg== X-Gm-Message-State: ACgBeo17sRByW4khjik5zZ6iRUetwmiwRi+kR1Oj40p7upgIxwmPpAuw ORB+MxHqZTD1yccg9Ix6JqRYyM3/RA== X-Google-Smtp-Source: AA6agR7m/uiWOU0X1ALpMi8LPsl7IheXdMIzK8T+7BYvKoXpERL9W/YFwQ3v9zngVlKofPdPkx5efJAG2Q== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:acc:b0:530:e79e:fc27 with SMTP id c12-20020a056a000acc00b00530e79efc27mr23466087pfl.61.1661898031820; Tue, 30 Aug 2022 15:20:31 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:58 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-16-sagis@google.com> Subject: [RFC PATCH v2 15/17] KVM: selftest: TDX: Verify the behavior when host consumes a TD private memory From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ryan Afranji The test checks that host can only read fixed values when trying to access the guest's private memory. Signed-off-by: Ryan Afranji Signed-off-by: Sagi Shahar --- .../selftests/kvm/x86_64/tdx_vm_tests.c | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 934f2f7a5df9..1776b39b7d9e 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -1274,6 +1274,98 @@ void verify_mmio_writes(void) printf("\t ... PASSED\n"); } =20 +TDX_GUEST_FUNCTION(guest_host_read_priv_mem) +{ + uint64_t guest_var =3D 0xABCD; + uint64_t ret; + + /* Sends address to host. */ + ret =3D tdvm_report_64bit_to_user_space((uint64_t)&guest_var); + if (ret) + tdvmcall_fatal(ret); + + /* Update guest_var's value and have host reread it. */ + guest_var =3D 0xFEDC; + + tdvmcall_success(); +} + +void verify_host_reading_private_mem(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct userspace_mem_region *region; + uint64_t guest_var_addr; + uint64_t host_virt; + uint64_t first_host_read; + uint64_t second_host_read; + int ctr; + + printf("Verifying host's behavior when reading TD private memory:\n"); + /* Create a TD VM with no memory. */ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD. */ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory. */ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Setup and initialize VM memory. */ + prepare_source_image(vm, guest_host_read_priv_mem, + TDX_FUNCTION_SIZE(guest_host_read_priv_mem), 0); + finalize_td_memory(vm); + + /* Get the address of the guest's variable. */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + printf("\t ... Guest's variable contains 0xABCD\n"); + + /* Guest virtual and guest physical addresses have 1:1 mapping. */ + guest_var_addr =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Search for the guest's address in guest's memory regions. */ + host_virt =3D 0; + hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) { + uint64_t offset; + uint64_t host_virt_base; + uint64_t guest_base; + + guest_base =3D (uint64_t)region->region.guest_phys_addr; + offset =3D guest_var_addr - guest_base; + + if (guest_base <=3D guest_var_addr && + offset <=3D region->region.memory_size) { + host_virt_base =3D (uint64_t)region->host_mem; + host_virt =3D host_virt_base + offset; + break; + } + } + TEST_ASSERT(host_virt !=3D 0, + "Guest address not found in guest memory regions\n"); + + /* Host reads guest's variable. */ + first_host_read =3D *(uint64_t *)host_virt; + printf("\t ... Host's read attempt value: %lu\n", first_host_read); + + /* Guest updates variable and host rereads it. */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + printf("\t ... Guest's variable updated to 0xFEDC\n"); + + second_host_read =3D *(uint64_t *)host_virt; + printf("\t ... Host's second read attempt value: %lu\n", + second_host_read); + + TEST_ASSERT(first_host_read =3D=3D second_host_read, + "Host did not read a fixed pattern\n"); + + printf("\t ... Fixed pattern was returned to the host\n"); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -1294,6 +1386,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_guest_hlt); run_in_new_process(&verify_mmio_reads); run_in_new_process(&verify_mmio_writes); + run_in_new_process(&verify_host_reading_private_mem); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A5DCECAAD4 for ; Tue, 30 Aug 2022 22:22:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231941AbiH3WWh (ORCPT ); Tue, 30 Aug 2022 18:22:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56496 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232281AbiH3WV5 (ORCPT ); Tue, 30 Aug 2022 18:21:57 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B4A468307D for ; Tue, 30 Aug 2022 15:20:59 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id 125-20020a621483000000b0053814ac4b8bso3400655pfu.16 for ; Tue, 30 Aug 2022 15:20:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=zd+lBScqnSmkIetLC1xR4dudPj5a700X/6NrBlSgAV4=; b=ET5No9KOQARFFK18hAOs093fKjXxVroc6nLNGj2YcF5XnW5vp4KG7BMHABT3lvRkys pfcLwV/CjF9DMORwkMQghxC6FjPEk3/jq0Ew5hs/MwfGWZsYNaOE0oHaufvVrEQeo569 hJSw8//FeEyvOm0pZcf6MlA/u9hOGhHMk5hip7rFr/OrGgMsGnG9vfKcF8/7EOR+w0QI ZeAIg4uworipwrLCrej+fyLhv5V1O8psD/t2XZnlObKRo9Dn/hVDoA/awOceWqrzLz09 JnyetQF7n21GylCr13ssH7SFgct8iPEYG27cyc+5FvWQiXM1zEyt+NIVoP6x/huPjdnQ JhGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=zd+lBScqnSmkIetLC1xR4dudPj5a700X/6NrBlSgAV4=; b=UnITbPVqVHwJM2KW1j6XlTW+RvmpWDSciw/DB8hdfEBHLacttOe9rbEQNdaBMoPxMR oZ634KuxzQxJ9TTwyXJ2pR06aF+UhnFlpK1DdTF9zTWVVHNde/AKr3QB28WLT620nDP5 QybXMpIsLdTWocNKQMyAINBBDbh/bRRsxXbkKmKuW5Ro9U9PEkYLaUx4K+dUqrGa+sA2 pusPNJ6X60B8fGmuJmm4x6ZC/vzTTWfQ7MW/+E9iLCMG5B7qAiR7FCQ5lzY9CDwjzex3 3Ej7lykYs1u4ZbS6M3+t984Al4TTim332RKdPmtuqwKrocYDn9JiPQoxIXGblWgh1Jfp brkw== X-Gm-Message-State: ACgBeo0BJ+fHmdLjE8lC/pteDdgb6KFALgSm0QUWRo/lfibPnaYCpeGL 0jJM7gbrwdKLXVe4Q9hBfl95TJ20qg== X-Google-Smtp-Source: AA6agR7l+9nzCrkMd2h5pdfU7qg8qiGZHLUMkG4txvqEY4nDBo+Jb6sEYsb5hHykvJHBJQ7xBXLtiptpiw== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a17:90a:738a:b0:1fa:d930:49d1 with SMTP id j10-20020a17090a738a00b001fad93049d1mr177774pjg.130.1661898033307; Tue, 30 Aug 2022 15:20:33 -0700 (PDT) Date: Tue, 30 Aug 2022 22:19:59 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-17-sagis@google.com> Subject: [RFC PATCH v2 16/17] KVM: selftest: TDX: Add TDG.VP.INFO test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Roger Wang Adds a test for TDG.VP.INFO Signed-off-by: Roger Wang Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 103 ++++++++---- .../selftests/kvm/lib/x86_64/tdx_lib.c | 18 ++- .../selftests/kvm/x86_64/tdx_vm_tests.c | 150 ++++++++++++++++++ 3 files changed, 235 insertions(+), 36 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 3729543a05a3..7af2d189043f 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -10,6 +10,11 @@ */ #define TDX_GUEST_MAX_NR_PAGES 10000 =20 +/* + * Max number of vCPUs for the guest VM + */ + #define TDX_GUEST_MAX_NUM_VCPUS 3 + /* * Page Table Address used when paging is enabled. */ @@ -71,6 +76,11 @@ #define TDX_MMIO_READ 0 #define TDX_MMIO_WRITE 1 =20 +#define TDX_TDCALL_INFO 1 + +#define TDX_TDPARAM_ATTR_SEPT_VE_DISABLE_BIT (1UL << 28) +#define TDX_TDPARAM_ATTR_PKS_BIT (1UL << 30) + #define GDT_ENTRY(flags, base, limit) \ ((((base) & 0xff000000ULL) << (56-24)) | \ (((flags) & 0x0000f0ffULL) << 40) | \ @@ -98,6 +108,7 @@ void add_td_memory(struct kvm_vm *vm, void *source_page, uint64_t gpa, int size); void finalize_td_memory(struct kvm_vm *vm); void initialize_td(struct kvm_vm *vm); +void initialize_td_with_attributes(struct kvm_vm *vm, uint64_t attributes); void initialize_td_vcpu(struct kvm_vcpu *vcpu); void prepare_source_image(struct kvm_vm *vm, void *guest_code, size_t guest_code_size, @@ -116,40 +127,41 @@ void prepare_source_image(struct kvm_vm *vm, void *gu= est_code, static inline void tdcall(struct kvm_regs *regs) { asm volatile ( - "mov %13, %%rax;\n\t" - "mov %14, %%rbx;\n\t" - "mov %15, %%rcx;\n\t" - "mov %16, %%rdx;\n\t" - "mov %17, %%r8;\n\t" - "mov %18, %%r9;\n\t" - "mov %19, %%r10;\n\t" - "mov %20, %%r11;\n\t" - "mov %21, %%r12;\n\t" - "mov %22, %%r13;\n\t" - "mov %23, %%r14;\n\t" - "mov %24, %%r15;\n\t" - "mov %25, %%rbp;\n\t" - "mov %26, %%rsi;\n\t" - "mov %27, %%rdi;\n\t" + "mov %14, %%rax;\n\t" + "mov %15, %%rbx;\n\t" + "mov %16, %%rcx;\n\t" + "mov %17, %%rdx;\n\t" + "mov %18, %%r8;\n\t" + "mov %19, %%r9;\n\t" + "mov %20, %%r10;\n\t" + "mov %21, %%r11;\n\t" + "mov %22, %%r12;\n\t" + "mov %23, %%r13;\n\t" + "mov %24, %%r14;\n\t" + "mov %25, %%r15;\n\t" + "mov %26, %%rbp;\n\t" + "mov %27, %%rsi;\n\t" + "mov %28, %%rdi;\n\t" ".byte 0x66, 0x0F, 0x01, 0xCC;\n\t" "mov %%rax, %0;\n\t" "mov %%rbx, %1;\n\t" - "mov %%rdx, %2;\n\t" - "mov %%r8, %3;\n\t" - "mov %%r9, %4;\n\t" - "mov %%r10, %5;\n\t" - "mov %%r11, %6;\n\t" - "mov %%r12, %7;\n\t" - "mov %%r13, %8;\n\t" - "mov %%r14, %9;\n\t" - "mov %%r15, %10;\n\t" - "mov %%rsi, %11;\n\t" - "mov %%rdi, %12;\n\t" - : "=3Dm" (regs->rax), "=3Dm" (regs->rbx), "=3Dm" (regs->rdx), - "=3Dm" (regs->r8), "=3Dm" (regs->r9), "=3Dm" (regs->r10), - "=3Dm" (regs->r11), "=3Dm" (regs->r12), "=3Dm" (regs->r13), - "=3Dm" (regs->r14), "=3Dm" (regs->r15), "=3Dm" (regs->rsi), - "=3Dm" (regs->rdi) + "mov %%rcx, %2;\n\t" + "mov %%rdx, %3;\n\t" + "mov %%r8, %4;\n\t" + "mov %%r9, %5;\n\t" + "mov %%r10, %6;\n\t" + "mov %%r11, %7;\n\t" + "mov %%r12, %8;\n\t" + "mov %%r13, %9;\n\t" + "mov %%r14, %10;\n\t" + "mov %%r15, %11;\n\t" + "mov %%rsi, %12;\n\t" + "mov %%rdi, %13;\n\t" + : "=3Dm" (regs->rax), "=3Dm" (regs->rbx), "=3Dm" (regs->rcx), + "=3Dm" (regs->rdx), "=3Dm" (regs->r8), "=3Dm" (regs->r9), + "=3Dm" (regs->r10), "=3Dm" (regs->r11), "=3Dm" (regs->r12), + "=3Dm" (regs->r13), "=3Dm" (regs->r14), "=3Dm" (regs->r15), + "=3Dm" (regs->rsi), "=3Dm" (regs->rdi) : "m" (regs->rax), "m" (regs->rbx), "m" (regs->rcx), "m" (regs->rdx), "m" (regs->r8), "m" (regs->r9), "m" (regs->r10), "m" (regs->r11), "m" (regs->r12), @@ -370,6 +382,35 @@ static inline uint64_t tdvmcall_cpuid(uint32_t eax, ui= nt32_t ecx, return regs.r10; } =20 +/* + * Execute TDG.VP.INFO instruction. + */ +static inline uint64_t tdcall_vp_info(uint64_t *rcx, uint64_t *rdx, + uint64_t *r8, uint64_t *r9, + uint64_t *r10, uint64_t *r11) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.rax =3D TDX_TDCALL_INFO; + tdcall(®s); + + if (rcx) + *rcx =3D regs.rcx; + if (rdx) + *rdx =3D regs.rdx; + if (r8) + *r8 =3D regs.r8; + if (r9) + *r9 =3D regs.r9; + if (r10) + *r10 =3D regs.r10; + if (r11) + *r11 =3D regs.r11; + + return regs.rax; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c b/tools/testi= ng/selftests/kvm/lib/x86_64/tdx_lib.c index 72bf2ff24a29..dc9a44ae4064 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c @@ -78,10 +78,10 @@ static struct tdx_cpuid_data get_tdx_cpuid_data(struct = kvm_vm *vm) } =20 /* - * Initialize a VM as a TD. + * Initialize a VM as a TD with attributes. * */ -void initialize_td(struct kvm_vm *vm) +void initialize_td_with_attributes(struct kvm_vm *vm, uint64_t attributes) { struct tdx_cpuid_data cpuid_data; int rc; @@ -99,7 +99,7 @@ void initialize_td(struct kvm_vm *vm) KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK); vm_enable_cap(vm, KVM_CAP_SPLIT_IRQCHIP, 24); =20 - /* Allocate and setup memoryfor the td guest. */ + /* Allocate and setup memory for the td guest. */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, TDX_GUEST_PT_FIXED_ADDR, 0, TDX_GUEST_MAX_NR_PAGES, 0); @@ -108,12 +108,20 @@ void initialize_td(struct kvm_vm *vm) =20 cpuid_data =3D get_tdx_cpuid_data(vm); =20 - init_vm.max_vcpus =3D 1; - init_vm.attributes =3D 0; + init_vm.max_vcpus =3D TDX_GUEST_MAX_NUM_VCPUS; + init_vm.attributes =3D attributes; memcpy(&init_vm.cpuid, &cpuid_data, sizeof(cpuid_data)); tdx_ioctl(vm->fd, KVM_TDX_INIT_VM, 0, &init_vm); } =20 +/* + * Initialize a VM as a TD with no attributes. + * + */ +void initialize_td(struct kvm_vm *vm) +{ + initialize_td_with_attributes(vm, 0); +} =20 void initialize_td_vcpu(struct kvm_vcpu *vcpu) { diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 1776b39b7d9e..8d49099e1ed8 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 @@ =20 #include "asm/kvm.h" #include "linux/kernel.h" +#include #include #include #include @@ -1366,6 +1367,154 @@ void verify_host_reading_private_mem(void) printf("\t ... PASSED\n"); } =20 +/* + * Do a TDG.VP.INFO call from the guest + */ +TDX_GUEST_FUNCTION(guest_tdcall_vp_info) +{ + uint64_t err; + uint64_t rcx, rdx, r8, r9, r10, r11; + + err =3D tdcall_vp_info(&rcx, &rdx, &r8, &r9, &r10, &r11); + if (err) + tdvmcall_fatal(err); + + /* return values to user space host */ + err =3D tdvm_report_64bit_to_user_space(rcx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(rdx); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r8); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r9); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r10); + if (err) + tdvmcall_fatal(err); + + err =3D tdvm_report_64bit_to_user_space(r11); + if (err) + tdvmcall_fatal(err); + + tdvmcall_success(); +} + +/* + * TDG.VP.INFO call from the guest. Verify the right values are returned + */ +void verify_tdcall_vp_info(void) +{ + const int num_vcpus =3D 2; + struct kvm_vcpu *vcpus[num_vcpus]; + struct kvm_vm *vm; + uint64_t rcx, rdx, r8, r9, r10, r11; + uint32_t ret_num_vcpus, ret_max_vcpus; + uint64_t attributes; + uint32_t i; + struct kvm_cpuid_entry2 *cpuid_entry; + struct tdx_cpuid_data cpuid_data; + int max_pa =3D -1; + int ret; + + printf("Verifying TDG.VP.INFO call:\n"); + /* Create a TD VM with no memory.*/ + vm =3D vm_create_tdx(); + + /* Setting attributes parameter used by TDH.MNG.INIT to 0x50000000 */ + attributes =3D TDX_TDPARAM_ATTR_SEPT_VE_DISABLE_BIT | + TDX_TDPARAM_ATTR_PKS_BIT; + + /* Allocate TD guest memory and initialize the TD.*/ + initialize_td_with_attributes(vm, attributes); + + /* Create vCPUs*/ + for (i =3D 0; i < num_vcpus; i++) + vcpus[i] =3D vm_vcpu_add_tdx(vm, i); + + /* Setup and initialize VM memory */ + prepare_source_image(vm, guest_tdcall_vp_info, + TDX_FUNCTION_SIZE(guest_tdcall_vp_info), 0); + finalize_td_memory(vm); + + /* Get KVM CPUIDs for reference */ + memset(&cpuid_data, 0, sizeof(cpuid_data)); + cpuid_data.cpuid.nent =3D KVM_MAX_CPUID_ENTRIES; + ret =3D ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data); + TEST_ASSERT(!ret, "KVM_GET_SUPPORTED_CPUID failed\n"); + cpuid_entry =3D find_cpuid_entry(cpuid_data, 0x80000008, 0); + TEST_ASSERT(cpuid_entry, "CPUID entry missing\n"); + max_pa =3D cpuid_entry->eax & 0xff; + + for (i =3D 0; i < num_vcpus; i++) { + struct kvm_vcpu *vcpu =3D vcpus[i]; + + /* Wait for guest to report rcx value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + rcx =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report rdx value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + rdx =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r8 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r8 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r9 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r9 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r10 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r10 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Wait for guest to report r11 value */ + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + r11 =3D read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + ret_num_vcpus =3D r8 & 0xFFFFFFFF; + ret_max_vcpus =3D (r8 >> 32) & 0xFFFFFFFF; + + /* first bits 5:0 of rcx represent the GPAW */ + ASSERT_EQ(rcx & 0x3F, max_pa); + /* next 63:6 bits of rcx is reserved and must be 0 */ + ASSERT_EQ(rcx >> 6, 0); + ASSERT_EQ(rdx, attributes); + ASSERT_EQ(ret_num_vcpus, num_vcpus); + ASSERT_EQ(ret_max_vcpus, TDX_GUEST_MAX_NUM_VCPUS); + /* VCPU_INDEX =3D i */ + ASSERT_EQ(r9, i); + /* verify reserved registers are 0 */ + ASSERT_EQ(r10, 0); + ASSERT_EQ(r11, 0); + + /* Wait for guest to complete execution */ + vcpu_run(vcpu); + + CHECK_GUEST_FAILURE(vcpu); + CHECK_GUEST_COMPLETION(vcpu); + + printf("\t ... Guest completed run on VCPU=3D%u\n", i); + } + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -1387,6 +1536,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_mmio_reads); run_in_new_process(&verify_mmio_writes); run_in_new_process(&verify_host_reading_private_mem); + run_in_new_process(&verify_tdcall_vp_info); =20 return 0; } --=20 2.37.2.789.g6183377224-goog From nobody Tue Apr 7 04:18:37 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5B23AECAAD4 for ; Tue, 30 Aug 2022 22:21:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231906AbiH3WVs (ORCPT ); Tue, 30 Aug 2022 18:21:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231940AbiH3WVN (ORCPT ); Tue, 30 Aug 2022 18:21:13 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D290F5F9BF for ; Tue, 30 Aug 2022 15:20:35 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id i1-20020a170902cf0100b001730caeec78so8655974plg.7 for ; Tue, 30 Aug 2022 15:20:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date; bh=AzDgZBgFplUyYkteDiAFd4snp6/vsyrTsM86sz6yvPk=; b=oyUkqckUdLsL5ggmZbJj+/O1xqCczSWPMKvRE8ocdVgkeAZFayetIhhOe44TGpaLql ReZ149//ZWno+R6jcV3voWkq4A5b+eDmxLN5bzhJhvPYNIFlg9bor3UQmG/QjWaULZTz coYkgMTzQol2T7/dgQMPD1VePwLVC/50IgmlElxIveOAXEQtCK9aKN/L5P89G3MOi/LC Afa3y0Bdp5ncs6BijVBN+Zt6cVaAqghhmYC4OVXKyk6CKVmjiIsRVsJABLObRS1/OQWY w3X5Rt+1SXUmcSRyLW9RezJQkIhnSTSPOVJFitZjCWB4+XG/GY2Q32BsGVMojvcpvTNc 90jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date; bh=AzDgZBgFplUyYkteDiAFd4snp6/vsyrTsM86sz6yvPk=; b=4MUMP8iDfPWy6I6r7NZxdWLe71D8stndVEYz/9ieRQpJyXrZUcmEY58T0gI1bDKmD+ guytpJ+fJL/uZhAuOQ5YLltUFYHZN3MPQEYmaGdWvho95APOnTFCstsqYYR1uHoA6/Kd oTSbduLTSPY2OnyBVgCd9Ciap6PmSd9yvDOCE0DC96n8Eo6e8fA/75LhjyQbHp2fAJ2b fIU6zmE+V8jqd7ygfmvOpyKZ0Ro50xSxqjvMYBx/asBGzyL3T2k5iBpukvKJBMLwK7r1 7+WqlmJ42ylF7vDll6SACKmK6ni5rYcZ8zEOixJv79uRgYGuJBV7mIqcbeCb7SwLNLMT JZYQ== X-Gm-Message-State: ACgBeo152BKTBpozCXL7+tVDAibN6RMUhadMWkdSYJblNwZGHutv7dNZ 6KK+JUSwgSn67WvLFGOhvb/T12w0Kg== X-Google-Smtp-Source: AA6agR4dolB76RWxR4Csigjf13X6+PTxv/agrCvSqBIs9UDI2TG+UKkBY4FJGdwS0vCvT+Rxs05FTlGBIQ== X-Received: from sagi.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:241b]) (user=sagis job=sendgmr) by 2002:a05:6a00:e8a:b0:535:cc5c:3d87 with SMTP id bo10-20020a056a000e8a00b00535cc5c3d87mr23494953pfb.24.1661898035202; Tue, 30 Aug 2022 15:20:35 -0700 (PDT) Date: Tue, 30 Aug 2022 22:20:00 +0000 In-Reply-To: <20220830222000.709028-1-sagis@google.com> Mime-Version: 1.0 References: <20220830222000.709028-1-sagis@google.com> X-Mailer: git-send-email 2.37.2.789.g6183377224-goog Message-ID: <20220830222000.709028-18-sagis@google.com> Subject: [RFC PATCH v2 17/17] KVM: selftest: TDX: Add shared memory test From: Sagi Shahar To: linux-kselftest@vger.kernel.org Cc: Paolo Bonzini , Sean Christopherson , Isaku Yamahata , Sagi Shahar , Erdem Aktas , Ryan Afranji , Roger Wang , Shuah Khan , Andrew Jones , Marc Zyngier , Ben Gardon , Jim Mattson , David Matlack , Peter Xu , Oliver Upton , Ricardo Koller , Yang Zhong , Wei Wang , Xiaoyao Li , Peter Gonda , Marc Orr , Emanuele Giuseppe Esposito , Christian Borntraeger , Eric Auger , Yanan Wang , Aaron Lewis , Vitaly Kuznetsov , Peter Shier , Axel Rasmussen , Zhenzhong Duan , "Maciej S . Szmigiero" , Like Xu , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Ryan Afranji Adds a test that sets up shared memory between the host and guest. Signed-off-by: Ryan Afranji Signed-off-by: Sagi Shahar --- tools/testing/selftests/kvm/lib/x86_64/tdx.h | 38 +++++- .../selftests/kvm/lib/x86_64/tdx_lib.c | 41 +++++- .../selftests/kvm/x86_64/tdx_vm_tests.c | 124 ++++++++++++++++++ 3 files changed, 192 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/s= elftests/kvm/lib/x86_64/tdx.h index 7af2d189043f..be8564f4672d 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h @@ -23,10 +23,21 @@ =20 /* * Max Page Table Size - * To map 4GB memory region with 2MB pages, there needs to be 1 page for P= ML4, - * 1 Page for PDPT, 4 pages for PD. Reserving 6 pages for PT. + * To map 4GB memory regions for each private and shared memory with 2MB p= ages, + * there needs to be 1 page for PML4, 1 Page for PDPT, 8 pages for PD. Res= erving + * 10 pages for PT. */ -#define TDX_GUEST_NR_PT_PAGES (1 + 1 + 4) +#define TDX_GUEST_NR_PT_PAGES (1 + 1 + 8) + +/* + * Guest Virtual Address Shared Bit + * TDX's shared bit is defined as the highest order bit in the GPA. Since = the + * highest order bit allowed in the GPA may exceed the GVA's, a 1:1 mapping + * cannot be applied for shared memory. This value is a bit within the ran= ge + * [32 - 38] (0-indexed) that will designate a 4 GB region of GVAs that ma= p the + * shared GPAs. This approach does not increase number of PML4 and PDPT pa= ges. + */ +#define TDX_GUEST_VIRT_SHARED_BIT 32 =20 /* * Predefined GDTR values. @@ -60,6 +71,7 @@ #define TDX_VMCALL_INVALID_OPERAND 0x8000000000000000 =20 #define TDX_GET_TD_VM_CALL_INFO 0x10000 +#define TDX_MAP_GPA 0x10001 #define TDX_REPORT_FATAL_ERROR 0x10003 #define TDX_INSTRUCTION_CPUID 10 #define TDX_INSTRUCTION_HLT 12 @@ -101,7 +113,7 @@ struct __packed tdx_gdtr { struct page_table { uint64_t pml4[512]; uint64_t pdpt[512]; - uint64_t pd[4][512]; + uint64_t pd[8][512]; }; =20 void add_td_memory(struct kvm_vm *vm, void *source_page, @@ -411,6 +423,24 @@ static inline uint64_t tdcall_vp_info(uint64_t *rcx, u= int64_t *rdx, return regs.rax; } =20 +/* + * Execute MapGPA instruction. + */ +static inline uint64_t tdvmcall_map_gpa(uint64_t address, uint64_t size, + uint64_t *data_out) +{ + struct kvm_regs regs; + + memset(®s, 0, sizeof(regs)); + regs.r11 =3D TDX_MAP_GPA; + regs.r12 =3D address; + regs.r13 =3D size; + regs.rcx =3D 0x3C00; + tdcall(®s); + *data_out =3D regs.r11; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO cal= l. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c b/tools/testi= ng/selftests/kvm/lib/x86_64/tdx_lib.c index dc9a44ae4064..23893949c3a1 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c @@ -183,29 +183,56 @@ void build_gdtr_table(void *gdtr_target, void *gdt_ta= rget) * which will be used by the TDX guest when paging is enabled. * TODO: use virt_pg_map() functions to dynamically allocate the page tabl= es. */ -void build_page_tables(void *pt_target, uint64_t pml4_base_address) +void build_page_tables(void *pt_target, uint64_t pml4_base_address, + uint64_t gpa_shared_bit) { uint64_t i; + uint64_t shared_pdpt_index; + uint64_t gpa_shared_mask; + uint64_t *pde; struct page_table *pt; =20 pt =3D malloc(sizeof(struct page_table)); TEST_ASSERT(pt !=3D NULL, "Could not allocate memory for page tables!\n"); memset((void *) &(pt->pml4[0]), 0, sizeof(pt->pml4)); memset((void *) &(pt->pdpt[0]), 0, sizeof(pt->pdpt)); - for (i =3D 0; i < 4; i++) + for (i =3D 0; i < 8; i++) memset((void *) &(pt->pd[i][0]), 0, sizeof(pt->pd[i])); =20 + /* Populate pml4 entry. */ pt->pml4[0] =3D (pml4_base_address + PAGE_SIZE) | _PAGE_PRESENT | _PAGE_RW; + + /* Populate pdpt entries for private memory region. */ for (i =3D 0; i < 4; i++) pt->pdpt[i] =3D (pml4_base_address + (i + 2) * PAGE_SIZE) | - _PAGE_PRESENT | _PAGE_RW; + _PAGE_PRESENT | _PAGE_RW; + + /* Index used in pdpt #0 to map to pd with guest virt shared bit set. */ + static_assert(TDX_GUEST_VIRT_SHARED_BIT >=3D 32 && + TDX_GUEST_VIRT_SHARED_BIT <=3D 38, + "Guest virtual shared bit must be in the range [32 - 38].\n"); + shared_pdpt_index =3D 1 << (TDX_GUEST_VIRT_SHARED_BIT - 30); =20 - uint64_t *pde =3D &(pt->pd[0][0]); + /* Populate pdpt entries for shared memory region. */ + for (i =3D 0; i < 4; i++) + pt->pdpt[shared_pdpt_index + i] =3D (pml4_base_address + (i + 6) * + PAGE_SIZE) | _PAGE_PRESENT | + _PAGE_RW; =20 - for (i =3D 0; i < sizeof(pt->pd) / sizeof(pt->pd[0][0]); i++, pde++) + /* Populate pd entries for private memory region. */ + pde =3D &(pt->pd[0][0]); + for (i =3D 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++) *pde =3D (i << 21) | _PAGE_PRESENT | _PAGE_RW | _PAGE_PS; - memcpy(pt_target, pt, 6 * PAGE_SIZE); + + /* Populate pd entries for shared memory region; set shared bit. */ + pde =3D &(pt->pd[4][0]); + gpa_shared_mask =3D BIT_ULL(gpa_shared_bit); + for (i =3D 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++) + *pde =3D gpa_shared_mask | (i << 21) | _PAGE_PRESENT | _PAGE_RW | + _PAGE_PS; + + memcpy(pt_target, pt, 10 * PAGE_SIZE); } =20 static void @@ -318,7 +345,7 @@ void prepare_source_image(struct kvm_vm *vm, void *gues= t_code, guest_code_base =3D gdt_address + (TDX_GUEST_STACK_NR_PAGES * PAGE_SIZE); =20 - build_page_tables(pt_address, TDX_GUEST_PT_FIXED_ADDR); + build_page_tables(pt_address, TDX_GUEST_PT_FIXED_ADDR, vm->pa_bits - 1); build_gdtr_table(gdtr_address, gdt_address); =20 /* reset vector code should end with int3 instructions. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/test= ing/selftests/kvm/x86_64/tdx_vm_tests.c index 8d49099e1ed8..a96abada54b6 100644 --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c @@ -1515,6 +1515,129 @@ void verify_tdcall_vp_info(void) printf("\t ... PASSED\n"); } =20 +TDX_GUEST_FUNCTION(guest_shared_mem) +{ + uint64_t gpa_shared_mask; + uint64_t gva_shared_mask; + uint64_t shared_gpa; + uint64_t shared_gva; + uint64_t gpa_width; + uint64_t failed_gpa; + uint64_t ret; + uint64_t err; + + gva_shared_mask =3D BIT_ULL(TDX_GUEST_VIRT_SHARED_BIT); + shared_gpa =3D 0x80000000; + shared_gva =3D gva_shared_mask | shared_gpa; + + /* Read highest order physical bit to calculate shared mask. */ + err =3D tdcall_vp_info(&gpa_width, 0, 0, 0, 0, 0); + if (err) + tdvmcall_fatal(err); + + /* Map gpa as shared. */ + gpa_shared_mask =3D BIT_ULL(gpa_width - 1); + ret =3D tdvmcall_map_gpa(shared_gpa | gpa_shared_mask, PAGE_SIZE, + &failed_gpa); + if (ret) + tdvmcall_fatal(ret); + + /* Write to shared memory. */ + *(uint16_t *)shared_gva =3D 0x1234; + tdvmcall_success(); + + /* Read from shared memory; report to host. */ + ret =3D tdvmcall_io(TDX_TEST_PORT, 2, TDX_IO_WRITE, + (uint64_t *)shared_gva); + if (ret) + tdvmcall_fatal(ret); + + tdvmcall_success(); +} + +void verify_shared_mem(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct userspace_mem_region *region; + uint16_t guest_read_val; + uint64_t shared_gpa; + uint64_t shared_hva; + uint64_t shared_pages_num; + int ctr; + + printf("Verifying shared memory\n"); + + /* Create a TD VM with no memory. */ + vm =3D vm_create_tdx(); + + /* Allocate TD guest memory and initialize the TD. */ + initialize_td(vm); + + /* Initialize the TD vcpu and copy the test code to the guest memory. */ + vcpu =3D vm_vcpu_add_tdx(vm, 0); + + /* Allocate shared memory. */ + shared_gpa =3D 0x80000000; + shared_pages_num =3D 1; + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + shared_gpa, 1, + shared_pages_num, 0); + + /* Setup and initialize VM memory. */ + prepare_source_image(vm, guest_shared_mem, + TDX_FUNCTION_SIZE(guest_shared_mem), 0); + finalize_td_memory(vm); + + /* Begin guest execution; guest writes to shared memory. */ + printf("\t ... Starting guest execution\n"); + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + + /* Get the host's shared memory address. */ + shared_hva =3D 0; + hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) { + uint64_t region_guest_addr; + + region_guest_addr =3D (uint64_t)region->region.guest_phys_addr; + if (region_guest_addr =3D=3D (shared_gpa)) { + shared_hva =3D (uint64_t)region->host_mem; + break; + } + } + TEST_ASSERT(shared_hva !=3D 0, + "Guest address not found in guest memory regions\n"); + + /* Verify guest write -> host read succeeds. */ + printf("\t ... Guest wrote 0x1234 to shared memory\n"); + if (*(uint16_t *)shared_hva !=3D 0x1234) { + printf("\t ... FAILED: Host read 0x%x instead of 0x1234\n", + *(uint16_t *)shared_hva); + } + printf("\t ... Host read 0x%x from shared memory\n", + *(uint16_t *)shared_hva); + + /* Verify host write -> guest read succeeds. */ + *((uint16_t *)shared_hva) =3D 0xABCD; + printf("\t ... Host wrote 0xabcd to shared memory\n"); + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_IO(vcpu, TDX_TEST_PORT, 2, TDX_IO_WRITE); + guest_read_val =3D *(uint16_t *)((void *)vcpu->run + vcpu->run->io.data_o= ffset); + + if (guest_read_val !=3D 0xABCD) { + printf("\t ... FAILED: Guest read 0x%x instead of 0xABCD\n", + guest_read_val); + kvm_vm_free(vm); + return; + } + printf("\t ... Guest read 0x%x from shared memory\n", + guest_read_val); + + kvm_vm_free(vm); + printf("\t ... PASSED\n"); +} + int main(int argc, char **argv) { if (!is_tdx_enabled()) { @@ -1537,6 +1660,7 @@ int main(int argc, char **argv) run_in_new_process(&verify_mmio_writes); run_in_new_process(&verify_host_reading_private_mem); run_in_new_process(&verify_tdcall_vp_info); + run_in_new_process(&verify_shared_mem); =20 return 0; } --=20 2.37.2.789.g6183377224-goog