On 10/2/2026 3:37 AM, Lisa Wang wrote:
> From: Sean Christopherson <[email protected]>
> 
> Add support for doing ucalls on TDX by abusing TDVMCALL_REPORT_FATAL_ERROR
> to pass the address of the payload to the host.  The "fatal error" TDVMCALL
> is perfectly suited for passing information to host userspace, is both the
                                                                  ^
                                                                 as

> TDX Module and KVM allow the guest to pass (almost) all registers to the
> host, i.e. provide enough of a data payload to make a collision with a real
> fatal error practically impossible.
> 
> TDX can't use port I/O, as the TDX ABI doesn't allow the guest to share
> arbitrary register state with the host on a port I/O exit, and the port I/O
> data payload is limited to 4 bytes, i.e. would potentially truncate the
> ucall address.
> 
> Alternatively, TDX could use MMIO, but using a magic emulated MMIO address
> is fragile (see the TODO in __vm_create()), especially for TDX since TDX
> doesn't support read-only memslots, i.e. doesn't have line of sight towards
> addressing the TODO.  E.g. TDX could hardcode the address to something that
> is all but guaranteed to be unused on x86, e.g. the I/O APIC base address
> or the HPET address, but that doesn't truly address the fragility concerns,
> and it's ugly because ucall_arch_init() would completely ignore the passed
> in @mmio_gpa despite obviously utilizing emulated MMIO.
> 
> Signed-off-by: Sean Christopherson <[email protected]>
> Signed-off-by: Lisa Wang <[email protected]>

Also one nit below.

otherwise,
Reviewed-by: Binbin Wu <[email protected]>

> ---
>  tools/testing/selftests/kvm/include/x86/tdx/tdx.h |  7 ++++++
>  tools/testing/selftests/kvm/lib/x86/ucall.c       | 27 
> ++++++++++++++++++++++-
>  2 files changed, 33 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx.h 
> b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h
> index d41a1efc8a63..9982aaaba885 100644
> --- a/tools/testing/selftests/kvm/include/x86/tdx/tdx.h
> +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h
> @@ -4,6 +4,13 @@
>  
>  #include <linux/types.h>
>  
> +/* TDX hypercall Leaf IDs */
> +#define TDVMCALL_GET_TD_VM_CALL_INFO         0x10000
> +#define TDVMCALL_MAP_GPA                     0x10001
> +#define TDVMCALL_GET_QUOTE                   0x10002
> +#define TDVMCALL_REPORT_FATAL_ERROR          0x10003
> +#define TDVMCALL_SETUP_EVENT_NOTIFY_INTERRUPT        0x10004
> +
>  u64 __tdvmcall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15);
>  
>  #endif /* SELFTEST_KVM_TDX_TDX_H */
> diff --git a/tools/testing/selftests/kvm/lib/x86/ucall.c 
> b/tools/testing/selftests/kvm/lib/x86/ucall.c
> index c003df3c7b8a..c1cd32d68464 100644
> --- a/tools/testing/selftests/kvm/lib/x86/ucall.c
> +++ b/tools/testing/selftests/kvm/lib/x86/ucall.c
> @@ -5,8 +5,28 @@
>   * 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)
> +#define UCALL_PIO_PORT               ((u16)0x1000)
> +#define UCALL_TDX_MAGIC              0xabacadabaULL
> +
> +static void ucall_tdx_do_ucall(gva_t uc)
> +{
> +     __tdvmcall(TDVMCALL_REPORT_FATAL_ERROR, UCALL_TDX_MAGIC, uc, 0, 0);
> +}
> +
> +static void *ucall_tdx_get_ucall(struct kvm_vcpu *vcpu)
> +{
> +     struct kvm_run *run = vcpu->run;
> +
> +     if (run->exit_reason == KVM_EXIT_SYSTEM_EVENT &&
> +         run->system_event.type == KVM_SYSTEM_EVENT_TDX_FATAL &&
> +         run->system_event.data[12] == UCALL_TDX_MAGIC)
> +             return (void *)(run->system_event.data[13]);

Nit:
It's more readable to have comment for data[12] and data[13] to
indicate they are the R12 and R13 passed.

> +
> +     return NULL;
> +}
>  
>  static void ucall_x86_do_ucall(gva_t uc)
>  {
> @@ -37,6 +57,11 @@ static struct {
>  
>  void ucall_arch_init(struct kvm_vm *vm, gpa_t mmio_gpa)
>  {
> +     if (is_tdx_vm(vm)) {
> +             ucall_x86_ops.do_ucall = ucall_tdx_do_ucall;
> +             ucall_x86_ops.get_ucall = ucall_tdx_get_ucall;
> +     }
> +
>       sync_global_to_guest(vm, ucall_x86_ops);
>  }
>  
> 


Reply via email to