Received: by 2002:a05:6358:45e:b0:b5:b6eb:e1f9 with SMTP id 30csp4713470rwe; Tue, 30 Aug 2022 15:45:43 -0700 (PDT) X-Google-Smtp-Source: AA6agR5yJvH6xdBJRgycHdARWo0iZpefnKMUcXbN95or3fDgP48I89gim1QQphznIwSx4L7m4r04 X-Received: by 2002:a17:907:9708:b0:741:9618:c493 with SMTP id jg8-20020a170907970800b007419618c493mr7894988ejc.631.1661899542852; Tue, 30 Aug 2022 15:45:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661899542; cv=none; d=google.com; s=arc-20160816; b=LhmYEC/ZH1DoBdGH5v+zASD6y+QUV3ZKy9JBi1Vxl1uVO8JhIhDfW6c0CpfnL0wO86 O5Xo4Wiw92luCXsPlsq9x79BUB7XmypvgVPhWnAA17wErWTG4YxPwvjyF/TMJwAg4tr+ 8CHHyIaa7klWsFKHcd3fA3sJDlC92Opn1yPzD2GBSpG/I5PDexLUQsDLTAm7u899Xye8 8MaqOGuAcQA8p6EACkUVnW9XilgVx1a4ibGy9eTLZTXYmnH43qnFr3eTcyjwRd7B7E/o u1KApKjZ5Ecb6WCN/MTyzaclLNz16AvwIZi6kiSy9z9pdukthGLyb7nEwrj9Y1n/dFQf 1WJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=sMSKVgYi+NQVBY9S65ltrEDvFSNwWuSwBWyaYR7CUj4=; b=DTvbRXG3E3xXVora3QvXWPS05D7YljROd7/zEupJqy090G0TO3VwBaf4P0R+vnUV7i 0RWSfQA5Xsk8VHiPGe9D+vIke20H9WpcEzXKFLs3CEU7DU/tLYeRDzmSMcbNvMHIPj3M GMnz6DSN4B+V7glc5ZVjfSSAbzA8X1JgtygeiamFI3am4HinqqVZ8U7RK6iR/8VLNO+t yCwTj2Qzh6B8UoaLePvMXJIHcp6Gz7yDiebv1dvygPxodik8ZJUAqt7UZLqtwEczvmIs op0FUc19zlxK20NasYqJQAnsbUGovRmXWim6KXGKlBEWRe5GAM8N19hmwwrKXp0KjXTZ /ZKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="OJS0Nn/G"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id hp2-20020a1709073e0200b007418baf9305si5906533ejc.376.2022.08.30.15.45.17; Tue, 30 Aug 2022 15:45:42 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="OJS0Nn/G"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232256AbiH3WUu (ORCPT + 99 others); Tue, 30 Aug 2022 18:20:50 -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-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 Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@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; } -- 2.37.2.789.g6183377224-goog