Skip to content

Commit e5d9b71

Browse files
Praveen Kumarliuw
authored andcommitted
x86/hyperv: fix root partition faults when writing to VP assist page MSR
For root partition the VP assist pages are pre-determined by the hypervisor. The root kernel is not allowed to change them to different locations. And thus, we are getting below stack as in current implementation root is trying to perform write to specific MSR. [ 2.778197] unchecked MSR access error: WRMSR to 0x40000073 (tried to write 0x0000000145ac5001) at rIP: 0xffffffff810c1084 (native_write_msr+0x4/0x30) [ 2.784867] Call Trace: [ 2.791507] hv_cpu_init+0xf1/0x1c0 [ 2.798144] ? hyperv_report_panic+0xd0/0xd0 [ 2.804806] cpuhp_invoke_callback+0x11a/0x440 [ 2.811465] ? hv_resume+0x90/0x90 [ 2.818137] cpuhp_issue_call+0x126/0x130 [ 2.824782] __cpuhp_setup_state_cpuslocked+0x102/0x2b0 [ 2.831427] ? hyperv_report_panic+0xd0/0xd0 [ 2.838075] ? hyperv_report_panic+0xd0/0xd0 [ 2.844723] ? hv_resume+0x90/0x90 [ 2.851375] __cpuhp_setup_state+0x3d/0x90 [ 2.858030] hyperv_init+0x14e/0x410 [ 2.864689] ? enable_IR_x2apic+0x190/0x1a0 [ 2.871349] apic_intr_mode_init+0x8b/0x100 [ 2.878017] x86_late_time_init+0x20/0x30 [ 2.884675] start_kernel+0x459/0x4fb [ 2.891329] secondary_startup_64_no_verify+0xb0/0xbb Since the hypervisor already provides the VP assist pages for root partition, we need to memremap the memory from hypervisor for root kernel to use. The mapping is done in hv_cpu_init during bringup and is unmapped in hv_cpu_die during teardown. Signed-off-by: Praveen Kumar <[email protected]> Reviewed-by: Sunil Muthuswamy <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent 63fb60c commit e5d9b71

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

arch/x86/hyperv/hv_init.c

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ EXPORT_SYMBOL_GPL(hv_vp_assist_page);
4444

4545
static int hv_cpu_init(unsigned int cpu)
4646
{
47+
union hv_vp_assist_msr_contents msr = { 0 };
4748
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
4849
int ret;
4950

@@ -54,25 +55,34 @@ static int hv_cpu_init(unsigned int cpu)
5455
if (!hv_vp_assist_page)
5556
return 0;
5657

57-
/*
58-
* The VP ASSIST PAGE is an "overlay" page (see Hyper-V TLFS's Section
59-
* 5.2.1 "GPA Overlay Pages"). Here it must be zeroed out to make sure
60-
* we always write the EOI MSR in hv_apic_eoi_write() *after* the
61-
* EOI optimization is disabled in hv_cpu_die(), otherwise a CPU may
62-
* not be stopped in the case of CPU offlining and the VM will hang.
63-
*/
6458
if (!*hvp) {
65-
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO);
66-
}
67-
68-
if (*hvp) {
69-
u64 val;
70-
71-
val = vmalloc_to_pfn(*hvp);
72-
val = (val << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT) |
73-
HV_X64_MSR_VP_ASSIST_PAGE_ENABLE;
74-
75-
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, val);
59+
if (hv_root_partition) {
60+
/*
61+
* For root partition we get the hypervisor provided VP assist
62+
* page, instead of allocating a new page.
63+
*/
64+
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
65+
*hvp = memremap(msr.pfn <<
66+
HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
67+
PAGE_SIZE, MEMREMAP_WB);
68+
} else {
69+
/*
70+
* The VP assist page is an "overlay" page (see Hyper-V TLFS's
71+
* Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
72+
* out to make sure we always write the EOI MSR in
73+
* hv_apic_eoi_write() *after* the EOI optimization is disabled
74+
* in hv_cpu_die(), otherwise a CPU may not be stopped in the
75+
* case of CPU offlining and the VM will hang.
76+
*/
77+
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO);
78+
if (*hvp)
79+
msr.pfn = vmalloc_to_pfn(*hvp);
80+
}
81+
WARN_ON(!(*hvp));
82+
if (*hvp) {
83+
msr.enable = 1;
84+
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
85+
}
7686
}
7787

7888
return 0;
@@ -170,8 +180,22 @@ static int hv_cpu_die(unsigned int cpu)
170180

171181
hv_common_cpu_die(cpu);
172182

173-
if (hv_vp_assist_page && hv_vp_assist_page[cpu])
174-
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, 0);
183+
if (hv_vp_assist_page && hv_vp_assist_page[cpu]) {
184+
union hv_vp_assist_msr_contents msr = { 0 };
185+
if (hv_root_partition) {
186+
/*
187+
* For root partition the VP assist page is mapped to
188+
* hypervisor provided page, and thus we unmap the
189+
* page here and nullify it, so that in future we have
190+
* correct page address mapped in hv_cpu_init.
191+
*/
192+
memunmap(hv_vp_assist_page[cpu]);
193+
hv_vp_assist_page[cpu] = NULL;
194+
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
195+
msr.enable = 0;
196+
}
197+
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
198+
}
175199

176200
if (hv_reenlightenment_cb == NULL)
177201
return 0;

arch/x86/include/asm/hyperv-tlfs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ union hv_x64_msr_hypercall_contents {
288288
} __packed;
289289
};
290290

291+
union hv_vp_assist_msr_contents {
292+
u64 as_uint64;
293+
struct {
294+
u64 enable:1;
295+
u64 reserved:11;
296+
u64 pfn:52;
297+
} __packed;
298+
};
299+
291300
struct hv_reenlightenment_control {
292301
__u64 vector:8;
293302
__u64 reserved1:8;

0 commit comments

Comments
 (0)