lkml.org 
[lkml]   [2022]   [Aug]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[RFC PATCH v2 14/17] KVM: selftest: TDX: Add TDX CPUID TDVMCALL test
    From
    This test issues a CPUID TDVMCALL from inside the guest to get the CPUID
    values as seen by KVM.

    Signed-off-by: Sagi Shahar <sagis@google.com>
    ---
    tools/testing/selftests/kvm/lib/x86_64/tdx.h | 23 ++++
    .../selftests/kvm/x86_64/tdx_vm_tests.c | 102 ++++++++++++++++++
    2 files changed, 125 insertions(+)

    diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
    index 17e3649e5729..3729543a05a3 100644
    --- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h
    +++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
    @@ -56,6 +56,7 @@

    #define TDX_GET_TD_VM_CALL_INFO 0x10000
    #define TDX_REPORT_FATAL_ERROR 0x10003
    +#define TDX_INSTRUCTION_CPUID 10
    #define TDX_INSTRUCTION_HLT 12
    #define TDX_INSTRUCTION_IO 30
    #define TDX_INSTRUCTION_RDMSR 31
    @@ -347,6 +348,28 @@ static inline uint64_t tdvmcall_mmio_write(uint64_t address, uint64_t size, uint
    return regs.r10;
    }

    +/*
    + * Execute CPUID instruction.
    + */
    +static inline uint64_t tdvmcall_cpuid(uint32_t eax, uint32_t ecx,
    + uint32_t *ret_eax, uint32_t *ret_ebx,
    + uint32_t *ret_ecx, uint32_t *ret_edx)
    +{
    + struct kvm_regs regs;
    +
    + memset(&regs, 0, sizeof(regs));
    + regs.r11 = TDX_INSTRUCTION_CPUID;
    + regs.r12 = eax;
    + regs.r13 = ecx;
    + regs.rcx = 0xFC00;
    + tdcall(&regs);
    + *ret_eax = regs.r12;
    + *ret_ebx = regs.r13;
    + *ret_ecx = regs.r14;
    + *ret_edx = regs.r15;
    + 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 382119bd444b..934f2f7a5df9 100644
    --- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
    +++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
    @@ -459,6 +459,107 @@ void verify_td_cpuid(void)
    printf("\t ... PASSED\n");
    }

    +/*
    + * Verifies CPUID TDVMCALL functionality.
    + * The guest will then send the values to userspace using an IO write to be
    + * checked against the expected values.
    + */
    +TDX_GUEST_FUNCTION(guest_code_cpuid_tdcall)
    +{
    + uint64_t err;
    + uint32_t eax, ebx, ecx, edx;
    +
    + // Read CPUID leaf 0x1 from host.
    + err = tdvmcall_cpuid(/*eax=*/1, /*ecx=*/0, &eax, &ebx, &ecx, &edx);
    + if (err)
    + tdvmcall_fatal(err);
    +
    + err = tdvm_report_to_user_space(eax);
    + if (err)
    + tdvmcall_fatal(err);
    +
    + err = tdvm_report_to_user_space(ebx);
    + if (err)
    + tdvmcall_fatal(err);
    +
    + err = tdvm_report_to_user_space(ecx);
    + if (err)
    + tdvmcall_fatal(err);
    +
    + err = tdvm_report_to_user_space(edx);
    + if (err)
    + tdvmcall_fatal(err);
    +
    + tdvmcall_success();
    +}
    +
    +void verify_td_cpuid_tdcall(void)
    +{
    + struct kvm_vcpu *vcpu;
    + struct kvm_vm *vm;
    + uint32_t eax, ebx, ecx, edx;
    + struct kvm_cpuid_entry2 *cpuid_entry;
    + struct tdx_cpuid_data cpuid_data;
    + int ret;
    +
    + printf("Verifying TD CPUID TDVMCALL:\n");
    + /* Create a TD VM with no memory.*/
    + vm = 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_tdcall,
    + TDX_FUNCTION_SIZE(guest_code_cpuid_tdcall), 0);
    + finalize_td_memory(vm);
    +
    + /* Wait for guest to report CPUID values */
    + vcpu_run(vcpu);
    + CHECK_GUEST_FAILURE(vcpu);
    + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
    + eax = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
    +
    + vcpu_run(vcpu);
    + CHECK_GUEST_FAILURE(vcpu);
    + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
    + ebx = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
    +
    + vcpu_run(vcpu);
    + CHECK_GUEST_FAILURE(vcpu);
    + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
    + ecx = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
    +
    + vcpu_run(vcpu);
    + CHECK_GUEST_FAILURE(vcpu);
    + CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
    + edx = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
    +
    + vcpu_run(vcpu);
    + CHECK_GUEST_FAILURE(vcpu);
    + CHECK_GUEST_COMPLETION(vcpu);
    +
    + /* Get KVM CPUIDs for reference */
    + memset(&cpuid_data, 0, sizeof(cpuid_data));
    + cpuid_data.cpuid.nent = 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");
    +
    + ASSERT_EQ(cpuid_entry->eax, eax);
    + // Mask lapic ID when comparing ebx.
    + ASSERT_EQ(cpuid_entry->ebx & ~0xFF000000, ebx & ~0xFF000000);
    + ASSERT_EQ(cpuid_entry->ecx, ecx);
    + ASSERT_EQ(cpuid_entry->edx, edx);
    +
    + kvm_vm_free(vm);
    + printf("\t ... PASSED\n");
    +}
    +
    /*
    * Verifies get_td_vmcall_info functionality.
    */
    @@ -1184,6 +1285,7 @@ int main(int argc, char **argv)
    run_in_new_process(&verify_report_fatal_error);
    run_in_new_process(&verify_td_ioexit);
    run_in_new_process(&verify_td_cpuid);
    + run_in_new_process(&verify_td_cpuid_tdcall);
    run_in_new_process(&verify_get_td_vmcall_info);
    run_in_new_process(&verify_guest_writes);
    run_in_new_process(&verify_guest_reads);
    --
    2.37.2.789.g6183377224-goog
    \
     
     \ /
      Last update: 2022-08-31 00:23    [W:2.817 / U:0.160 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site