From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 25025C5475B for ; Fri, 1 Mar 2024 12:10:05 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7E33E6B007B; Fri, 1 Mar 2024 07:10:04 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 792476B007D; Fri, 1 Mar 2024 07:10:04 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 65A166B007E; Fri, 1 Mar 2024 07:10:04 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 505B66B007B for ; Fri, 1 Mar 2024 07:10:04 -0500 (EST) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id E3ECBA1CC4 for ; Fri, 1 Mar 2024 12:10:03 +0000 (UTC) X-FDA: 81848351886.07.EF4A5CA Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.20]) by imf26.hostedemail.com (Postfix) with ESMTP id 405E614000F for ; Fri, 1 Mar 2024 12:10:01 +0000 (UTC) Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QhUjWkY6; spf=none (imf26.hostedemail.com: domain of binbin.wu@linux.intel.com has no SPF policy when checking 198.175.65.20) smtp.mailfrom=binbin.wu@linux.intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1709295001; a=rsa-sha256; cv=none; b=rjg1LAs+Yllb//iyXNWCGRVKC6hngy570AYRAH3qdMoL8fWmnvmqlt7zaysrSiHIuUoIVT ZdqU0z9f4SPFodZGgDZ9a7dm/zyiwEjghSsUr0AS7lCgZr5boJWhmmFEbJtV792aLBQaPa C1JrTVHXKfRZf+xG58Ygn0XCpJBilBo= ARC-Authentication-Results: i=1; imf26.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QhUjWkY6; spf=none (imf26.hostedemail.com: domain of binbin.wu@linux.intel.com has no SPF policy when checking 198.175.65.20) smtp.mailfrom=binbin.wu@linux.intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1709295001; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=RHupJ3izw5l+PEY0jcozobS+2zy4pLDDzmwHBUOTWKQ=; b=JggTjsKlRh6eiuMnbK4xFcHB0vol6QH3dVKbuSBjiHMpeoypDhEIMJwDznP3AyuBogCjmu NhmfNsq8R9PG3vl0P7TycY0XPnheOcXtwbiko0GzSfPTvZ+Wh9OhPlhlrqIugpH1/R4IND NtSzwbarZ/OPt0PuTTQF2PtixStgYfU= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1709295001; x=1740831001; h=message-id:date:mime-version:subject:from:to:cc: references:in-reply-to:content-transfer-encoding; bh=ScRQVG3nMmZ8fe0cGcbyZVAKxEDLmyRQd9yx2uT1RQY=; b=QhUjWkY6Fdh9p30/spZ8wtY/iF2pVVuj1C91U+Ks9QKX3fY/hFfgiFmr xeE0k+gYHIM85QowYBvt77kSN0r5Yf6Ik8pT3Upx03B7xM/oW8eSZugHD wV8X6GcnWqYYFp8xgXwvtDWP7UBC82G1hcih+IFxMQeuZZBoWyMWTZJZU GloozV0BZI44NkhNkmAFMohFyeU5FRI3X2DDMdv5Bx0fiUHe83aLIkSk5 C7sQ3B5gDAxRTAtzplxCbJSaIlaY68QsvWjZVEd0MB1MfyL3RHi47GUcb zEBKB9vrN8Qvlgk/DQzLc0nLdnR55WkdoHP+dosR8h7eTrPTHpFtzGTGg Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10999"; a="3717300" X-IronPort-AV: E=Sophos;i="6.06,196,1705392000"; d="scan'208";a="3717300" Received: from fmviesa008.fm.intel.com ([10.60.135.148]) by orvoesa112.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Mar 2024 04:10:00 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.06,196,1705392000"; d="scan'208";a="8319181" Received: from binbinwu-mobl.ccr.corp.intel.com (HELO [10.125.242.247]) ([10.125.242.247]) by fmviesa008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Mar 2024 04:09:55 -0800 Message-ID: Date: Fri, 1 Mar 2024 20:09:52 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [RFC PATCH v5 15/29] KVM: selftests: TDX: Add TDX MSR read/write tests From: Binbin Wu To: Sagi Shahar Cc: linux-kselftest@vger.kernel.org, Ackerley Tng , Ryan Afranji , Erdem Aktas , Isaku Yamahata , Sean Christopherson , Paolo Bonzini , Shuah Khan , Peter Gonda , Haibo Xu , Chao Peng , Vishal Annapurve , Roger Wang , Vipin Sharma , jmattson@google.com, dmatlack@google.com, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-mm@kvack.org References: <20231212204647.2170650-1-sagis@google.com> <20231212204647.2170650-16-sagis@google.com> In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Rspamd-Server: rspam08 X-Rspamd-Queue-Id: 405E614000F X-Stat-Signature: a9qxyr6zckzg4qs5h4dzeirzq9tyseft X-Rspam-User: X-HE-Tag: 1709295001-98949 X-HE-Meta: U2FsdGVkX18jPR/P7fAPsl5HLC3TPClnv//jzMc2aTqR93IuuJNYz6YGOqKLrH6aZBMyKEat4nyX0fb42rL9515nuWPQCxYvR8VicSLi4pxvKmBLhYWCec7oi6jn0PQdtaS5jB62TdB5mmJEvPM93V3sYHVUP1MVjH+FlJejuCkNIHbJH06S8wdCHoxDP3tEQqL5ouwYZARblJR94dX8HfIingkCaJ7wY+RUyxyieYjJuDsNOva44c0ABySMDDL2J4FiuuXLY48TGRIyto22A/ByApl5LcqT/IIWDM9yfXnNRDHtkNBcRy+ONR1Ls6sPt/lRT73HYaOWJ9cLS1LDPGvo9RFiMSmlAo8msKCoMDd46Ho+pGDdnZFxQZwv8FDZeNXFlRg5lFfAMLDN6vE404O7Ck6cljKq+cmpAJrkM+8PBSnqXOTYstSIcWDKr3OufiHCyvFHiaRQ0jguxq6jtrZFYRilI9XPuaqnq+NrRq5ZFhZK2o0sPKwuChAkCIYO75TA9I9sCCmkwabxxg2EN7HQvTkCoLmKUfyoMbBair3GSsqm/ImkLLiRGK/f3XCSYon38KzfNJoine7v4uRWrFCNl2hRsktkc4CrQTcMPo3QHCckEHvtWBZvrgEwAnva1B0sw72NldU3WNUYZOPMgYa47xnsDQnahx10tjxtfbrZlBgOo8ebczugZRfahvr7q8CbYQNLv6oi3FC6H/4IRMljGAJnutmyRL+Iv5+6+Df7uolM19bK1yJrAsb2tjCmqj7bxSsxYaFeL3WOJngJpEEwWLABJmuvgmeT7jyxPKYCj8O07CLzctnyL5kgEkm+QHZyS6WXprNmaDHaYO6VamJ+tmBnsruWjFdS0I1/5GyqNa1aGaWI/Q== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: On 3/1/2024 8:00 PM, Binbin Wu wrote: > > > On 12/13/2023 4:46 AM, Sagi Shahar wrote: >> The test verifies reads and writes for MSR registers with different >> access >> level. >> >> Signed-off-by: Sagi Shahar >> Signed-off-by: Ackerley Tng >> Signed-off-by: Ryan Afranji >> --- >>   .../selftests/kvm/include/x86_64/tdx/tdx.h    |   5 + >>   .../selftests/kvm/lib/x86_64/tdx/tdx.c        |  27 +++ >>   .../selftests/kvm/x86_64/tdx_vm_tests.c       | 209 ++++++++++++++++++ >>   3 files changed, 241 insertions(+) >> >> diff --git a/tools/testing/selftests/kvm/include/x86_64/tdx/tdx.h >> b/tools/testing/selftests/kvm/include/x86_64/tdx/tdx.h >> index 63788012bf94..85ba6aab79a7 100644 >> --- a/tools/testing/selftests/kvm/include/x86_64/tdx/tdx.h >> +++ b/tools/testing/selftests/kvm/include/x86_64/tdx/tdx.h >> @@ -9,11 +9,16 @@ >>   #define TDG_VP_VMCALL_REPORT_FATAL_ERROR 0x10003 >>     #define TDG_VP_VMCALL_INSTRUCTION_IO 30 >> +#define TDG_VP_VMCALL_INSTRUCTION_RDMSR 31 >> +#define TDG_VP_VMCALL_INSTRUCTION_WRMSR 32 >> + >>   void handle_userspace_tdg_vp_vmcall_exit(struct kvm_vcpu *vcpu); >>   uint64_t tdg_vp_vmcall_instruction_io(uint64_t port, uint64_t size, >>                         uint64_t write, uint64_t *data); >>   void tdg_vp_vmcall_report_fatal_error(uint64_t error_code, uint64_t >> data_gpa); >>   uint64_t tdg_vp_vmcall_get_td_vmcall_info(uint64_t *r11, uint64_t >> *r12, >>                       uint64_t *r13, uint64_t *r14); >> +uint64_t tdg_vp_vmcall_instruction_rdmsr(uint64_t index, uint64_t >> *ret_value); >> +uint64_t tdg_vp_vmcall_instruction_wrmsr(uint64_t index, uint64_t >> value); >>     #endif // SELFTEST_TDX_TDX_H >> diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx/tdx.c >> b/tools/testing/selftests/kvm/lib/x86_64/tdx/tdx.c >> index e5a9e13c62e2..88ea6f2a6469 100644 >> --- a/tools/testing/selftests/kvm/lib/x86_64/tdx/tdx.c >> +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx/tdx.c >> @@ -87,3 +87,30 @@ uint64_t tdg_vp_vmcall_get_td_vmcall_info(uint64_t >> *r11, uint64_t *r12, >>         return ret; >>   } >> + >> +uint64_t tdg_vp_vmcall_instruction_rdmsr(uint64_t index, uint64_t >> *ret_value) >> +{ >> +    uint64_t ret; >> +    struct tdx_hypercall_args args = { >> +        .r11 = TDG_VP_VMCALL_INSTRUCTION_RDMSR, >> +        .r12 = index, >> +    }; >> + >> +    ret = __tdx_hypercall(&args, TDX_HCALL_HAS_OUTPUT); >> + >> +    if (ret_value) >> +        *ret_value = args.r11; >> + >> +    return ret; >> +} >> + >> +uint64_t tdg_vp_vmcall_instruction_wrmsr(uint64_t index, uint64_t >> value) >> +{ >> +    struct tdx_hypercall_args args = { >> +        .r11 = TDG_VP_VMCALL_INSTRUCTION_WRMSR, >> +        .r12 = index, >> +        .r13 = value, >> +    }; >> + >> +    return __tdx_hypercall(&args, 0); >> +} >> 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 699cba36e9ce..5db3701cc6d9 100644 >> --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c >> +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c >> @@ -515,6 +515,213 @@ void verify_guest_reads(void) >>       printf("\t ... PASSED\n"); >>   } >>   +/* >> + * Define a filter which denies all MSR access except the following: >> + * MSR_X2APIC_APIC_ICR: Allow read/write access (allowed by default) > > The default filtering behavior of tdx_msr_test_filter is > KVM_MSR_FILTER_DEFAULT_DENY, and MSR_X2APIC_APIC_ICR is not covered > by any specific range, shouldn't MSR_X2APIC_APIC_ICR be denied by > default? Sorry, please ignore this comment. I see the description from the KVM document later: "x2APIC MSR accesses cannot be filtered (KVM silently ignores filters that cover any x2APIC MSRs)." > >> + * MSR_IA32_MISC_ENABLE: Allow read access >> + * MSR_IA32_POWER_CTL: Allow write access >> + */ >> +#define MSR_X2APIC_APIC_ICR 0x830 >> +static u64 tdx_msr_test_allow_bits = 0xFFFFFFFFFFFFFFFF; >> +struct kvm_msr_filter tdx_msr_test_filter = { >> +    .flags = KVM_MSR_FILTER_DEFAULT_DENY, >> +    .ranges = { >> +        { >> +            .flags = KVM_MSR_FILTER_READ, >> +            .nmsrs = 1, >> +            .base = MSR_IA32_MISC_ENABLE, >> +            .bitmap = (uint8_t *)&tdx_msr_test_allow_bits, >> +        }, { >> +            .flags = KVM_MSR_FILTER_WRITE, >> +            .nmsrs = 1, >> +            .base = MSR_IA32_POWER_CTL, >> +            .bitmap = (uint8_t *)&tdx_msr_test_allow_bits, >> +        }, >> +    }, >> +}; >> + >> +/* >> + * Verifies MSR read functionality. >> + */ >> +void guest_msr_read(void) >> +{ >> +    uint64_t data; >> +    uint64_t ret; >> + >> +    ret = tdg_vp_vmcall_instruction_rdmsr(MSR_X2APIC_APIC_ICR, &data); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    ret = tdx_test_report_64bit_to_user_space(data); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    ret = tdg_vp_vmcall_instruction_rdmsr(MSR_IA32_MISC_ENABLE, &data); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    ret = tdx_test_report_64bit_to_user_space(data); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    /* We expect this call to fail since MSR_IA32_POWER_CTL is write >> only */ >> +    ret = tdg_vp_vmcall_instruction_rdmsr(MSR_IA32_POWER_CTL, &data); >> +    if (ret) { >> +        ret = tdx_test_report_64bit_to_user_space(ret); >> +        if (ret) >> +            tdx_test_fatal(ret); >> +    } else { >> +        tdx_test_fatal(-99); >> +    } >> + >> +    tdx_test_success(); >> +} >> + >> +void verify_guest_msr_reads(void) >> +{ >> +    struct kvm_vm *vm; >> +    struct kvm_vcpu *vcpu; >> + >> +    uint64_t data; >> +    int ret; >> + >> +    vm = td_create(); >> +    td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); >> + >> +    /* >> +     * 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, &tdx_msr_test_filter); >> +    TEST_ASSERT(ret == 0, >> +            "KVM_X86_SET_MSR_FILTER failed, ret: %i errno: %i (%s)", >> +            ret, errno, strerror(errno)); >> + >> +    vcpu = td_vcpu_add(vm, 0, guest_msr_read); >> +    td_finalize(vm); >> + >> +    printf("Verifying guest msr reads:\n"); >> + >> +    printf("\t ... Setting test MSR values\n"); >> +    /* Write arbitrary to the MSRs. */ >> +    vcpu_set_msr(vcpu, MSR_X2APIC_APIC_ICR, 4); >> +    vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE, 5); >> +    vcpu_set_msr(vcpu, MSR_IA32_POWER_CTL, 6); >> + >> +    printf("\t ... Running guest\n"); >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_CHECK_GUEST_FAILURE(vcpu); >> +    data = tdx_test_read_64bit_report_from_guest(vcpu); >> +    TEST_ASSERT_EQ(data, 4); >> + >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_CHECK_GUEST_FAILURE(vcpu); >> +    data = tdx_test_read_64bit_report_from_guest(vcpu); >> +    TEST_ASSERT_EQ(data, 5); >> + >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_CHECK_GUEST_FAILURE(vcpu); >> +    data = tdx_test_read_64bit_report_from_guest(vcpu); >> +    TEST_ASSERT_EQ(data, TDG_VP_VMCALL_INVALID_OPERAND); >> + >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_ASSERT_SUCCESS(vcpu); >> + >> +    kvm_vm_free(vm); >> +    printf("\t ... PASSED\n"); >> +} >> + >> +/* >> + * Verifies MSR write functionality. >> + */ >> +void guest_msr_write(void) >> +{ >> +    uint64_t ret; >> + >> +    ret = tdg_vp_vmcall_instruction_wrmsr(MSR_X2APIC_APIC_ICR, 4); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    /* We expect this call to fail since MSR_IA32_MISC_ENABLE is >> read only */ >> +    ret = tdg_vp_vmcall_instruction_wrmsr(MSR_IA32_MISC_ENABLE, 5); >> +    if (ret) { >> +        ret = tdx_test_report_64bit_to_user_space(ret); >> +        if (ret) >> +            tdx_test_fatal(ret); >> +    } else { >> +        tdx_test_fatal(-99); >> +    } >> + >> + >> +    ret = tdg_vp_vmcall_instruction_wrmsr(MSR_IA32_POWER_CTL, 6); >> +    if (ret) >> +        tdx_test_fatal(ret); >> + >> +    tdx_test_success(); >> +} >> + >> +void verify_guest_msr_writes(void) >> +{ >> +    struct kvm_vcpu *vcpu; >> +    struct kvm_vm *vm; >> + >> +    uint64_t data; >> +    int ret; >> + >> +    vm = td_create(); >> +    td_initialize(vm, VM_MEM_SRC_ANONYMOUS, 0); >> + >> +    /* >> +     * 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, &tdx_msr_test_filter); >> +    TEST_ASSERT(ret == 0, >> +            "KVM_X86_SET_MSR_FILTER failed, ret: %i errno: %i (%s)", >> +            ret, errno, strerror(errno)); >> + >> +    vcpu = td_vcpu_add(vm, 0, guest_msr_write); >> +    td_finalize(vm); >> + >> +    printf("Verifying guest msr writes:\n"); >> + >> +    printf("\t ... Running guest\n"); >> +    /* Only the write to MSR_IA32_MISC_ENABLE should trigger an exit */ >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_CHECK_GUEST_FAILURE(vcpu); >> +    data = tdx_test_read_64bit_report_from_guest(vcpu); >> +    TEST_ASSERT_EQ(data, TDG_VP_VMCALL_INVALID_OPERAND); >> + >> +    td_vcpu_run(vcpu); >> +    TDX_TEST_ASSERT_SUCCESS(vcpu); >> + >> +    printf("\t ... Verifying MSR values writen by guest\n"); >> + >> +    TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_X2APIC_APIC_ICR), 4); >> +    TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_MISC_ENABLE), 0x1800); >> +    TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_POWER_CTL), 6); >> + >> +    kvm_vm_free(vm); >> +    printf("\t ... PASSED\n"); >> +} >> + >> + >>   int main(int argc, char **argv) >>   { >>       setbuf(stdout, NULL); >> @@ -531,6 +738,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_writes); >> +    run_in_new_process(&verify_guest_msr_reads); >>         return 0; >>   } > >