Drivers: hv: Setup synic registers in case of nested root partition
authorJinank Jain <jinankjain@linux.microsoft.com>
Mon, 2 Jan 2023 07:12:52 +0000 (07:12 +0000)
committerWei Liu <wei.liu@kernel.org>
Tue, 17 Jan 2023 13:36:43 +0000 (13:36 +0000)
Child partitions are free to allocate SynIC message and event page but in
case of root partition it must use the pages allocated by Microsoft
Hypervisor (MSHV). Base address for these pages can be found using
synthetic MSRs exposed by MSHV. There is a slight difference in those MSRs
for nested vs non-nested root partition.

Signed-off-by: Jinank Jain <jinankjain@linux.microsoft.com>
Reviewed-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/cb951fb1ad6814996fc54f4a255c5841a20a151f.1672639707.git.jinankjain@linux.microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/mshyperv.h
arch/x86/kernel/cpu/mshyperv.c
drivers/hv/hv.c

index 724a2589c0e7e5accb17a54b417d4982ba3b93df..271d081dc2513c11cb50f2f3919658a29ad219f7 100644 (file)
@@ -227,6 +227,17 @@ enum hv_isolation_type {
 #define HV_REGISTER_SINT14                     0x4000009E
 #define HV_REGISTER_SINT15                     0x4000009F
 
+/*
+ * Define synthetic interrupt controller model specific registers for
+ * nested hypervisor.
+ */
+#define HV_REGISTER_NESTED_SCONTROL            0x40001080
+#define HV_REGISTER_NESTED_SVERSION            0x40001081
+#define HV_REGISTER_NESTED_SIEFP               0x40001082
+#define HV_REGISTER_NESTED_SIMP                0x40001083
+#define HV_REGISTER_NESTED_EOM                 0x40001084
+#define HV_REGISTER_NESTED_SINT0               0x40001090
+
 /*
  * Synthetic Timer MSRs. Four timers per vcpu.
  */
index 6d502f3efb0f4792544766b677bc51d5147d1da6..e3e91b4f299c7eaced5a85c2363f127b907fa8d0 100644 (file)
@@ -196,30 +196,10 @@ static inline bool hv_is_synic_reg(unsigned int reg)
        return false;
 }
 
-static inline u64 hv_get_register(unsigned int reg)
-{
-       u64 value;
-
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp())
-               hv_ghcb_msr_read(reg, &value);
-       else
-               rdmsrl(reg, value);
-       return value;
-}
-
-static inline void hv_set_register(unsigned int reg, u64 value)
-{
-       if (hv_is_synic_reg(reg) && hv_isolation_type_snp()) {
-               hv_ghcb_msr_write(reg, value);
-
-               /* Write proxy bit via wrmsl instruction */
-               if (reg >= HV_REGISTER_SINT0 &&
-                   reg <= HV_REGISTER_SINT15)
-                       wrmsrl(reg, value | 1 << 20);
-       } else {
-               wrmsrl(reg, value);
-       }
-}
+u64 hv_get_register(unsigned int reg);
+void hv_set_register(unsigned int reg, u64 value);
+u64 hv_get_non_nested_register(unsigned int reg);
+void hv_set_non_nested_register(unsigned int reg, u64 value);
 
 #else /* CONFIG_HYPERV */
 static inline void hyperv_init(void) {}
@@ -239,6 +219,8 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
 }
 static inline void hv_set_register(unsigned int reg, u64 value) { }
 static inline u64 hv_get_register(unsigned int reg) { return 0; }
+static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { }
+static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
 static inline int hv_set_mem_host_visibility(unsigned long addr, int numpages,
                                             bool visible)
 {
index f9b78d4829e3545ead373de981d14f3b86f07083..dedec2f23ad103a37f34ab9106372604a1aab76b 100644 (file)
@@ -42,6 +42,71 @@ bool hv_nested;
 struct ms_hyperv_info ms_hyperv;
 
 #if IS_ENABLED(CONFIG_HYPERV)
+static inline unsigned int hv_get_nested_reg(unsigned int reg)
+{
+       switch (reg) {
+       case HV_REGISTER_SIMP:
+               return HV_REGISTER_NESTED_SIMP;
+       case HV_REGISTER_SIEFP:
+               return HV_REGISTER_NESTED_SIEFP;
+       case HV_REGISTER_SVERSION:
+               return HV_REGISTER_NESTED_SVERSION;
+       case HV_REGISTER_SCONTROL:
+               return HV_REGISTER_NESTED_SCONTROL;
+       case HV_REGISTER_SINT0:
+               return HV_REGISTER_NESTED_SINT0;
+       case HV_REGISTER_EOM:
+               return HV_REGISTER_NESTED_EOM;
+       default:
+               return reg;
+       }
+}
+
+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);
+       else
+               rdmsrl(reg, value);
+       return value;
+}
+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);
+
+               /* Write proxy bit via wrmsl instruction */
+               if (reg >= HV_REGISTER_SINT0 &&
+                   reg <= HV_REGISTER_SINT15)
+                       wrmsrl(reg, value | 1 << 20);
+       } else {
+               wrmsrl(reg, value);
+       }
+}
+EXPORT_SYMBOL_GPL(hv_set_non_nested_register);
+
+u64 hv_get_register(unsigned int reg)
+{
+       if (hv_nested)
+               reg = hv_get_nested_reg(reg);
+
+       return hv_get_non_nested_register(reg);
+}
+EXPORT_SYMBOL_GPL(hv_get_register);
+
+void hv_set_register(unsigned int reg, u64 value)
+{
+       if (hv_nested)
+               reg = hv_get_nested_reg(reg);
+
+       hv_set_non_nested_register(reg, value);
+}
+EXPORT_SYMBOL_GPL(hv_set_register);
+
 static void (*vmbus_handler)(void);
 static void (*hv_stimer0_handler)(void);
 static void (*hv_kexec_handler)(void);
index 4d6480d57546def690e7fe553b7421e7f6e505a8..8b0dd8e5244d70b50da53733b68b27a876535aa3 100644 (file)
@@ -147,7 +147,7 @@ int hv_synic_alloc(void)
                 * Synic message and event pages are allocated by paravisor.
                 * Skip these pages allocation here.
                 */
-               if (!hv_isolation_type_snp()) {
+               if (!hv_isolation_type_snp() && !hv_root_partition) {
                        hv_cpu->synic_message_page =
                                (void *)get_zeroed_page(GFP_ATOMIC);
                        if (hv_cpu->synic_message_page == NULL) {
@@ -216,7 +216,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP);
        simp.simp_enabled = 1;
 
-       if (hv_isolation_type_snp()) {
+       if (hv_isolation_type_snp() || hv_root_partition) {
                hv_cpu->synic_message_page
                        = memremap(simp.base_simp_gpa << HV_HYP_PAGE_SHIFT,
                                   HV_HYP_PAGE_SIZE, MEMREMAP_WB);
@@ -233,7 +233,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
        siefp.siefp_enabled = 1;
 
-       if (hv_isolation_type_snp()) {
+       if (hv_isolation_type_snp() || hv_root_partition) {
                hv_cpu->synic_event_page =
                        memremap(siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT,
                                 HV_HYP_PAGE_SIZE, MEMREMAP_WB);
@@ -315,20 +315,24 @@ void hv_synic_disable_regs(unsigned int cpu)
         * addresses.
         */
        simp.simp_enabled = 0;
-       if (hv_isolation_type_snp())
+       if (hv_isolation_type_snp() || hv_root_partition) {
                memunmap(hv_cpu->synic_message_page);
-       else
+               hv_cpu->synic_message_page = NULL;
+       } else {
                simp.base_simp_gpa = 0;
+       }
 
        hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
 
        siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
        siefp.siefp_enabled = 0;
 
-       if (hv_isolation_type_snp())
+       if (hv_isolation_type_snp() || hv_root_partition) {
                memunmap(hv_cpu->synic_event_page);
-       else
+               hv_cpu->synic_event_page = NULL;
+       } else {
                siefp.base_siefp_gpa = 0;
+       }
 
        hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);