From: Dexuan Cui <decui@xxxxxxxxxxxxx> Sent: Tuesday, December 6, 2022 4:33 PM > > Add Hyper-V specific code so that a TDX guest can run on Hyper-V: > No need to use hv_vp_assist_page. > Don't use the unsafe Hyper-V TSC page. > Don't try to use HV_REGISTER_CRASH_CTL. > Share SynIC Event/Message pages and VMBus Monitor pages with the host. > Use pgprot_decrypted(PAGE_KERNEL_NOENC))in hv_ringbuffer_init(). > > Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx> > > Changes in v2: > Used a new function hv_set_memory_enc_dec_needed() in > __set_memory_enc_pgtable(). > Added the missing set_memory_encrypted() in hv_synic_free(). > > --- > > arch/x86/hyperv/hv_init.c | 19 ++++++++--- > arch/x86/hyperv/ivm.c | 5 +++ > arch/x86/kernel/cpu/mshyperv.c | 17 +++++++++- > arch/x86/mm/pat/set_memory.c | 2 +- > drivers/hv/connection.c | 4 ++- > drivers/hv/hv.c | 60 +++++++++++++++++++++++++++++++++- > drivers/hv/hv_common.c | 6 ++++ > drivers/hv/ring_buffer.c | 2 +- > include/asm-generic/mshyperv.h | 2 ++ > 9 files changed, 108 insertions(+), 9 deletions(-) > > diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c > index c0ba53ad8b8e..8d7b63346194 100644 > --- a/arch/x86/hyperv/hv_init.c > +++ b/arch/x86/hyperv/hv_init.c > @@ -77,7 +77,7 @@ static int hyperv_init_ghcb(void) > static int hv_cpu_init(unsigned int cpu) > { > union hv_vp_assist_msr_contents msr = { 0 }; > - struct hv_vp_assist_page **hvp = &hv_vp_assist_page[cpu]; > + struct hv_vp_assist_page **hvp; > int ret; > > ret = hv_common_cpu_init(cpu); > @@ -87,6 +87,7 @@ static int hv_cpu_init(unsigned int cpu) > if (!hv_vp_assist_page) > return 0; > > + hvp = &hv_vp_assist_page[cpu]; > if (hv_root_partition) { > /* > * For root partition we get the hypervisor provided VP assist > @@ -396,11 +397,21 @@ void __init hyperv_init(void) > if (hv_common_init()) > return; > > - hv_vp_assist_page = kcalloc(num_possible_cpus(), > - sizeof(*hv_vp_assist_page), GFP_KERNEL); > + /* > + * The VP assist page is useless to a TDX guest: the only use we > + * would have for it is lazy EOI, which can not be used with TDX. > + */ > + if (hv_isolation_type_tdx()) > + hv_vp_assist_page = NULL; > + else > + hv_vp_assist_page = kcalloc(num_possible_cpus(), > + sizeof(*hv_vp_assist_page), > + GFP_KERNEL); > if (!hv_vp_assist_page) { > ms_hyperv.hints &= > ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED; > - goto common_free; > + > + if (!hv_isolation_type_tdx()) > + goto common_free; > } > > if (hv_isolation_type_snp()) { > diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c > index 07e4253b5809..4398042f10d5 100644 > --- a/arch/x86/hyperv/ivm.c > +++ b/arch/x86/hyperv/ivm.c > @@ -258,6 +258,11 @@ bool hv_is_isolation_supported(void) > return hv_get_isolation_type() != HV_ISOLATION_TYPE_NONE; > } > > +bool hv_set_memory_enc_dec_needed(void) > +{ > + return hv_is_isolation_supported() && !hv_isolation_type_tdx(); > +} > + > DEFINE_STATIC_KEY_FALSE(isolation_type_snp); > > /* > diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c > index 941372449ff2..24569da3c1f8 100644 > --- a/arch/x86/kernel/cpu/mshyperv.c > +++ b/arch/x86/kernel/cpu/mshyperv.c > @@ -345,8 +345,23 @@ static void __init ms_hyperv_init_platform(void) > } > > if (IS_ENABLED(CONFIG_INTEL_TDX_GUEST) && > - hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) > + hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) { > static_branch_enable(&isolation_type_tdx); > + > + /* > + * The GPAs of SynIC Event/Message pages and VMBus > + * Moniter pages need to be added by this offset. > + */ > + ms_hyperv.shared_gpa_boundary = cc_mkdec(0); > + > + /* Don't use the unsafe Hyper-V TSC page */ > + ms_hyperv.features &= > + ~HV_MSR_REFERENCE_TSC_AVAILABLE; > + > + /* HV_REGISTER_CRASH_CTL is unsupported */ > + ms_hyperv.misc_features &= > + ~HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; > + } > } > > if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) { > diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c > index 2e5a045731de..5892196f8ade 100644 > --- a/arch/x86/mm/pat/set_memory.c > +++ b/arch/x86/mm/pat/set_memory.c > @@ -2120,7 +2120,7 @@ static int __set_memory_enc_pgtable(unsigned long addr, > int numpages, bool enc) > > static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc) > { > - if (hv_is_isolation_supported()) > + if (hv_set_memory_enc_dec_needed()) > return hv_set_mem_host_visibility(addr, numpages, !enc); > > if (cc_platform_has(CC_ATTR_MEM_ENCRYPT)) > diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c > index 9dc27e5d367a..1ecc3c29e3f7 100644 > --- a/drivers/hv/connection.c > +++ b/drivers/hv/connection.c > @@ -250,12 +250,14 @@ int vmbus_connect(void) > * Isolation VM with AMD SNP needs to access monitor page via > * address space above shared gpa boundary. > */ > - if (hv_isolation_type_snp()) { > + if (hv_isolation_type_snp() || hv_isolation_type_tdx()) { > vmbus_connection.monitor_pages_pa[0] += > ms_hyperv.shared_gpa_boundary; > vmbus_connection.monitor_pages_pa[1] += > ms_hyperv.shared_gpa_boundary; > + } > > + if (hv_isolation_type_snp()) { > vmbus_connection.monitor_pages[0] > = > memremap(vmbus_connection.monitor_pages_pa[0], > HV_HYP_PAGE_SIZE, > diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c > index 4d6480d57546..78aca415985c 100644 > --- a/drivers/hv/hv.c > +++ b/drivers/hv/hv.c > @@ -18,6 +18,7 @@ > #include <linux/clockchips.h> > #include <linux/delay.h> > #include <linux/interrupt.h> > +#include <linux/set_memory.h> > #include <clocksource/hyperv_timer.h> > #include <asm/mshyperv.h> > #include "hyperv_vmbus.h" > @@ -119,6 +120,7 @@ int hv_synic_alloc(void) > { > int cpu; > struct hv_per_cpu_context *hv_cpu; > + int ret = -ENOMEM; > > /* > * First, zero all per-cpu memory areas so hv_synic_free() can > @@ -168,6 +170,30 @@ int hv_synic_alloc(void) > pr_err("Unable to allocate post msg page\n"); > goto err; > } > + > + > + if (hv_isolation_type_tdx()) { > + ret = set_memory_decrypted( > + (unsigned long)hv_cpu->synic_message_page, 1); > + if (ret) { > + pr_err("Failed to decrypt SYNIC msg page\n"); > + goto err; > + } > + > + ret = set_memory_decrypted( > + (unsigned long)hv_cpu->synic_event_page, 1); > + if (ret) { > + pr_err("Failed to decrypt SYNIC event page\n"); > + goto err; > + } > + > + ret = set_memory_decrypted( > + (unsigned long)hv_cpu->post_msg_page, 1); > + if (ret) { > + pr_err("Failed to decrypt post msg page\n"); > + goto err; > + } > + } > } > > return 0; > @@ -176,18 +202,42 @@ int hv_synic_alloc(void) > * Any memory allocations that succeeded will be freed when > * the caller cleans up by calling hv_synic_free() > */ > - return -ENOMEM; > + return ret; > } > > > void hv_synic_free(void) > { > int cpu; > + int ret; > > for_each_present_cpu(cpu) { > struct hv_per_cpu_context *hv_cpu > = per_cpu_ptr(hv_context.cpu_context, cpu); > > + if (hv_isolation_type_tdx()) { > + ret = set_memory_encrypted( > + (unsigned long)hv_cpu->synic_message_page, 1); > + if (ret) { > + pr_err("Failed to encrypt SYNIC msg page\n"); > + continue; > + } > + > + ret = set_memory_encrypted( > + (unsigned long)hv_cpu->synic_event_page, 1); > + if (ret) { > + pr_err("Failed to encrypt SYNIC event page\n"); > + continue; > + } > + > + ret = set_memory_encrypted( > + (unsigned long)hv_cpu->post_msg_page, 1); > + if (ret) { > + pr_err("Failed to encrypt post msg page\n"); > + continue; > + } > + } > + > free_page((unsigned long)hv_cpu->synic_event_page); > free_page((unsigned long)hv_cpu->synic_message_page); > free_page((unsigned long)hv_cpu->post_msg_page); > @@ -225,6 +275,10 @@ void hv_synic_enable_regs(unsigned int cpu) > } else { > simp.base_simp_gpa = virt_to_phys(hv_cpu->synic_message_page) > >> HV_HYP_PAGE_SHIFT; > + > + if (hv_isolation_type_tdx()) > + simp.base_simp_gpa |= ms_hyperv.shared_gpa_boundary > + >> HV_HYP_PAGE_SHIFT; Since we're using cc_mkdec() in hv_do_hypercall() to set the SHARED bit, perhaps the same could be done here to simplify the code and avoid the explicit call to hv_isolation_type_tdx(): simp.base_simp_gpa = cc_mkdec(virt_to_phys(hv_cpu->synic_message)) >> HV_HYP_PAGE_SHIFT; cc_mkdec() does nothing in a normal VM, and vTOM VMs are already special-cased. > } > > hv_set_register(HV_REGISTER_SIMP, simp.as_uint64); > @@ -243,6 +297,10 @@ void hv_synic_enable_regs(unsigned int cpu) > } else { > siefp.base_siefp_gpa = virt_to_phys(hv_cpu->synic_event_page) > >> HV_HYP_PAGE_SHIFT; > + > + if (hv_isolation_type_tdx()) > + siefp.base_siefp_gpa |= ms_hyperv.shared_gpa_boundary > + >> HV_HYP_PAGE_SHIFT; Same here. > } > > hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64); > diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c > index a9a03ab04b97..192dcf295dfc 100644 > --- a/drivers/hv/hv_common.c > +++ b/drivers/hv/hv_common.c > @@ -262,6 +262,12 @@ bool __weak hv_is_isolation_supported(void) > } > EXPORT_SYMBOL_GPL(hv_is_isolation_supported); > > +bool __weak hv_set_memory_enc_dec_needed(void) > +{ > + return false; > +} > +EXPORT_SYMBOL_GPL(hv_set_memory_enc_dec_needed); > + > bool __weak hv_isolation_type_snp(void) > { > return false; > diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c > index c6692fd5ab15..a51da82316ce 100644 > --- a/drivers/hv/ring_buffer.c > +++ b/drivers/hv/ring_buffer.c > @@ -233,7 +233,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, > > ring_info->ring_buffer = (struct hv_ring_buffer *) > vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, > - PAGE_KERNEL); > + pgprot_decrypted(PAGE_KERNEL_NOENC)); > > kfree(pages_wraparound); > if (!ring_info->ring_buffer) > diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h > index bfb9eb9d7215..b7b1b18c9854 100644 > --- a/include/asm-generic/mshyperv.h > +++ b/include/asm-generic/mshyperv.h > @@ -262,6 +262,7 @@ bool hv_is_hyperv_initialized(void); > bool hv_is_hibernation_supported(void); > enum hv_isolation_type hv_get_isolation_type(void); > bool hv_is_isolation_supported(void); > +bool hv_set_memory_enc_dec_needed(void); > bool hv_isolation_type_snp(void); > u64 hv_ghcb_hypercall(u64 control, void *input, void *output, u32 input_size); > void hyperv_cleanup(void); > @@ -274,6 +275,7 @@ static inline bool hv_is_hyperv_initialized(void) { return false; } > static inline bool hv_is_hibernation_supported(void) { return false; } > static inline void hyperv_cleanup(void) {} > static inline bool hv_is_isolation_supported(void) { return false; } > +static inline bool hv_set_memory_enc_dec_needed(void) { return false; } > static inline enum hv_isolation_type hv_get_isolation_type(void) > { > return HV_ISOLATION_TYPE_NONE; > -- > 2.25.1