From patchwork Tue Aug 30 22:19:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601373 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 F0B7DECAAA1 for ; Tue, 30 Aug 2022 22:20:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231913AbiH3WUN (ORCPT ); Tue, 30 Aug 2022 18:20:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231797AbiH3WUL (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 072E02655B for ; Tue, 30 Aug 2022 15:20:07 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id q9-20020a17090aa00900b001fd93514a68so6046697pjp.3 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=7ByUhR9WmilstaZn3jrUuPBf3LgHYA2skqxRPb8pfGlEL4ufqkeARHtse4xPawgxWC SH1DgjAVEK5HJGYhLpjfZQ/59WfigAjBvn45CVlNhCYzuikjnsTe3fQHgHrTTYl22TZp Vuoe+RQtsVKMc02s3W38g3gl2dq4Gr9eQKrlnb8OEnyBGpCDp0dtzaUb6ghtphIMDa7l zZbiw7QUNKM7BdZBShAdzwFQu+ecnX8WJCltbfRK43zEiYFdeNJPCYSXrHZvoxq91pwH T0OklgTgQ/1kXtqJXL9au5LR5EvpeGI7H3lEmyw+BKKOlUGEDoBciOcCXR5tSsLxHtxQ sKew== X-Gm-Message-State: ACgBeo1eF5psqG4/cBOPQNdjAZ94wT8ayrlhU4BmZGmOdXN0JCXJA6US ER5ipDhvAmuVqm+bA9DZCq3o2QN1kpmAaWbf+zn2PUwMM9NCC4WLdbP8O4igVeEZOIX9X/0T950 Vk/DEqDWB/HjSJryCjZpZrEXOgg6jnsBVyvvZT0kkQlCHpGF8bcX2csPEFyueGUGg1ifSxmg= 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-kselftest@vger.kernel.org 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/testing/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 @@ #define NSEC_PER_SEC 1000000000L +#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 */ @@ -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, int type); struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, uint64_t nr_extra_pages); 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); } 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/selftests/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[] = { _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES, "Missing new mode params?"); -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, int type) { struct kvm_vm *vm; @@ -159,7 +159,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages) hash_init(vm->regions.slot_hash); vm->mode = mode; - vm->type = 0; + vm->type = type; vm->pa_bits = vm_guest_mode_params[mode].pa_bits; vm->va_bits = vm_guest_mode_params[mode].va_bits; @@ -294,7 +294,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, nr_extra_pages); struct kvm_vm *vm; - vm = ____vm_create(mode, nr_pages); + vm = ____vm_create(mode, nr_pages, KVM_VM_TYPE_DEFAULT); kvm_vm_elf_load(vm, program_invocation_name); From patchwork Tue Aug 30 22:19:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601372 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 E8E50ECAAD5 for ; Tue, 30 Aug 2022 22:20:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231994AbiH3WUR (ORCPT ); Tue, 30 Aug 2022 18:20:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51908 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231911AbiH3WUN (ORCPT ); Tue, 30 Aug 2022 18:20:13 -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 5D732201BF for ; Tue, 30 Aug 2022 15:20:11 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id cj15-20020a056a00298f00b0053a700f1178so1395826pfb.14 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=52L7l/YWc+RiUyYc39PC2pOctjVWWROqOzFkQqSP65oM0lYIdeKXc7Q8CNuEGc46lH znrstEckQgw/5PlJKboI8cJz5fSD50jXaQKmjwjl5y9jQ7eJOejz/ROS2OpfWQ5IpDu9 wyPzbDzIzGDGrsn/3K1ZPNYfNFvRm2jFqdKR+RdZJvzVYvTESpFPdmt3fxxRJkOfPflh DV0+B+hj31OxunpCOABncR5PFeOjahNC7Yo34yUVVvgk4dWo6soWuYWBlKNOqX2zX9Ko ZZE7lX2ZRCNHvliDaVJXaEzbDyf50OudLyS8k1I5gN+JALKROl1OkkAM80/CR6zftOOl vynQ== X-Gm-Message-State: ACgBeo2GUsC9jN8JiO5uUPPUmsU48hRZh52tvx3oFPrEzI9pwFhsvVxo K20UV1zMYuUpIAZyuGl/8Y9azeFg0ROXALZim9Lcjm+I8rimcQ3P+7K2z1zy5anugNwEtODTKfb Nk4mjHZLgP/kkT542Jp0DwnLwlFYRFriPXgWO/uoVB/ZgfSr7bsHYsm50R5eYCsqyldP+uTs= 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-kselftest@vger.kernel.org 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 += set_memory_region_test TEST_GEN_PROGS_x86_64 += steal_time TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test TEST_GEN_PROGS_x86_64 += system_counter_offset_test +TEST_GEN_PROGS_x86_64 += x86_64/tdx_vm_tests # Compiled outputs used by test targets TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/selftests/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*/ +#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 *guest_code, size_t guest_code_size, uint64_t guest_code_signature); +/* + * 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" + : "=m" (regs->rax), "=m" (regs->rbx), "=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->rsi), + "=m" (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=1byte, 2=2bytes, 4=4bytes. + * write - 1=IO write 0=IO 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=1byte, 2=2bytes, 4=4bytes. + * R13 Direction. 0=Read, 1=Write. + * 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 = TDX_INSTRUCTION_IO; + regs.r12 = size; + regs.r13 = write; + regs.r14 = port; + if (write) { + regs.r15 = *data; + regs.rcx = 0xFC00; + } else { + regs.rcx = 0x7C00; + } + tdcall(®s); + if (!write) + *data = regs.r11; + return regs.r10; +} + +/* + * Report test success to user space. + */ +static inline void tdvmcall_success(void) +{ + uint64_t code = 0; + + tdvmcall_io(TDX_SUCCESS_PORT, /*size=*/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/testing/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 == KVM_EXIT_IO) && \ + ((VCPU)->run->io.port == TDX_SUCCESS_PORT) && \ + ((VCPU)->run->io.size == 4) && \ + ((VCPU)->run->io.direction == 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 in a + * new process context and wait for it to finish or fail to prevent TEST_ASSERT + * to kill the main testing process. + */ +void run_in_new_process(void (*func)(void)) +{ + if (fork() == 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 = 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 = 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; +} From patchwork Tue Aug 30 22:19:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601371 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 6A420ECAAD4 for ; Tue, 30 Aug 2022 22:20:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232009AbiH3WUX (ORCPT ); Tue, 30 Aug 2022 18:20:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52818 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231898AbiH3WUW (ORCPT ); Tue, 30 Aug 2022 18:20:22 -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 4AD452ED7B for ; Tue, 30 Aug 2022 15:20:15 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id b9-20020a170902d50900b0016f0342a417so8810844plg.21 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=E9uWGM4ledHLzrZH6XQatqob9/WarejXegHfUHsVk/mgqmocQLYnAWDDBFAocjJi6L x0WPf1ejfjA4LYR93Zhl6jckeUwMeKpdI4mK1HlGiIkzd1hFFPxwdoHuObzNt9Sepwxw +Nv3tFTjFmD4WkwtifNRqI1Q3zGFc2rUykvt4C3U9MWyW7ig7/yEhUvOirWEbjaMrimk OztSBdS+7HcJeVD9ru6MZcsQNszFdCgpmU+j9rKzV566HVbQtwqZGIpCm/ZefvsCmtKv 0ZejuShzPt1UdH0uwmwBOon1oqxgU+T7BOCfY7FAh9E1JSKAHZ5Otm3DGbFCiLCbyOgi iIYA== X-Gm-Message-State: ACgBeo1yQoWMprdHSqeQcDqTp696HiMp3+IXHnceAsr5vv9EMtX7ui4q MjP7gZD1VLaqxGKt2h86w5RPxzjHsa6oLbR2HtilqLDThJmGcnki89IsuyY0Mk7zhWy0j61v6Vk TO/ssSIaP290hOQFKlIjYYrVE1fOZHQ9Y9A+q2RLdXoiyCZJw+c5cGPX3bs2+1hhCMEYKwlk= 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-kselftest@vger.kernel.org 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/selftests/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 #define TDX_SUCCESS_PORT 0x30 +#define TDX_TEST_PORT 0x31 #define TDX_IO_READ 0 #define TDX_IO_WRITE 1 diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 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)) +#define CHECK_IO(VCPU, PORT, SIZE, DIR) \ + do { \ + TEST_ASSERT((VCPU)->run->exit_reason == KVM_EXIT_IO, \ + "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", \ + (VCPU)->run->exit_reason, \ + exit_reason_str((VCPU)->run->exit_reason)); \ + \ + TEST_ASSERT(((VCPU)->run->exit_reason == KVM_EXIT_IO) && \ + ((VCPU)->run->io.port == (PORT)) && \ + ((VCPU)->run->io.size == (SIZE)) && \ + ((VCPU)->run->io.direction == (DIR)), \ + "Got 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 == 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"); } +/* + * 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 = 0xAB; + + ret = tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_WRITE, &data_out); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvmcall_io(TDX_TEST_PORT, 1, TDX_IO_READ, &data_in); + if (ret) + tdvmcall_fatal(ret); + + delta = data_in - data_out; + if (delta != 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 = 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 = 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 = *(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) = 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) run_in_new_process(&verify_td_lifecycle); run_in_new_process(&verify_report_fatal_error); + run_in_new_process(&verify_td_ioexit); return 0; } From patchwork Tue Aug 30 22:19:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601370 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 29D55ECAAA1 for ; Tue, 30 Aug 2022 22:20:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231190AbiH3WUk (ORCPT ); Tue, 30 Aug 2022 18:20:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53856 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232129AbiH3WUe (ORCPT ); Tue, 30 Aug 2022 18:20:34 -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 7C1AB4E62A for ; Tue, 30 Aug 2022 15:20:19 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id 92-20020a17090a09e500b001d917022847so5214633pjo.1 for ; Tue, 30 Aug 2022 15:20:19 -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=waWv5y5MuZJf4tmxzK7Q2VPfkj8Vxo7tzeHMJSSRMfG42TcXtgozjIPmoOYbmmRKyM yyLo8iIljpvO3iBXLfi/ADcbzVsVzDLoWs0kQ2nWfwNsWLUP+rFI0JPSaYteoTKN6KCi PjyAn3iJb9w4KMXLs22k+nMlUqPJHvpzSdZ0UvanHfRbpExMA1cZWA29swq6BjtZQxSS evJv02MJk7FdXzVrbXPqGFEXQzGfPfSfnCTPWyQJJGNK9IHT6fhZ24TpRl00t/05HapO nq8YgJghLzBIZq5XXISRlh19Bz60pSJOqRtJUQWo/Qar7h6dvGyzjgsP1gV0JJgMsGpP /HKQ== X-Gm-Message-State: ACgBeo1eb7UnrynFXpvDYP0/bvOU1XDx+TfwBSDhgW2Kxj5pw7Wz/w7I bccx5q+kda7/aaHx49DTcIFFt1ExaiiS/vDWuHc9awZXtSLm0LrGIMQ6SURvBgoUt2LNyu/wKxz KL2KoI08S1yNn0X7F+7PzE+d4FKVrR6S4sfSpEBl1wYE5/uf3zJeNo//0/DN2LQ0ch90UoRI= 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-kselftest@vger.kernel.org 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/selftests/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 @@ #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 @@ -231,6 +232,18 @@ static inline void tdvmcall_fatal(uint64_t error_code) tdcall(®s); } +/* + * Reports a 32 bit value from the guest to user space using a TDVM IO call. + * 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 = data; + + return tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=*/4, TDX_IO_WRITE, &data_64); +} + #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/testing/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)); } +/* + * 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 = 0; i < cpuid_data.cpuid.nent; i++) { + e = &cpuid_data.entries[i]; + + if (e->function == function && + (e->index == 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"); } +/* + * 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 = tdvm_report_to_user_space(ebx); + if (err) + tdvmcall_fatal(err); + + err = 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 = 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 = 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 = *(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 = *(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 = KVM_MAX_CPUID_ENTRIES; + ret = ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data); + TEST_ASSERT(!ret, "KVM_GET_SUPPORTED_CPUID failed\n"); + cpuid_entry = find_cpuid_entry(cpuid_data, 1, 0); + TEST_ASSERT(cpuid_entry, "CPUID entry missing\n"); + + host_max_addressable_ids = (cpuid_entry->ebx >> 16) & 0xFF; + + guest_sse3_enabled = ecx & 0x1; // Native + guest_clflush_line_size = (ebx >> 8) & 0xFF; // Fixed + guest_max_addressable_ids = (ebx >> 16) & 0xFF; // As Configured + guest_fma_enabled = (ecx >> 12) & 0x1; // As Configured (if Native) + guest_initial_apic_id = (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"); +} 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); return 0; } From patchwork Tue Aug 30 22:19:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601368 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 1680AECAAD5 for ; Tue, 30 Aug 2022 22:21:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232170AbiH3WVb (ORCPT ); Tue, 30 Aug 2022 18:21:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232300AbiH3WVK (ORCPT ); Tue, 30 Aug 2022 18:21:10 -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 4149161D66 for ; Tue, 30 Aug 2022 15:20:26 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id mq13-20020a17090b380d00b001fb60a596c8so1379633pjb.0 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=2FTSFAq+r0XzBJdYRsQIgy6IexWF0KbYrMkm3AE8Lm8FNFIQnzyVuISfU8u+1YfyHE 9QA6/hFM7JNv8GfkcX1SO8xk2pZZ8c2EzIDF1ITDAm5mP3FPI82+XAtA2KI7qCMmVmHW 7J1DnFrwPO3zKtJeREZSz2s+WQcAadzCwcQxKdC6HfazpN/toO14D+CzXL6jlciAC3/c j6PbhvVNB4sU9o+1LK8sBNdooCTo1jOjdOB24FXIFQpZgdmfA2OeADQPsl54xVvaij/a vfDeZdjwGUKaIWBWgW4tNnN6sQKkPllt5xdD6lmIC0FhzkvhZY7Zdahf4FRfs/GDj9rC VUXQ== X-Gm-Message-State: ACgBeo2pE5wLp0umkdNUioJyRzbA1m+r7KgkYi01ZTdgfQN7di8S61wQ zKyVioKmmlP5HfCohrcLHwF1NEJA09+0lL/qWkFzpsrNHVqvRWLjjffwksY34SdSgnczWmVn4Pe Y1d7VK/rIi7fnx88tkthdZ6RVlJKu5MrlnujUyX56mBYa4ffMT1g4+L5+nU9RfJfC60JG/nE= 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-kselftest@vger.kernel.org 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/selftests/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 #define TDX_SUCCESS_PORT 0x30 #define TDX_TEST_PORT 0x31 @@ -258,6 +260,38 @@ static inline uint64_t tdvmcall_get_td_vmcall_info(uint64_t *r11, uint64_t *r12, return regs.r10; } +/* + * 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 = TDX_INSTRUCTION_RDMSR; + regs.r12 = index; + regs.rcx = 0x1C00; + tdcall(®s); + *ret_value = 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 = TDX_INSTRUCTION_WRMSR; + regs.r12 = index; + regs.r13 = value; + regs.rcx = 0x3C00; + tdcall(®s); + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO call. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 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) + +/* + * 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 = 0xFFFFFFFFFFFFFFFF; +#define MTTR_BASE_0 (0x200) +#define MTTR_BASE_1 (0x202) +#define MTTR_BASE_2 (0x204) +struct kvm_msr_filter test_filter = { + .flags = KVM_MSR_FILTER_DEFAULT_DENY, + .ranges = { + { + .flags = KVM_MSR_FILTER_READ | + KVM_MSR_FILTER_WRITE, + .nmsrs = 1, + .base = MTTR_BASE_0, + .bitmap = (uint8_t *)&allow_bits, + }, { + .flags = KVM_MSR_FILTER_READ, + .nmsrs = 1, + .base = MTTR_BASE_1, + .bitmap = (uint8_t *)&allow_bits, + }, { + .flags = KVM_MSR_FILTER_WRITE, + .nmsrs = 1, + .base = MTTR_BASE_2, + .bitmap = (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"); } +/* + * Verifies MSR read functionality. + */ +TDX_GUEST_FUNCTION(guest_msr_read) +{ + uint64_t data; + uint64_t ret; + + ret = tdvmcall_rdmsr(MTTR_BASE_0, &data); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvm_report_64bit_to_user_space(data); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvmcall_rdmsr(MTTR_BASE_1, &data); + if (ret) + tdvmcall_fatal(ret); + + ret = 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 = tdvmcall_rdmsr(MTTR_BASE_2, &data); + if (ret) { + ret = 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 = 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 = 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 = kvm_check_cap(KVM_CAP_X86_MSR_FILTER); + TEST_ASSERT(ret, "KVM_CAP_X86_MSR_FILTER is unavailable"); + + ret = ioctl(vm->fd, KVM_X86_SET_MSR_FILTER, &test_filter); + TEST_ASSERT(ret == 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 = 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 = read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, 4); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data = read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + ASSERT_EQ(data, 5); + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + data = 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 = 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 = tdvmcall_wrmsr(MTTR_BASE_1, 5); + if (ret) { + ret = tdvm_report_64bit_to_user_space(ret); + if (ret) + tdvmcall_fatal(ret); + } else { + tdvmcall_fatal(-99); + } + + + ret = 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 = 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 = 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 = kvm_check_cap(KVM_CAP_X86_MSR_FILTER); + TEST_ASSERT(ret, "KVM_CAP_X86_MSR_FILTER is unavailable"); + + ret = ioctl(vm->fd, KVM_X86_SET_MSR_FILTER, &test_filter); + TEST_ASSERT(ret == 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 = 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 = 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); return 0; } From patchwork Tue Aug 30 22:19:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601369 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 5E46FECAAA1 for ; Tue, 30 Aug 2022 22:21:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232302AbiH3WVa (ORCPT ); Tue, 30 Aug 2022 18:21:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232185AbiH3WVK (ORCPT ); Tue, 30 Aug 2022 18:21:10 -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 CCD8B5E556 for ; Tue, 30 Aug 2022 15:20:27 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id oo12-20020a17090b1c8c00b001faa0b549caso11850655pjb.0 for ; Tue, 30 Aug 2022 15:20:27 -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=gwUHb72Ah+mpq8prtiP0p/+Z1cPc//pgKYuscQRw0Bo+Zz/0C5vv8uXc+qTkwbcusv lOXlyBELVIkpy5WXpLhoFYxdC33wkqjqFhyUfYAGYyQ3GLi9qJ64e0se+dvLfmEfI8dH mBrc4zOIoV5wwiGGgtUXcTFQb1rewzVa2uPbQrc2mwtDv1I+Ml5dEuR7tOICeNtsWGnY yslpn1/QQJzVa/mhXrA3CO30vWiUuI6NptIdcrIbCf4D+pH9zreB2B2NphEZWTMyyiM6 1m/LzAkRZRQ74gVbJ0j+gXIWaU5mLfzgm75CZXKXWg6urUnKldpQradUnS9b2OHZK14t HraQ== X-Gm-Message-State: ACgBeo2V1aSr+w3Izc+ZZ3dA1beib1RaNpd2Wkj/i9XASnsp0F9CvyhM phj9mhHtM6tNLbbAhUWaQnRhU0lt0JnT6WbiG4GcCFNTnPTtcjBsAURh3N2IRYidAC6PT1kHklM eIZ8VGvPYzExCTvK0lBIRw+sGdjXUE+klzbw1DcJM5P0gWgB/x2/URtoqA5Pt9si4hpLgfjg= 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-kselftest@vger.kernel.org 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/selftests/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 #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 #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; } +/* + * 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 = TDX_INSTRUCTION_VE_REQUEST_MMIO; + regs.r12 = size; + regs.r13 = TDX_MMIO_READ; + regs.r14 = address; + regs.rcx = 0x7C00; + tdcall(®s); + *data_out = regs.r11; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO call. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 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 #include "asm/kvm.h" +#include "linux/kernel.h" #include #include #include @@ -47,6 +48,24 @@ (VCPU)->run->io.direction); \ } while (0) +#define CHECK_MMIO(VCPU, ADDR, SIZE, DIR) \ + do { \ + TEST_ASSERT((VCPU)->run->exit_reason == 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 == KVM_EXIT_MMIO) && \ + ((VCPU)->run->mmio.phys_addr == (ADDR)) && \ + ((VCPU)->run->mmio.len == (SIZE)) && \ + ((VCPU)->run->mmio.is_write == (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 == KVM_EXIT_SYSTEM_EVENT) \ @@ -89,6 +108,8 @@ struct kvm_msr_filter test_filter = { }, }; +#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); } +TDX_GUEST_FUNCTION(guest_mmio_reads) +{ + uint64_t data; + uint64_t ret; + + ret = tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 1, &data); + if (ret) + tdvmcall_fatal(ret); + if (data != 0x12) + tdvmcall_fatal(1); + + ret = tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 2, &data); + if (ret) + tdvmcall_fatal(ret); + if (data != 0x1234) + tdvmcall_fatal(2); + + ret = tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 4, &data); + if (ret) + tdvmcall_fatal(ret); + if (data != 0x12345678) + tdvmcall_fatal(4); + + ret = tdvmcall_mmio_read(MMIO_VALID_ADDRESS, 8, &data); + if (ret) + tdvmcall_fatal(ret); + if (data != 0x1234567890ABCDEF) + tdvmcall_fatal(8); + + // Read an invalid number of bytes. + ret = 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 = 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 = 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 = 0x12; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 2, TDX_MMIO_READ); + *(uint16_t *)vcpu->run->mmio.data = 0x1234; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 4, TDX_MMIO_READ); + *(uint32_t *)vcpu->run->mmio.data = 0x12345678; + + vcpu_run(vcpu); + CHECK_GUEST_FAILURE(vcpu); + CHECK_MMIO(vcpu, MMIO_VALID_ADDRESS, 8, TDX_MMIO_READ); + *(uint64_t *)vcpu->run->mmio.data = 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); return 0; } From patchwork Tue Aug 30 22:19:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601367 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 DD6B1ECAAA1 for ; Tue, 30 Aug 2022 22:21:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232323AbiH3WVq (ORCPT ); Tue, 30 Aug 2022 18:21:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231906AbiH3WVO (ORCPT ); Tue, 30 Aug 2022 18:21:14 -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 002A67172F for ; Tue, 30 Aug 2022 15:20:28 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id k16-20020a635a50000000b0042986056df6so6063322pgm.2 for ; Tue, 30 Aug 2022 15:20:28 -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=knJ6GYQ39UkMJol5z+PMBVtmoZ5216DgNFVSzh+TfCuZtZCSJ9GLxCzyGIjfWPHhEr fID+VUJO8Fk9+f9gEpoU+D7nk3yVaXM7BJXWSvAEFoNktok64p+VxHO8wXIjijvW6VFF sRgIh0+wWgTmAcBlTSyatQjUDfyxpFiA8YT0RrMxvr98SM1r+0zunAADWQuDhTN4FlMp 6w5L/GOyD6y8hhQbSlzB1ZkzYASZTWgEmn626dsM/6TFxze6DkorVoxkGJGCcqOJaihs C4lsx5HXTAzB9qqobCBXOWwc2baoGKyXVM7siF3wOLg4oLf5DsVVSbK/RZ6HxTpGU9w0 fRjg== X-Gm-Message-State: ACgBeo1Ewxwyu8YVySMsUDOu3NuWJOFM+ZjedfOmiSfn7zSqjG9Hiku/ OUq3+Hd7qVaffFWHVIWXNSSc8baw509DaEtn79pVzLQJKf3zTh/0nh/567KwdejKSbEvVZ3JaXe Q7vuwkkld+HTUbop81Kftm9u8HoO3ONKiwBzvrfJqLfbDMBaCSkQOsjNUoROkU6P0Jg+gNGU= 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-kselftest@vger.kernel.org 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/selftests/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 address, uint64_t size, uint6 return regs.r10; } +/* + * 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 = TDX_INSTRUCTION_VE_REQUEST_MMIO; + regs.r12 = size; + regs.r13 = TDX_MMIO_WRITE; + regs.r14 = address; + regs.r15 = data_in; + regs.rcx = 0xFC00; + tdcall(®s); + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO call. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 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"); } +TDX_GUEST_FUNCTION(guest_mmio_writes) +{ + uint64_t ret; + + ret = tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 1, 0x12); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 2, 0x1234); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 4, 0x12345678); + if (ret) + tdvmcall_fatal(ret); + + ret = tdvmcall_mmio_write(MMIO_VALID_ADDRESS, 8, 0x1234567890ABCDEF); + if (ret) + tdvmcall_fatal(ret); + + // Write across page boundary. + ret = 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 = 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 = 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 = *(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 = *(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 = *(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 = *(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); return 0; } From patchwork Tue Aug 30 22:19:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601366 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 63D7DECAAD5 for ; Tue, 30 Aug 2022 22:22:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232402AbiH3WWU (ORCPT ); Tue, 30 Aug 2022 18:22:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56402 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230076AbiH3WVx (ORCPT ); Tue, 30 Aug 2022 18:21:53 -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 E62CE82D31 for ; Tue, 30 Aug 2022 15:20:56 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id b25-20020aa78119000000b00536a929d8e4so5086960pfi.1 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=lka4vmLFeKqD8WXl1NRDnbzF376NChRZ6kKvE5dkZgdY32gwi0RApKL/0iW+TvoJQq RwOqvEN7Y8n0YTF/MmyJAYdGmFUKE/kK9TTsuF3mouC6LV+bwI4F9IdhIclrZOsV3m9f T1vmYwr3rBBTLw9ODoUlbaBZDPa/zhVq9HhXw7bDxjQjuzfStDGogSFDQhAPHokkIBGz w+oZDmMtbrAHLqcAucZcrDlo44zRcB+H8xyVUjko1H5pvUYuEKvL4OhSZodkveoW2lcF pzmrhoG7GaG3KkPrpWtty+PYP9/gCkYAmLChFxWiyFh2DxzXpjlF3fXS7aHOrN6e/Ofo gE6A== X-Gm-Message-State: ACgBeo0uGmq10p129vwMyHYYOwA1HvVYoBT8j5obuo4E930LvuSIDWd9 y7/NdkjXp732Y7nOKfv7ML5hljdVJTi6PGv0POhlqTYZm5v6mAu3Ooc3zGHcINVQaL6iHqZoBkO ZpN0omj6lCL0Y7KuKYMBBEnOyrdRGJEEUVVKBDZw5X7gyD0rnQ+4DlKVFMjz4Pztn1e3DdI8= 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-kselftest@vger.kernel.org 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/testing/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"); } +TDX_GUEST_FUNCTION(guest_host_read_priv_mem) +{ + uint64_t guest_var = 0xABCD; + uint64_t ret; + + /* Sends address to host. */ + ret = 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 = 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 = 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 = 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 = read_64bit_from_guest(vcpu, TDX_DATA_REPORT_PORT); + + /* Search for the guest's address in guest's memory regions. */ + host_virt = 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 = (uint64_t)region->region.guest_phys_addr; + offset = guest_var_addr - guest_base; + + if (guest_base <= guest_var_addr && + offset <= region->region.memory_size) { + host_virt_base = (uint64_t)region->host_mem; + host_virt = host_virt_base + offset; + break; + } + } + TEST_ASSERT(host_virt != 0, + "Guest address not found in guest memory regions\n"); + + /* Host reads guest's variable. */ + first_host_read = *(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 = *(uint64_t *)host_virt; + printf("\t ... Host's second read attempt value: %lu\n", + second_host_read); + + TEST_ASSERT(first_host_read == 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); return 0; } From patchwork Tue Aug 30 22:20:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sagi Shahar X-Patchwork-Id: 601365 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 CA272ECAAA1 for ; Tue, 30 Aug 2022 22:22:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232353AbiH3WWj (ORCPT ); Tue, 30 Aug 2022 18:22:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232350AbiH3WWI (ORCPT ); Tue, 30 Aug 2022 18:22:08 -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 26C0381B1C for ; Tue, 30 Aug 2022 15:21:04 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id n30-20020a17090a5aa100b001fb0c492d5eso5411613pji.3 for ; Tue, 30 Aug 2022 15:21:04 -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=1bajW6KDUD/EDutt9XJqNGVrLAJLSNwcfrK6JHRnAFSjKbRYrHokrYWj26uP+/UyIv 3960fvjiK1ldOq5V9I308TXM6f3CRnkAEiNYAb8kxJUFzCOmUAHOmErKXz9lewZhDvvV K5SjcJ5kYrSauNhBkwcZLBHAS/NfK5Rk7j6dSnHZss+KBToig/JrMGoPYdNVcHC9tvWk YXqLLdeDOEBRg7B70HpkTktN/Pj66YOyUupnyU4ByY6nAXjZXgbivmpNw8W6XtIea+vf jkg3RXzN+BAJuT69dlXw5t3LwUbGRgfiP+SY4XXaLd1vcCpBBcFNzuQElE5SQjA3Rb65 JH8A== X-Gm-Message-State: ACgBeo3Aw5E6+6qfDj8R/WH2TuSyLHuvHo6GeYCko7m1KkvYm2s9a2Au JzyWCvQGOa+qdnu8qlWHwPnYMQcDB9Xn6mYEI+ZVcsGlGlOVnzQr8w05qgBuzrmUNpboe+vVcx2 qgP2wdVUBV5pxaIuraD4XDSKqPrTbZUMORldlkdb16b5Nmegjm9bbaYpBKIeCQXLMMk647wM= 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-kselftest@vger.kernel.org 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/selftests/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 @@ /* * Max Page Table Size - * To map 4GB memory region with 2MB pages, there needs to be 1 page for PML4, - * 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 pages, + * there needs to be 1 page for PML4, 1 Page for PDPT, 8 pages for PD. Reserving + * 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 range + * [32 - 38] (0-indexed) that will designate a 4 GB region of GVAs that map the + * shared GPAs. This approach does not increase number of PML4 and PDPT pages. + */ +#define TDX_GUEST_VIRT_SHARED_BIT 32 /* * Predefined GDTR values. @@ -60,6 +71,7 @@ #define TDX_VMCALL_INVALID_OPERAND 0x8000000000000000 #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]; }; 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, uint64_t *rdx, return regs.rax; } +/* + * 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 = TDX_MAP_GPA; + regs.r12 = address; + regs.r13 = size; + regs.rcx = 0x3C00; + tdcall(®s); + *data_out = regs.r11; + return regs.r10; +} + /* * Reports a 32 bit value from the guest to user space using a TDVM IO call. * Data is reported on port TDX_DATA_REPORT_PORT. diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c b/tools/testing/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_target) * which will be used by the TDX guest when paging is enabled. * TODO: use virt_pg_map() functions to dynamically allocate the page tables. */ -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; pt = malloc(sizeof(struct page_table)); TEST_ASSERT(pt != 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 = 0; i < 4; i++) + for (i = 0; i < 8; i++) memset((void *) &(pt->pd[i][0]), 0, sizeof(pt->pd[i])); + /* Populate pml4 entry. */ pt->pml4[0] = (pml4_base_address + PAGE_SIZE) | _PAGE_PRESENT | _PAGE_RW; + + /* Populate pdpt entries for private memory region. */ for (i = 0; i < 4; i++) pt->pdpt[i] = (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 >= 32 && + TDX_GUEST_VIRT_SHARED_BIT <= 38, + "Guest virtual shared bit must be in the range [32 - 38].\n"); + shared_pdpt_index = 1 << (TDX_GUEST_VIRT_SHARED_BIT - 30); - uint64_t *pde = &(pt->pd[0][0]); + /* Populate pdpt entries for shared memory region. */ + for (i = 0; i < 4; i++) + pt->pdpt[shared_pdpt_index + i] = (pml4_base_address + (i + 6) * + PAGE_SIZE) | _PAGE_PRESENT | + _PAGE_RW; - for (i = 0; i < sizeof(pt->pd) / sizeof(pt->pd[0][0]); i++, pde++) + /* Populate pd entries for private memory region. */ + pde = &(pt->pd[0][0]); + for (i = 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++) *pde = (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 = &(pt->pd[4][0]); + gpa_shared_mask = BIT_ULL(gpa_shared_bit); + for (i = 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++) + *pde = gpa_shared_mask | (i << 21) | _PAGE_PRESENT | _PAGE_RW | + _PAGE_PS; + + memcpy(pt_target, pt, 10 * PAGE_SIZE); } static void @@ -318,7 +345,7 @@ void prepare_source_image(struct kvm_vm *vm, void *guest_code, guest_code_base = gdt_address + (TDX_GUEST_STACK_NR_PAGES * PAGE_SIZE); - 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); /* reset vector code should end with int3 instructions. diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c index 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"); } +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 = BIT_ULL(TDX_GUEST_VIRT_SHARED_BIT); + shared_gpa = 0x80000000; + shared_gva = gva_shared_mask | shared_gpa; + + /* Read highest order physical bit to calculate shared mask. */ + err = tdcall_vp_info(&gpa_width, 0, 0, 0, 0, 0); + if (err) + tdvmcall_fatal(err); + + /* Map gpa as shared. */ + gpa_shared_mask = BIT_ULL(gpa_width - 1); + ret = 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 = 0x1234; + tdvmcall_success(); + + /* Read from shared memory; report to host. */ + ret = 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 = 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 = vm_vcpu_add_tdx(vm, 0); + + /* Allocate shared memory. */ + shared_gpa = 0x80000000; + shared_pages_num = 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 = 0; + hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) { + uint64_t region_guest_addr; + + region_guest_addr = (uint64_t)region->region.guest_phys_addr; + if (region_guest_addr == (shared_gpa)) { + shared_hva = (uint64_t)region->host_mem; + break; + } + } + TEST_ASSERT(shared_hva != 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 != 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) = 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 = *(uint16_t *)((void *)vcpu->run + vcpu->run->io.data_offset); + + if (guest_read_val != 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); return 0; }