x86/hyperv: allocate output arg pages if required
authorWei Liu <wei.liu@kernel.org>
Wed, 3 Feb 2021 15:04:24 +0000 (15:04 +0000)
committerWei Liu <wei.liu@kernel.org>
Thu, 11 Feb 2021 08:47:06 +0000 (08:47 +0000)
When Linux runs as the root partition, it will need to make hypercalls
which return data from the hypervisor.

Allocate pages for storing results when Linux runs as the root
partition.

Signed-off-by: Lillian Grassin-Drake <ligrassi@microsoft.com>
Co-Developed-by: Lillian Grassin-Drake <ligrassi@microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/20210203150435.27941-6-wei.liu@kernel.org
arch/x86/hyperv/hv_init.c
arch/x86/include/asm/mshyperv.h

index 6608d50d7aaa4b5008abbe4ce109b85f5ae2d987..a73f4db31870672627dd42a87f714ea9ad1cf7ff 100644 (file)
@@ -45,6 +45,9 @@ EXPORT_SYMBOL_GPL(hv_vp_assist_page);
 void  __percpu **hyperv_pcpu_input_arg;
 EXPORT_SYMBOL_GPL(hyperv_pcpu_input_arg);
 
+void  __percpu **hyperv_pcpu_output_arg;
+EXPORT_SYMBOL_GPL(hyperv_pcpu_output_arg);
+
 u32 hv_max_vp_index;
 EXPORT_SYMBOL_GPL(hv_max_vp_index);
 
@@ -77,12 +80,19 @@ static int hv_cpu_init(unsigned int cpu)
        void **input_arg;
        struct page *pg;
 
-       input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
        /* hv_cpu_init() can be called with IRQs disabled from hv_resume() */
-       pg = alloc_page(irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+       pg = alloc_pages(irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL, hv_root_partition ? 1 : 0);
        if (unlikely(!pg))
                return -ENOMEM;
+
+       input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
        *input_arg = page_address(pg);
+       if (hv_root_partition) {
+               void **output_arg;
+
+               output_arg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
+               *output_arg = page_address(pg + 1);
+       }
 
        hv_get_vp_index(msr_vp_index);
 
@@ -209,14 +219,23 @@ static int hv_cpu_die(unsigned int cpu)
        unsigned int new_cpu;
        unsigned long flags;
        void **input_arg;
-       void *input_pg = NULL;
+       void *pg;
 
        local_irq_save(flags);
        input_arg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
-       input_pg = *input_arg;
+       pg = *input_arg;
        *input_arg = NULL;
+
+       if (hv_root_partition) {
+               void **output_arg;
+
+               output_arg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
+               *output_arg = NULL;
+       }
+
        local_irq_restore(flags);
-       free_page((unsigned long)input_pg);
+
+       free_pages((unsigned long)pg, hv_root_partition ? 1 : 0);
 
        if (hv_vp_assist_page && hv_vp_assist_page[cpu])
                wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, 0);
@@ -369,6 +388,12 @@ void __init hyperv_init(void)
 
        BUG_ON(hyperv_pcpu_input_arg == NULL);
 
+       /* Allocate the per-CPU state for output arg for root */
+       if (hv_root_partition) {
+               hyperv_pcpu_output_arg = alloc_percpu(void *);
+               BUG_ON(hyperv_pcpu_output_arg == NULL);
+       }
+
        /* Allocate percpu VP index */
        hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index),
                                    GFP_KERNEL);
index 4014a1ca2faea7d8e81bbb49b1f7cbb1175c9e31..ef06cdac8444dc365848955848c3e9cda318fa83 100644 (file)
@@ -78,6 +78,7 @@ extern int hyperv_init_cpuhp;
 
 extern void *hv_hypercall_pg;
 extern void  __percpu  **hyperv_pcpu_input_arg;
+extern void  __percpu  **hyperv_pcpu_output_arg;
 
 static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
 {