On Thu, May 21, 2026, Lisa Wang wrote:
> 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)

I think we should use an x86-specific GPA, not the first address past memslot0.
Unlike other architectures, x86 has a nice swath of addresses that are pretty
much guaranteed to be unused, thanks to selftests creating a local APIC by 
default.
On the other hand, the chances of a collision with a memslot just after memslot0
are decidedly non-zero.

Note, because CoCo VMS don't support read-only memslots, the TODO in 
__vm_create()
can't be resolved for TDX using the suggested shenanigans.

I vote for either the I/O APIC (0xfec00000) or HPET(0xfed00000).  We *know* TDX
doesn't support an in-kernel I/O APIC, and the odds of KVM selftests ever
implementing an I/O APIC are basically nil.  Ditto for the HPET.

> +{
> +     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;

Drop host_ucall_mmio_gpa entirely.  "host GPA" is rather nonsensical, and KVM is
responsible for stripping the shared bit.  You can actually drop ucall_mmio_gpa
as well if we go with a hardcoded magic address.

> +             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);

s/MMIO_SIZE_8B/sizeof(hva_t), because what you're writing is the address of a
pointer in the host virtual address space.

> +             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));

This needs to return NULL.  Either that or make this an if-elif.  Falling
through to the normal KVM_EXIT_IO check is not what we want.

Reply via email to