Skip to content
Permalink
Browse files
x86/tdx: Wire up KVM hypercalls
KVM hypercalls use the "vmcall" or "vmmcall" instructions.
Although the ABI is similar, those instructions no longer
function for TDX guests. Make vendor-specific TDVMCALLs
instead of VMCALL. This enables TDX guests to run with KVM
acting as the hypervisor. TDX guests running under other
hypervisors will continue to use those hypervisors'
hypercalls.

Since KVM driver can be built as a kernel module, export
tdx_kvm_hypercall*() to make the symbols visible to kvm.ko.

[Isaku Yamahata: proposed KVM VENDOR string]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Reviewed-by: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
  • Loading branch information
kiryl authored and Kuppuswamy Sathyanarayanan committed Jun 12, 2021
1 parent 248a99b commit 65aab3097498af2947a88010cc4354a2cd7edac1
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
@@ -892,6 +892,11 @@ config INTEL_TDX_GUEST
run in a CPU mode that protects the confidentiality of TD memory
contents and the TD’s CPU state from other software, including VMM.

# This option enables KVM specific hypercalls in TDX guest.
config INTEL_TDX_GUEST_KVM
def_bool y
depends on KVM_GUEST && INTEL_TDX_GUEST

endif #HYPERVISOR_GUEST

source "arch/x86/Kconfig.cpu"
@@ -5,6 +5,7 @@
#include <asm/processor.h>
#include <asm/alternative.h>
#include <linux/interrupt.h>
#include <linux/protected_guest.h>
#include <uapi/asm/kvm_para.h>

#ifdef CONFIG_KVM_GUEST
@@ -32,6 +33,10 @@ static inline bool kvm_check_and_clear_guest_paused(void)
static inline long kvm_hypercall0(unsigned int nr)
{
long ret;

if (prot_guest_has(PR_GUEST_TDX))
return tdx_kvm_hypercall(nr, 0, 0, 0, 0);

asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr)
@@ -42,6 +47,10 @@ static inline long kvm_hypercall0(unsigned int nr)
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
{
long ret;

if (prot_guest_has(PR_GUEST_TDX))
return tdx_kvm_hypercall(nr, p1, 0, 0, 0);

asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1)
@@ -53,6 +62,10 @@ static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
unsigned long p2)
{
long ret;

if (prot_guest_has(PR_GUEST_TDX))
return tdx_kvm_hypercall(nr, p1, p2, 0, 0);

asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2)
@@ -64,6 +77,10 @@ static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3)
{
long ret;

if (prot_guest_has(PR_GUEST_TDX))
return tdx_kvm_hypercall(nr, p1, p2, p3, 0);

asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3)
@@ -76,6 +93,10 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
unsigned long p4)
{
long ret;

if (prot_guest_has(PR_GUEST_TDX))
return tdx_kvm_hypercall(nr, p1, p2, p3, p4);

asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
@@ -78,4 +78,23 @@ static inline bool tdx_protected_guest_has(unsigned long flag) { return false; }

#endif /* CONFIG_INTEL_TDX_GUEST */

#ifdef CONFIG_INTEL_TDX_GUEST_KVM
u64 __tdx_hypercall_vendor_kvm(u64 fn, u64 r12, u64 r13, u64 r14,
u64 r15, struct tdx_hypercall_output *out);

static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3,
unsigned long p4)
{
return __tdx_hypercall_vendor_kvm(nr, p1, p2, p3, p4, NULL);
}
#else
static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3,
unsigned long p4)
{
return -ENODEV;
}
#endif /* CONFIG_INTEL_TDX_GUEST_KVM */

#endif /* _ASM_X86_TDX_H */
@@ -3,6 +3,7 @@
#include <asm/asm.h>
#include <asm/frame.h>
#include <asm/unwind_hints.h>
#include <asm/export.h>

#include <linux/linkage.h>
#include <linux/bits.h>
@@ -25,6 +26,8 @@
TDG_R12 | TDG_R13 | \
TDG_R14 | TDG_R15 )

#define TDVMCALL_VENDOR_KVM 0x4d564b2e584454 /* "TDX.KVM" */

/*
* TDX guests use the TDCALL instruction to make requests to the
* TDX module and hypercalls to the VMM. It is supported in
@@ -226,3 +229,26 @@ SYM_FUNC_START(__tdx_hypercall)
FRAME_END
retq
SYM_FUNC_END(__tdx_hypercall)

#ifdef CONFIG_INTEL_TDX_GUEST_KVM

/*
* Helper function for KVM vendor TDVMCALLs. This assembly wrapper
* lets us reuse do_tdvmcall() for KVM-specific hypercalls (
* TDVMCALL_VENDOR_KVM).
*/
SYM_FUNC_START(__tdx_hypercall_vendor_kvm)
FRAME_BEGIN
/*
* R10 is not part of the function call ABI, but it is a part
* of the TDVMCALL ABI. So set it before making call to the
* do_tdx_hypercall().
*/
movq $TDVMCALL_VENDOR_KVM, %r10
call do_tdx_hypercall
FRAME_END
retq
SYM_FUNC_END(__tdx_hypercall_vendor_kvm)

EXPORT_SYMBOL(__tdx_hypercall_vendor_kvm);
#endif /* CONFIG_INTEL_TDX_GUEST_KVM */

0 comments on commit 65aab30

Please sign in to comment.