Skip to content

Commit 5170a82

Browse files
Jork Loeserliuw
authored andcommitted
x86/hyperv: Skip LP/VP creation on kexec
After a kexec the logical processors and virtual processors already exist in the hypervisor because they were created by the previous kernel. Attempting to add them again causes either a BUG_ON or corrupted VP state leading to MCEs in the new kernel. Add hv_lp_exists() to probe whether an LP is already present by calling HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME. When it succeeds the LP exists and we skip the add-LP and create-VP loops entirely. Also add hv_call_notify_all_processors_started() which informs the hypervisor that all processors are online. This is required after adding LPs (fresh boot) and is a no-op on kexec since we skip that path. Co-developed-by: Anirudh Rayabharam <anrayabh@linux.microsoft.com> Signed-off-by: Anirudh Rayabharam <anrayabh@linux.microsoft.com> Co-developed-by: Stanislav Kinsburskii <stanislav.kinsburskii@gmail.com> Signed-off-by: Stanislav Kinsburskii <stanislav.kinsburskii@gmail.com> Co-developed-by: Mukesh Rathor <mrathor@linux.microsoft.com> Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com> Signed-off-by: Jork Loeser <jloeser@linux.microsoft.com> Reviewed-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent f7ce370 commit 5170a82

5 files changed

Lines changed: 77 additions & 0 deletions

File tree

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,20 @@ static void __init hv_smp_prepare_cpus(unsigned int max_cpus)
429429
}
430430

431431
#ifdef CONFIG_X86_64
432+
/* If AP LPs exist, we are in a kexec'd kernel and VPs already exist */
433+
if (num_present_cpus() == 1 || hv_lp_exists(1))
434+
return;
435+
432436
for_each_present_cpu(i) {
433437
if (i == 0)
434438
continue;
435439
ret = hv_call_add_logical_proc(numa_cpu_node(i), i, cpu_physical_id(i));
436440
BUG_ON(ret);
437441
}
438442

443+
ret = hv_call_notify_all_processors_started();
444+
WARN_ON(ret);
445+
439446
for_each_present_cpu(i) {
440447
if (i == 0)
441448
continue;

drivers/hv/hv_proc.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,50 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
239239
return ret;
240240
}
241241
EXPORT_SYMBOL_GPL(hv_call_create_vp);
242+
243+
int hv_call_notify_all_processors_started(void)
244+
{
245+
struct hv_input_notify_partition_event *input;
246+
u64 status;
247+
unsigned long irq_flags;
248+
int ret = 0;
249+
250+
local_irq_save(irq_flags);
251+
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
252+
memset(input, 0, sizeof(*input));
253+
input->event = HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED;
254+
status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT,
255+
input, NULL);
256+
local_irq_restore(irq_flags);
257+
258+
if (!hv_result_success(status)) {
259+
hv_status_err(status, "\n");
260+
ret = hv_result_to_errno(status);
261+
}
262+
return ret;
263+
}
264+
265+
bool hv_lp_exists(u32 lp_index)
266+
{
267+
struct hv_input_get_logical_processor_run_time *input;
268+
struct hv_output_get_logical_processor_run_time *output;
269+
unsigned long flags;
270+
u64 status;
271+
272+
local_irq_save(flags);
273+
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
274+
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
275+
276+
input->lp_index = lp_index;
277+
status = hv_do_hypercall(HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME,
278+
input, output);
279+
local_irq_restore(flags);
280+
281+
if (!hv_result_success(status) &&
282+
hv_result(status) != HV_STATUS_INVALID_LP_INDEX) {
283+
hv_status_err(status, "\n");
284+
BUG();
285+
}
286+
287+
return hv_result_success(status);
288+
}

include/asm-generic/mshyperv.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ bool hv_result_needs_memory(u64 status);
347347
int hv_deposit_memory_node(int node, u64 partition_id, u64 status);
348348
int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages);
349349
int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id);
350+
int hv_call_notify_all_processors_started(void);
351+
bool hv_lp_exists(u32 lp_index);
350352
int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags);
351353

352354
#else /* CONFIG_MSHV_ROOT */
@@ -366,6 +368,14 @@ static inline int hv_call_add_logical_proc(int node, u32 lp_index, u32 acpi_id)
366368
{
367369
return -EOPNOTSUPP;
368370
}
371+
static inline int hv_call_notify_all_processors_started(void)
372+
{
373+
return -EOPNOTSUPP;
374+
}
375+
static inline bool hv_lp_exists(u32 lp_index)
376+
{
377+
return false;
378+
}
369379
static inline int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
370380
{
371381
return -EOPNOTSUPP;

include/hyperv/hvgdk_mini.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
435435
/* HV_CALL_CODE */
436436
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
437437
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
438+
#define HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME 0x0004
438439
#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008
439440
#define HVCALL_SEND_IPI 0x000b
440441
#define HVCALL_ENABLE_VP_VTL 0x000f

include/hyperv/hvhdk_mini.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,25 @@ union hv_partition_event_input {
362362

363363
enum hv_partition_event {
364364
HV_PARTITION_EVENT_ROOT_CRASHDUMP = 2,
365+
HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED = 4,
365366
};
366367

367368
struct hv_input_notify_partition_event {
368369
u32 event; /* enum hv_partition_event */
369370
union hv_partition_event_input input;
370371
} __packed;
371372

373+
struct hv_input_get_logical_processor_run_time {
374+
u32 lp_index;
375+
} __packed;
376+
377+
struct hv_output_get_logical_processor_run_time {
378+
u64 global_time;
379+
u64 local_run_time;
380+
u64 rsvdz0;
381+
u64 hypervisor_time;
382+
} __packed;
383+
372384
struct hv_lp_startup_status {
373385
u64 hv_status;
374386
u64 substatus1;

0 commit comments

Comments
 (0)