A fully enlightened TDX guest on Hyper-V (i.e. without the paravisor) only uses the GHCI call rather than hv_hypercall_pg. In hv_do_hypercall(), Hyper-V requires that the input/output addresses must have the cc_mask. Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> Reviewed-by: Michael Kelley <mikelley@xxxxxxxxxxxxx> Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx> --- Changes in v2: Included asm/coco.h in arch/x86/include/asm/mshyperv.h to avoid a gcc warning: "implicit declaration of cc_mkdec" arch/x86/hyperv/hv_init.c | 8 ++++++++ arch/x86/hyperv/ivm.c | 17 +++++++++++++++++ arch/x86/include/asm/mshyperv.h | 17 +++++++++++++++++ drivers/hv/hv_common.c | 10 ++++++++-- include/asm-generic/mshyperv.h | 1 + 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index bcfbcda8b050c..255e02ec467eb 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -476,6 +476,10 @@ void __init hyperv_init(void) /* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ hv_ghcb_msr_write(HV_X64_MSR_GUEST_OS_ID, guest_id); + /* A TDX guest uses the GHCI call rather than hv_hypercall_pg. */ + if (hv_isolation_type_tdx()) + goto skip_hypercall_pg_init; + hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, NUMA_NO_NODE, @@ -515,6 +519,7 @@ void __init hyperv_init(void) wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); } +skip_hypercall_pg_init: /* * hyperv_init() is called before LAPIC is initialized: see * apic_intr_mode_init() -> x86_platform.apic_post_init() and @@ -642,6 +647,9 @@ bool hv_is_hyperv_initialized(void) if (x86_hyper_type != X86_HYPER_MS_HYPERV) return false; + /* A TDX guest uses the GHCI call rather than hv_hypercall_pg. */ + if (hv_isolation_type_tdx()) + return true; /* * Verify that earlier initialization succeeded by checking * that the hypercall page is setup diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index afdae1a8a1177..6c7598d9e68a3 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -571,3 +571,20 @@ bool hv_isolation_type_tdx(void) { return static_branch_unlikely(&isolation_type_tdx); } + +#ifdef CONFIG_INTEL_TDX_GUEST + +u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2) +{ + struct tdx_hypercall_args args = { }; + + args.r10 = control; + args.rdx = param1; + args.r8 = param2; + + (void)__tdx_hypercall_ret(&args); + + return args.r11; +} + +#endif diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index e18c6c8f4fba8..24d7f662a8beb 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -5,6 +5,7 @@ #include <linux/types.h> #include <linux/nmi.h> #include <linux/msi.h> +#include <asm/coco.h> #include <asm/io.h> #include <asm/hyperv-tlfs.h> #include <asm/nospec-branch.h> @@ -51,6 +52,7 @@ extern union hv_ghcb * __percpu *hv_ghcb_pg; extern bool hv_isolation_type_en_snp(void); bool hv_isolation_type_tdx(void); +u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); /* * DEFAULT INIT GPAT and SEGMENT LIMIT value in struct VMSA @@ -63,6 +65,10 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages); int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id); int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags); +/* + * If the hypercall involves no input or output parameters, the hypervisor + * ignores the corresponding GPA pointer. + */ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) { u64 input_address = input ? virt_to_phys(input) : 0; @@ -70,6 +76,11 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output) u64 hv_status; #ifdef CONFIG_X86_64 + if (hv_isolation_type_tdx()) + return hv_tdx_hypercall(control, + cc_mkdec(input_address), + cc_mkdec(output_address)); + if (hv_isolation_type_en_snp()) { __asm__ __volatile__("mov %4, %%r8\n" "vmmcall" @@ -123,6 +134,9 @@ static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1) u64 hv_status; #ifdef CONFIG_X86_64 + if (hv_isolation_type_tdx()) + return hv_tdx_hypercall(control, input1, 0); + if (hv_isolation_type_en_snp()) { __asm__ __volatile__( "vmmcall" @@ -174,6 +188,9 @@ static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2) u64 hv_status; #ifdef CONFIG_X86_64 + if (hv_isolation_type_tdx()) + return hv_tdx_hypercall(control, input1, input2); + if (hv_isolation_type_en_snp()) { __asm__ __volatile__("mov %4, %%r8\n" "vmmcall" diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index da3307533f4d7..897bbb96f4118 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -381,10 +381,10 @@ int hv_common_cpu_init(unsigned int cpu) *outputarg = (char *)(*inputarg) + HV_HYP_PAGE_SIZE; } - if (hv_isolation_type_en_snp()) { + if (hv_isolation_type_en_snp() || hv_isolation_type_tdx()) { ret = set_memory_decrypted((unsigned long)*inputarg, pgcount); if (ret) { - kfree(*inputarg); + /* It may be unsafe to free *inputarg */ *inputarg = NULL; return ret; } @@ -567,3 +567,9 @@ u64 __weak hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_s return HV_STATUS_INVALID_PARAMETER; } EXPORT_SYMBOL_GPL(hv_ghcb_hypercall); + +u64 __weak hv_tdx_hypercall(u64 control, u64 param1, u64 param2) +{ + return HV_STATUS_INVALID_PARAMETER; +} +EXPORT_SYMBOL_GPL(hv_tdx_hypercall); diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index 82eba2d5fc4cd..f577eff58ea0b 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -283,6 +283,7 @@ enum hv_isolation_type hv_get_isolation_type(void); bool hv_is_isolation_supported(void); bool hv_isolation_type_snp(void); u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); +u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2); void hyperv_cleanup(void); bool hv_query_ext_cap(u64 cap_query); void hv_setup_dma_ops(struct device *dev, bool coherent); -- 2.25.1