From: Ackerley Tng <[email protected]>

Implement TDX ucall using TDCALL-based MMIO to pass the ucall address
from the VM to the host.

In standard KVM selftests, ucall uses a PIO instruction as a trigger
to exit to the host, which then retrieves the ucall address by reading
the guest's RDI register. This approach is incompatible with TDX
because the host cannot access guest registers.

Furthermore, PIO exits only expose 4 bytes of immediate data, which
is insufficient for a 8-byte ucall address. By using TDCALL-based MMIO,
the VM can share the full 8-byte address in a single exit without
refactoring the common ucall framework and other non-x86 architectures.

Signed-off-by: Ackerley Tng <[email protected]>
Co-developed-by: Sagi Shahar <[email protected]>
Signed-off-by: Sagi Shahar <[email protected]>
Co-developed-by: Lisa Wang <[email protected]>
Signed-off-by: Lisa Wang <[email protected]>
---
 tools/testing/selftests/kvm/include/x86/ucall.h |  6 -----
 tools/testing/selftests/kvm/lib/x86/ucall.c     | 30 +++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/ucall.h 
b/tools/testing/selftests/kvm/include/x86/ucall.h
index 0e4950041e3e..7e54ec2c1a45 100644
--- a/tools/testing/selftests/kvm/include/x86/ucall.h
+++ b/tools/testing/selftests/kvm/include/x86/ucall.h
@@ -2,12 +2,6 @@
 #ifndef SELFTEST_KVM_UCALL_H
 #define SELFTEST_KVM_UCALL_H
 
-#include "kvm_util.h"
-
 #define UCALL_EXIT_REASON       KVM_EXIT_IO
 
-static inline void ucall_arch_init(struct kvm_vm *vm, gpa_t mmio_gpa)
-{
-}
-
 #endif
diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c 
b/tools/testing/selftests/kvm/lib/x86/ucall.c
index e7dd5791959b..c8e3418d53af 100644
--- a/tools/testing/selftests/kvm/lib/x86/ucall.c
+++ b/tools/testing/selftests/kvm/lib/x86/ucall.c
@@ -5,11 +5,34 @@
  * Copyright (C) 2018, Red Hat, Inc.
  */
 #include "kvm_util.h"
+#include "tdx/tdx.h"
+#include "tdx/tdx_util.h"
 
 #define UCALL_PIO_PORT ((u16)0x1000)
 
+static u8 vm_type;
+static gpa_t host_ucall_mmio_gpa;
+static gpa_t ucall_mmio_gpa;
+
+void ucall_arch_init(struct kvm_vm *vm, gpa_t mmio_gpa)
+{
+       vm_type = vm->type;
+       sync_global_to_guest(vm, vm_type);
+
+       if (is_tdx_vm(vm)) {
+               host_ucall_mmio_gpa = ucall_mmio_gpa = mmio_gpa;
+               ucall_mmio_gpa |= vm->arch.s_bit;
+               sync_global_to_guest(vm, ucall_mmio_gpa);
+       }
+}
+
 void ucall_arch_do_ucall(gva_t uc)
 {
+       if (vm_type == KVM_X86_TDX_VM) {
+               tdx_mmio_write(ucall_mmio_gpa, MMIO_SIZE_8B, uc);
+               return;
+       }
+
        /*
         * FIXME: Revert this hack (the entire commit that added it) once nVMX
         * preserves L2 GPRs across a nested VM-Exit.  If a ucall from L2, e.g.
@@ -46,6 +69,13 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *run = vcpu->run;
 
+       if (vm_type == KVM_X86_TDX_VM) {
+               if (run->exit_reason == KVM_EXIT_MMIO &&
+                   run->mmio.phys_addr == host_ucall_mmio_gpa &&
+                   run->mmio.len == MMIO_SIZE_8B && run->mmio.is_write)
+                       return (void *)(*((u64 *)run->mmio.data));
+       }
+
        if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
                struct kvm_regs regs;
 

-- 
2.54.0.746.g67dd491aae-goog


Reply via email to