Commit 68f2f2bc authored by Dexuan Cui's avatar Dexuan Cui Committed by Wei Liu

Drivers: hv: vmbus: Support fully enlightened TDX guests

Add Hyper-V specific code so that a fully enlightened TDX guest (i.e.
without the paravisor) can run on Hyper-V:
  Don't use hv_vp_assist_page. Use GHCI instead.
  Don't try to use the unsupported HV_REGISTER_CRASH_CTL.
  Don't trust (use) Hyper-V's TLB-flushing hypercalls.
  Don't use lazy EOI.
  Share the SynIC Event/Message pages with the hypervisor.
  Don't use the Hyper-V TSC page for now, because non-trivial work is
    required to share the page with the hypervisor.
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarWei Liu <wei.liu@kernel.org>
Link: https://lore.kernel.org/r/20230824080712.30327-4-decui@microsoft.com
parent d6e0228d
...@@ -177,8 +177,11 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector, ...@@ -177,8 +177,11 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector,
(exclude_self && weight == 1 && cpumask_test_cpu(this_cpu, mask))) (exclude_self && weight == 1 && cpumask_test_cpu(this_cpu, mask)))
return true; return true;
if (!hv_hypercall_pg) /* A fully enlightened TDX VM uses GHCI rather than hv_hypercall_pg. */
return false; if (!hv_hypercall_pg) {
if (ms_hyperv.paravisor_present || !hv_isolation_type_tdx())
return false;
}
if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR)) if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
return false; return false;
...@@ -231,9 +234,15 @@ static bool __send_ipi_one(int cpu, int vector) ...@@ -231,9 +234,15 @@ static bool __send_ipi_one(int cpu, int vector)
trace_hyperv_send_ipi_one(cpu, vector); trace_hyperv_send_ipi_one(cpu, vector);
if (!hv_hypercall_pg || (vp == VP_INVAL)) if (vp == VP_INVAL)
return false; return false;
/* A fully enlightened TDX VM uses GHCI rather than hv_hypercall_pg. */
if (!hv_hypercall_pg) {
if (ms_hyperv.paravisor_present || !hv_isolation_type_tdx())
return false;
}
if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR)) if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
return false; return false;
......
...@@ -80,7 +80,7 @@ static int hyperv_init_ghcb(void) ...@@ -80,7 +80,7 @@ static int hyperv_init_ghcb(void)
static int hv_cpu_init(unsigned int cpu) static int hv_cpu_init(unsigned int cpu)
{ {
union hv_vp_assist_msr_contents msr = { 0 }; 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; int ret;
ret = hv_common_cpu_init(cpu); ret = hv_common_cpu_init(cpu);
...@@ -90,6 +90,7 @@ static int hv_cpu_init(unsigned int cpu) ...@@ -90,6 +90,7 @@ static int hv_cpu_init(unsigned int cpu)
if (!hv_vp_assist_page) if (!hv_vp_assist_page)
return 0; return 0;
hvp = &hv_vp_assist_page[cpu];
if (hv_root_partition) { if (hv_root_partition) {
/* /*
* For root partition we get the hypervisor provided VP assist * For root partition we get the hypervisor provided VP assist
...@@ -442,11 +443,21 @@ void __init hyperv_init(void) ...@@ -442,11 +443,21 @@ void __init hyperv_init(void)
if (hv_common_init()) if (hv_common_init())
return; 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) { if (!hv_vp_assist_page) {
ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED; ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED;
goto common_free;
if (!hv_isolation_type_tdx())
goto common_free;
} }
if (hv_isolation_type_snp()) { if (hv_isolation_type_snp()) {
......
...@@ -420,6 +420,20 @@ static void __init ms_hyperv_init_platform(void) ...@@ -420,6 +420,20 @@ static void __init ms_hyperv_init_platform(void)
static_branch_enable(&isolation_type_en_snp); static_branch_enable(&isolation_type_en_snp);
} else if (hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) { } else if (hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) {
static_branch_enable(&isolation_type_tdx); static_branch_enable(&isolation_type_tdx);
/* A TDX VM must use x2APIC and doesn't use lazy EOI. */
ms_hyperv.hints &= ~HV_X64_APIC_ACCESS_RECOMMENDED;
if (!ms_hyperv.paravisor_present) {
/* To be supported: more work is required. */
ms_hyperv.features &= ~HV_MSR_REFERENCE_TSC_AVAILABLE;
/* HV_REGISTER_CRASH_CTL is unsupported. */
ms_hyperv.misc_features &= ~HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
/* Don't trust Hyper-V's TLB-flushing hypercalls. */
ms_hyperv.hints &= ~HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED;
}
} }
} }
......
...@@ -121,11 +121,15 @@ int hv_synic_alloc(void) ...@@ -121,11 +121,15 @@ int hv_synic_alloc(void)
(void *)get_zeroed_page(GFP_ATOMIC); (void *)get_zeroed_page(GFP_ATOMIC);
if (hv_cpu->synic_event_page == NULL) { if (hv_cpu->synic_event_page == NULL) {
pr_err("Unable to allocate SYNIC event page\n"); pr_err("Unable to allocate SYNIC event page\n");
free_page((unsigned long)hv_cpu->synic_message_page);
hv_cpu->synic_message_page = NULL;
goto err; goto err;
} }
} }
if (hv_isolation_type_en_snp()) { if (!ms_hyperv.paravisor_present &&
(hv_isolation_type_en_snp() || hv_isolation_type_tdx())) {
ret = set_memory_decrypted((unsigned long) ret = set_memory_decrypted((unsigned long)
hv_cpu->synic_message_page, 1); hv_cpu->synic_message_page, 1);
if (ret) { if (ret) {
...@@ -174,7 +178,8 @@ void hv_synic_free(void) ...@@ -174,7 +178,8 @@ void hv_synic_free(void)
= per_cpu_ptr(hv_context.cpu_context, cpu); = per_cpu_ptr(hv_context.cpu_context, cpu);
/* It's better to leak the page if the encryption fails. */ /* It's better to leak the page if the encryption fails. */
if (hv_isolation_type_en_snp()) { if (!ms_hyperv.paravisor_present &&
(hv_isolation_type_en_snp() || hv_isolation_type_tdx())) {
if (hv_cpu->synic_message_page) { if (hv_cpu->synic_message_page) {
ret = set_memory_encrypted((unsigned long) ret = set_memory_encrypted((unsigned long)
hv_cpu->synic_message_page, 1); hv_cpu->synic_message_page, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment