On 5/22/2026 7:17 AM, Lisa Wang wrote: > From: Erdem Aktas <[email protected]> > > Implement the tdx_mmio_write() to allow TDX VMs to request MMIO > emulation. > > Follow the Intel Guest-Hypervisor Communication Interface (GHCI) spec > to the minimum extent that a spec-abiding TDX module will pass the > request to KVM. Skip implementing the #VE handler as described in the > GHCI spec so selftests will not take a dependency on having a working ^ Something was cut off? > > To perform emulated I/O, VMs use the TDG.VP.VMCALL instruction to > request MMIO. > > Signed-off-by: Erdem Aktas <[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/Makefile.kvm | 1 + > tools/testing/selftests/kvm/include/x86/tdx/tdx.h | 16 ++++++++++++ > tools/testing/selftests/kvm/lib/x86/tdx/tdx.c | 30 > +++++++++++++++++++++++ > 3 files changed, 47 insertions(+) > > diff --git a/tools/testing/selftests/kvm/Makefile.kvm > b/tools/testing/selftests/kvm/Makefile.kvm > index a651a876c522..489324cecf83 100644 > --- a/tools/testing/selftests/kvm/Makefile.kvm > +++ b/tools/testing/selftests/kvm/Makefile.kvm > @@ -33,6 +33,7 @@ LIBKVM_x86 += lib/x86/ucall.c > LIBKVM_x86 += lib/x86/vmx.c > LIBKVM_x86 += lib/x86/tdx/tdx_util.c > LIBKVM_x86 += lib/x86/tdx/td_boot.S > +LIBKVM_x86 += lib/x86/tdx/tdx.c > > LIBKVM_arm64 += lib/arm64/gic.c > LIBKVM_arm64 += lib/arm64/gic_v3.c > diff --git a/tools/testing/selftests/kvm/include/x86/tdx/tdx.h > b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h > new file mode 100644 > index 000000000000..810ca7423c84 > --- /dev/null > +++ b/tools/testing/selftests/kvm/include/x86/tdx/tdx.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +#ifndef SELFTESTS_TDX_TDX_H > +#define SELFTESTS_TDX_TDX_H Nit: The headers in tools/testing/selftests/kvm use SELFTEST_KVM_XXX. > + > +#include <linux/types.h> > + > +enum mmio_size { > + MMIO_SIZE_1B = 1, > + MMIO_SIZE_2B = 2, > + MMIO_SIZE_4B = 4, > + MMIO_SIZE_8B = 8 > +}; > + > +u64 tdx_mmio_write(u64 address, enum mmio_size size, u64 data_in); > + > +#endif // SELFTESTS_TDX_TDX_H > diff --git a/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c > b/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c > new file mode 100644 > index 000000000000..f19be79fe11f > --- /dev/null > +++ b/tools/testing/selftests/kvm/lib/x86/tdx/tdx.c > @@ -0,0 +1,30 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include "tdx/tdx.h" > + > +#define TDG_VP_VMCALL 0 > +#define TDG_VP_VMCALL_VE_REQUEST_MMIO 48 > +#define TDVMCALL_MMIO_WRITE 1 > +#define TDVMCALL_EXPOSE_REGS_MASK 0xFC00 > + > +u64 tdx_mmio_write(u64 address, enum mmio_size size, u64 data_in) > +{ > + register u64 r10_reg asm("r10") = TDG_VP_VMCALL; I think this should just be 0 instead of TDG_VP_VMCALL, although TDG_VP_VMCALL is also 0. Per GHCI spec about R10: : Set to 0 indicates that TDG.VP.VMCALL leaf used in R11 is defined : in this specification. : All other values 0x1 to 0xFFFFFFFFFFFFFFFF indicate TDG.VP.VMCALL : is vendor-specific (both R10 and R11). > + register u64 r11_reg asm("r11") = TDG_VP_VMCALL_VE_REQUEST_MMIO; > + register u64 r12_reg asm("r12") = size; > + register u64 r13_reg asm("r13") = TDVMCALL_MMIO_WRITE; > + register u64 r14_reg asm("r14") = address; > + register u64 r15_reg asm("r15") = data_in; > + register u64 rax_reg asm("rax") = TDG_VP_VMCALL; > + register u64 rcx_reg asm("rcx") = TDVMCALL_EXPOSE_REGS_MASK; > + > + asm volatile( > + ".byte 0x66,0x0f,0x01,0xcc" /* tdcall */ > + : "+r" (r10_reg), "+r" (r11_reg) > + : "r" (r12_reg), "r" (r13_reg), "r" (r14_reg), "r" (r15_reg), > + "r" (rax_reg), "r" (rcx_reg) > + : "cc", "memory" > + ); > + > + return r10_reg; > +} >

