OSDN Git Service

Merge tag 'hyperv-next-signed-20230902' of git://git.kernel.org/pub/scm/linux/kernel...
[tomoyo/tomoyo-test1.git] / arch / x86 / kernel / cpu / mshyperv.c
index 0100468..e6bba12 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/nmi.h>
 #include <clocksource/hyperv_timer.h>
 #include <asm/numa.h>
+#include <asm/svm.h>
 
 /* Is Linux running as the root partition? */
 bool hv_root_partition;
@@ -39,6 +40,10 @@ bool hv_root_partition;
 bool hv_nested;
 struct ms_hyperv_info ms_hyperv;
 
+/* Used in modules via hv_do_hypercall(): see arch/x86/include/asm/mshyperv.h */
+bool hyperv_paravisor_present __ro_after_init;
+EXPORT_SYMBOL_GPL(hyperv_paravisor_present);
+
 #if IS_ENABLED(CONFIG_HYPERV)
 static inline unsigned int hv_get_nested_reg(unsigned int reg)
 {
@@ -65,8 +70,8 @@ u64 hv_get_non_nested_register(unsigned int reg)
 {
        u64 value;
 
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
-               hv_ghcb_msr_read(reg, &value);
+       if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present)
+               hv_ivm_msr_read(reg, &value);
        else
                rdmsrl(reg, value);
        return value;
@@ -75,8 +80,8 @@ EXPORT_SYMBOL_GPL(hv_get_non_nested_register);
 
 void hv_set_non_nested_register(unsigned int reg, u64 value)
 {
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
-               hv_ghcb_msr_write(reg, value);
+       if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present) {
+               hv_ivm_msr_write(reg, value);
 
                /* Write proxy bit via wrmsl instruction */
                if (hv_is_sint_reg(reg))
@@ -295,6 +300,15 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
 
        native_smp_prepare_cpus(max_cpus);
 
+       /*
+        *  Override wakeup_secondary_cpu_64 callback for SEV-SNP
+        *  enlightened guest.
+        */
+       if (!ms_hyperv.paravisor_present && hv_isolation_type_snp()) {
+               apic->wakeup_secondary_cpu_64 = hv_snp_boot_ap;
+               return;
+       }
+
 #ifdef CONFIG_X86_64
        for_each_present_cpu(i) {
                if (i == 0)
@@ -313,6 +327,26 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
 }
 #endif
 
+/*
+ * When a fully enlightened TDX VM runs on Hyper-V, the firmware sets the
+ * HW_REDUCED flag: refer to acpi_tb_create_local_fadt(). Consequently ttyS0
+ * interrupts can't work because request_irq() -> ... -> irq_to_desc() returns
+ * NULL for ttyS0. This happens because mp_config_acpi_legacy_irqs() sees a
+ * nr_legacy_irqs() of 0, so it doesn't initialize the array 'mp_irqs[]', and
+ * later setup_IO_APIC_irqs() -> find_irq_entry() fails to find the legacy irqs
+ * from the array and hence doesn't create the necessary irq description info.
+ *
+ * Clone arch/x86/kernel/acpi/boot.c: acpi_generic_reduced_hw_init() here,
+ * except don't change 'legacy_pic', which keeps its default value
+ * 'default_legacy_pic'. This way, mp_config_acpi_legacy_irqs() sees a non-zero
+ * nr_legacy_irqs() and eventually serial console interrupts works properly.
+ */
+static void __init reduced_hw_init(void)
+{
+       x86_init.timers.timer_init      = x86_init_noop;
+       x86_init.irqs.pre_vector_init   = x86_init_noop;
+}
+
 static void __init ms_hyperv_init_platform(void)
 {
        int hv_max_functions_eax;
@@ -399,11 +433,33 @@ static void __init ms_hyperv_init_platform(void)
                        ms_hyperv.shared_gpa_boundary =
                                BIT_ULL(ms_hyperv.shared_gpa_boundary_bits);
 
+               hyperv_paravisor_present = !!ms_hyperv.paravisor_present;
+
                pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n",
                        ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b);
 
-               if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP)
+
+               if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) {
                        static_branch_enable(&isolation_type_snp);
+               } else if (hv_get_isolation_type() == HV_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;
+
+                               x86_init.acpi.reduced_hw_early_init = reduced_hw_init;
+                       }
+               }
        }
 
        if (hv_max_functions_eax >= HYPERV_CPUID_NESTED_FEATURES) {
@@ -473,7 +529,7 @@ static void __init ms_hyperv_init_platform(void)
 
 #if IS_ENABLED(CONFIG_HYPERV)
        if ((hv_get_isolation_type() == HV_ISOLATION_TYPE_VBS) ||
-           (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP))
+           ms_hyperv.paravisor_present)
                hv_vtom_init();
        /*
         * Setup the hook to get control post apic initialization.
@@ -497,7 +553,8 @@ static void __init ms_hyperv_init_platform(void)
 
 # ifdef CONFIG_SMP
        smp_ops.smp_prepare_boot_cpu = hv_smp_prepare_boot_cpu;
-       if (hv_root_partition)
+       if (hv_root_partition ||
+           (!ms_hyperv.paravisor_present && hv_isolation_type_snp()))
                smp_ops.smp_prepare_cpus = hv_smp_prepare_cpus;
 # endif
 
@@ -560,6 +617,22 @@ static bool __init ms_hyperv_msi_ext_dest_id(void)
        return eax & HYPERV_VS_PROPERTIES_EAX_EXTENDED_IOAPIC_RTE;
 }
 
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+static void hv_sev_es_hcall_prepare(struct ghcb *ghcb, struct pt_regs *regs)
+{
+       /* RAX and CPL are already in the GHCB */
+       ghcb_set_rcx(ghcb, regs->cx);
+       ghcb_set_rdx(ghcb, regs->dx);
+       ghcb_set_r8(ghcb, regs->r8);
+}
+
+static bool hv_sev_es_hcall_finish(struct ghcb *ghcb, struct pt_regs *regs)
+{
+       /* No checking of the return state needed */
+       return true;
+}
+#endif
+
 const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .name                   = "Microsoft Hyper-V",
        .detect                 = ms_hyperv_platform,
@@ -567,4 +640,8 @@ const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .init.x2apic_available  = ms_hyperv_x2apic_available,
        .init.msi_ext_dest_id   = ms_hyperv_msi_ext_dest_id,
        .init.init_platform     = ms_hyperv_init_platform,
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+       .runtime.sev_es_hcall_prepare = hv_sev_es_hcall_prepare,
+       .runtime.sev_es_hcall_finish = hv_sev_es_hcall_finish,
+#endif
 };