]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
hyperv: Change hv_root_partition into a function
authorNuno Das Neves <nunodasneves@linux.microsoft.com>
Fri, 21 Feb 2025 19:56:34 +0000 (11:56 -0800)
committerWei Liu <wei.liu@kernel.org>
Sat, 22 Feb 2025 02:21:45 +0000 (02:21 +0000)
Introduce hv_curr_partition_type to store the partition type
as an enum.

Right now this is limited to guest or root partition, but there will
be other kinds in future and the enum is easily extensible.

Set up hv_curr_partition_type early in Hyper-V initialization with
hv_identify_partition_type(). hv_root_partition() just queries this
value, and shouldn't be called before that.

Making this check into a function sets the stage for adding a config
option to gate the compilation of root partition code. In particular,
hv_root_partition() can be stubbed out always be false if root
partition support isn't desired.

Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <eahariha@linux.microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Link: https://lore.kernel.org/r/1740167795-13296-3-git-send-email-nunodasneves@linux.microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Message-ID: <1740167795-13296-3-git-send-email-nunodasneves@linux.microsoft.com>

arch/arm64/hyperv/mshyperv.c
arch/x86/hyperv/hv_init.c
arch/x86/kernel/cpu/mshyperv.c
drivers/clocksource/hyperv_timer.c
drivers/hv/hv.c
drivers/hv/hv_common.c
drivers/hv/vmbus_drv.c
drivers/iommu/hyperv-iommu.c
include/asm-generic/mshyperv.h

index 29fcfd595f48067d85b9c0c343d648d67b7a6f4c..2265ea5ce5adf2b85f566dfdbea6b93afe3801bc 100644 (file)
@@ -61,6 +61,8 @@ static int __init hyperv_init(void)
                ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints,
                ms_hyperv.misc_features);
 
+       hv_identify_partition_type();
+
        ret = hv_common_init();
        if (ret)
                return ret;
index 9be1446f5bd380b4af01de8f160d8b53113faf9f..ddeb40930bc8027e06fe586eabb9d82b86dc54b8 100644 (file)
@@ -90,7 +90,7 @@ static int hv_cpu_init(unsigned int cpu)
                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
                 * page, instead of allocating a new page.
@@ -242,7 +242,7 @@ static int hv_cpu_die(unsigned int cpu)
 
        if (hv_vp_assist_page && hv_vp_assist_page[cpu]) {
                union hv_vp_assist_msr_contents msr = { 0 };
-               if (hv_root_partition) {
+               if (hv_root_partition()) {
                        /*
                         * For root partition the VP assist page is mapped to
                         * hypervisor provided page, and thus we unmap the
@@ -317,7 +317,7 @@ static int hv_suspend(void)
        union hv_x64_msr_hypercall_contents hypercall_msr;
        int ret;
 
-       if (hv_root_partition)
+       if (hv_root_partition())
                return -EPERM;
 
        /*
@@ -518,7 +518,7 @@ void __init hyperv_init(void)
        rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
        hypercall_msr.enable = 1;
 
-       if (hv_root_partition) {
+       if (hv_root_partition()) {
                struct page *pg;
                void *src;
 
@@ -592,7 +592,7 @@ skip_hypercall_pg_init:
         * If we're running as root, we want to create our own PCI MSI domain.
         * We can't set this in hv_pci_init because that would be too late.
         */
-       if (hv_root_partition)
+       if (hv_root_partition())
                x86_init.irqs.create_pci_msi_domain = hv_create_pci_msi_domain;
 #endif
 
index f285757618fc8cf6e67b62c3d1a725d9b6ba70ed..4f01f424ea5bd42b981de9f9bfc51c67d07fed3c 100644 (file)
@@ -33,8 +33,6 @@
 #include <asm/numa.h>
 #include <asm/svm.h>
 
-/* Is Linux running as the root partition? */
-bool hv_root_partition;
 /* Is Linux running on nested Microsoft Hypervisor */
 bool hv_nested;
 struct ms_hyperv_info ms_hyperv;
@@ -451,25 +449,7 @@ static void __init ms_hyperv_init_platform(void)
        pr_debug("Hyper-V: max %u virtual processors, %u logical processors\n",
                 ms_hyperv.max_vp_index, ms_hyperv.max_lp_index);
 
-       /*
-        * Check CPU management privilege.
-        *
-        * To mirror what Windows does we should extract CPU management
-        * features and use the ReservedIdentityBit to detect if Linux is the
-        * root partition. But that requires negotiating CPU management
-        * interface (a process to be finalized). For now, use the privilege
-        * flag as the indicator for running as root.
-        *
-        * Hyper-V should never specify running as root and as a Confidential
-        * VM. But to protect against a compromised/malicious Hyper-V trying
-        * to exploit root behavior to expose Confidential VM memory, ignore
-        * the root partition setting if also a Confidential VM.
-        */
-       if ((ms_hyperv.priv_high & HV_CPU_MANAGEMENT) &&
-           !(ms_hyperv.priv_high & HV_ISOLATION)) {
-               hv_root_partition = true;
-               pr_info("Hyper-V: running as root partition\n");
-       }
+       hv_identify_partition_type();
 
        if (ms_hyperv.hints & HV_X64_HYPERV_NESTED) {
                hv_nested = true;
@@ -618,7 +598,7 @@ 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
index f00019b078a71ab766dfbdac7b381b2965de8bdd..09549451dd515a93bee87bc0727d6dd336693920 100644 (file)
@@ -582,7 +582,7 @@ static void __init hv_init_tsc_clocksource(void)
         * mapped.
         */
        tsc_msr.as_uint64 = hv_get_msr(HV_MSR_REFERENCE_TSC);
-       if (hv_root_partition)
+       if (hv_root_partition())
                tsc_pfn = tsc_msr.pfn;
        else
                tsc_pfn = HVPFN_DOWN(virt_to_phys(tsc_page));
@@ -627,7 +627,7 @@ void __init hv_remap_tsc_clocksource(void)
        if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE))
                return;
 
-       if (!hv_root_partition) {
+       if (!hv_root_partition()) {
                WARN(1, "%s: attempt to remap TSC page in guest partition\n",
                     __func__);
                return;
index fab0690b5c418ac61183c8791303f3a2ad36d93a..a38f84548bc25d633351e1e3d9126673a1918249 100644 (file)
@@ -144,7 +144,7 @@ int hv_synic_alloc(void)
                 * Synic message and event pages are allocated by paravisor.
                 * Skip these pages allocation here.
                 */
-               if (!ms_hyperv.paravisor_present && !hv_root_partition) {
+               if (!ms_hyperv.paravisor_present && !hv_root_partition()) {
                        hv_cpu->synic_message_page =
                                (void *)get_zeroed_page(GFP_ATOMIC);
                        if (!hv_cpu->synic_message_page) {
@@ -272,7 +272,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
        simp.simp_enabled = 1;
 
-       if (ms_hyperv.paravisor_present || hv_root_partition) {
+       if (ms_hyperv.paravisor_present || hv_root_partition()) {
                /* Mask out vTOM bit. ioremap_cache() maps decrypted */
                u64 base = (simp.base_simp_gpa << HV_HYP_PAGE_SHIFT) &
                                ~ms_hyperv.shared_gpa_boundary;
@@ -291,7 +291,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP);
        siefp.siefp_enabled = 1;
 
-       if (ms_hyperv.paravisor_present || hv_root_partition) {
+       if (ms_hyperv.paravisor_present || hv_root_partition()) {
                /* Mask out vTOM bit. ioremap_cache() maps decrypted */
                u64 base = (siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT) &
                                ~ms_hyperv.shared_gpa_boundary;
@@ -367,7 +367,7 @@ void hv_synic_disable_regs(unsigned int cpu)
         * addresses.
         */
        simp.simp_enabled = 0;
-       if (ms_hyperv.paravisor_present || hv_root_partition) {
+       if (ms_hyperv.paravisor_present || hv_root_partition()) {
                iounmap(hv_cpu->synic_message_page);
                hv_cpu->synic_message_page = NULL;
        } else {
@@ -379,7 +379,7 @@ void hv_synic_disable_regs(unsigned int cpu)
        siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP);
        siefp.siefp_enabled = 0;
 
-       if (ms_hyperv.paravisor_present || hv_root_partition) {
+       if (ms_hyperv.paravisor_present || hv_root_partition()) {
                iounmap(hv_cpu->synic_event_page);
                hv_cpu->synic_event_page = NULL;
        } else {
index 5cf9894b9e795a486ecc934c5fb96d6391f10d16..3d9cfcfbc854ab9cf1d5d98dce69dbcaf6ed9cdd 100644 (file)
 u64 hv_current_partition_id = HV_PARTITION_ID_SELF;
 EXPORT_SYMBOL_GPL(hv_current_partition_id);
 
+enum hv_partition_type hv_curr_partition_type;
+EXPORT_SYMBOL_GPL(hv_curr_partition_type);
+
 /*
- * hv_root_partition, ms_hyperv and hv_nested are defined here with other
+ * ms_hyperv and hv_nested are defined here with other
  * Hyper-V specific globals so they are shared across all architectures and are
  * built only when CONFIG_HYPERV is defined.  But on x86,
  * ms_hyperv_init_platform() is built even when CONFIG_HYPERV is not
@@ -43,9 +46,6 @@ EXPORT_SYMBOL_GPL(hv_current_partition_id);
  * here, allowing for an overriding definition in the module containing
  * ms_hyperv_init_platform().
  */
-bool __weak hv_root_partition;
-EXPORT_SYMBOL_GPL(hv_root_partition);
-
 bool __weak hv_nested;
 EXPORT_SYMBOL_GPL(hv_nested);
 
@@ -283,7 +283,7 @@ static void hv_kmsg_dump_register(void)
 
 static inline bool hv_output_page_exists(void)
 {
-       return hv_root_partition || IS_ENABLED(CONFIG_HYPERV_VTL_MODE);
+       return hv_root_partition() || IS_ENABLED(CONFIG_HYPERV_VTL_MODE);
 }
 
 void __init hv_get_partition_id(void)
@@ -594,7 +594,7 @@ EXPORT_SYMBOL_GPL(hv_setup_dma_ops);
 
 bool hv_is_hibernation_supported(void)
 {
-       return !hv_root_partition && acpi_sleep_state_supported(ACPI_STATE_S4);
+       return !hv_root_partition() && acpi_sleep_state_supported(ACPI_STATE_S4);
 }
 EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);
 
@@ -717,3 +717,23 @@ int hv_result_to_errno(u64 status)
        }
        return -EIO;
 }
+
+void hv_identify_partition_type(void)
+{
+       /* Assume guest role */
+       hv_curr_partition_type = HV_PARTITION_TYPE_GUEST;
+       /*
+        * Check partition creation and cpu management privileges
+        *
+        * Hyper-V should never specify running as root and as a Confidential
+        * VM. But to protect against a compromised/malicious Hyper-V trying
+        * to exploit root behavior to expose Confidential VM memory, ignore
+        * the root partition setting if also a Confidential VM.
+        */
+       if ((ms_hyperv.priv_high & HV_CREATE_PARTITIONS) &&
+           (ms_hyperv.priv_high & HV_CPU_MANAGEMENT) &&
+           !(ms_hyperv.priv_high & HV_ISOLATION)) {
+               pr_info("Hyper-V: running as root partition\n");
+               hv_curr_partition_type = HV_PARTITION_TYPE_ROOT;
+       }
+}
index 75eb1390b45cae94a6dc0c283bf2d628044861e4..22afebfc28ffebfbb72305441e6ab56bf63b2588 100644 (file)
@@ -2656,7 +2656,7 @@ static int __init hv_acpi_init(void)
        if (!hv_is_hyperv_initialized())
                return -ENODEV;
 
-       if (hv_root_partition && !hv_nested)
+       if (hv_root_partition() && !hv_nested)
                return 0;
 
        /*
index 2a86aa5d54c68febbdc3940641ccfbaa39a4fc46..53e4b37716af92a91f48cf9549304e6ac4b22f3a 100644 (file)
@@ -130,7 +130,7 @@ static int __init hyperv_prepare_irq_remapping(void)
            x86_init.hyper.msi_ext_dest_id())
                return -ENODEV;
 
-       if (hv_root_partition) {
+       if (hv_root_partition()) {
                name = "HYPERV-ROOT-IR";
                ops = &hyperv_root_ir_domain_ops;
        } else {
@@ -151,7 +151,7 @@ static int __init hyperv_prepare_irq_remapping(void)
                return -ENOMEM;
        }
 
-       if (hv_root_partition)
+       if (hv_root_partition())
                return 0; /* The rest is only relevant to guests */
 
        /*
index 3f115e2bcdaaa8cda62afbd86589da1e9df870fd..54ebd630e72c900d081839cadc81a6d2fe24b26a 100644 (file)
 
 #define VTPM_BASE_ADDRESS 0xfed40000
 
+enum hv_partition_type {
+       HV_PARTITION_TYPE_GUEST,
+       HV_PARTITION_TYPE_ROOT,
+};
+
 struct ms_hyperv_info {
        u32 features;
        u32 priv_high;
@@ -59,6 +64,7 @@ struct ms_hyperv_info {
 extern struct ms_hyperv_info ms_hyperv;
 extern bool hv_nested;
 extern u64 hv_current_partition_id;
+extern enum hv_partition_type hv_curr_partition_type;
 
 extern void * __percpu *hyperv_pcpu_input_arg;
 extern void * __percpu *hyperv_pcpu_output_arg;
@@ -190,8 +196,6 @@ void hv_remove_crash_handler(void);
 extern int vmbus_interrupt;
 extern int vmbus_irq;
 
-extern bool hv_root_partition;
-
 #if IS_ENABLED(CONFIG_HYPERV)
 /*
  * Hypervisor's notion of virtual processor ID is different from
@@ -213,6 +217,7 @@ void __init hv_common_free(void);
 void __init ms_hyperv_late_init(void);
 int hv_common_cpu_init(unsigned int cpu);
 int hv_common_cpu_die(unsigned int cpu);
+void hv_identify_partition_type(void);
 
 void *hv_alloc_hyperv_page(void);
 void *hv_alloc_hyperv_zeroed_page(void);
@@ -310,6 +315,7 @@ void hyperv_cleanup(void);
 bool hv_query_ext_cap(u64 cap_query);
 void hv_setup_dma_ops(struct device *dev, bool coherent);
 #else /* CONFIG_HYPERV */
+static inline void hv_identify_partition_type(void) {}
 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) {}
@@ -321,4 +327,9 @@ static inline enum hv_isolation_type hv_get_isolation_type(void)
 }
 #endif /* CONFIG_HYPERV */
 
+static inline bool hv_root_partition(void)
+{
+       return hv_curr_partition_type == HV_PARTITION_TYPE_ROOT;
+}
+
 #endif