Skip to content

Commit d31558c

Browse files
committed
Merge tag 'hyperv-next-signed-20260218' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V updates from Wei Liu: - Debugfs support for MSHV statistics (Nuno Das Neves) - Support for the integrated scheduler (Stanislav Kinsburskii) - Various fixes for MSHV memory management and hypervisor status handling (Stanislav Kinsburskii) - Expose more capabilities and flags for MSHV partition management (Anatol Belski, Muminul Islam, Magnus Kulke) - Miscellaneous fixes to improve code quality and stability (Carlos López, Ethan Nelson-Moore, Li RongQing, Michael Kelley, Mukesh Rathor, Purna Pavan Chandra Aekkaladevi, Stanislav Kinsburskii, Uros Bizjak) - PREEMPT_RT fixes for vmbus interrupts (Jan Kiszka) * tag 'hyperv-next-signed-20260218' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (34 commits) mshv: Handle insufficient root memory hypervisor statuses mshv: Handle insufficient contiguous memory hypervisor status mshv: Introduce hv_deposit_memory helper functions mshv: Introduce hv_result_needs_memory() helper function mshv: Add SMT_ENABLED_GUEST partition creation flag mshv: Add nested virtualization creation flag Drivers: hv: vmbus: Simplify allocation of vmbus_evt mshv: expose the scrub partition hypercall mshv: Add support for integrated scheduler mshv: Use try_cmpxchg() instead of cmpxchg() x86/hyperv: Fix error pointer dereference x86/hyperv: Reserve 3 interrupt vectors used exclusively by MSHV Drivers: hv: vmbus: Use kthread for vmbus interrupts on PREEMPT_RT x86/hyperv: Remove ASM_CALL_CONSTRAINT with VMMCALL insn x86/hyperv: Use savesegment() instead of inline asm() to save segment registers mshv: fix SRCU protection in irqfd resampler ack handler mshv: make field names descriptive in a header struct x86/hyperv: Update comment in hyperv_cleanup() mshv: clear eventfd counter on irqfd shutdown x86/hyperv: Use memremap()/memunmap() instead of ioremap_cache()/iounmap() ...
2 parents 8bf22c3 + 158ebb5 commit d31558c

27 files changed

Lines changed: 1776 additions & 261 deletions

arch/x86/hyperv/hv_crash.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ static void hv_notify_prepare_hyp(void)
279279
static noinline __noclone void crash_nmi_callback(struct pt_regs *regs)
280280
{
281281
struct hv_input_disable_hyp_ex *input;
282-
u64 status;
283282
int msecs = 1000, ccpu = smp_processor_id();
284283

285284
if (ccpu == 0) {
@@ -313,7 +312,7 @@ static noinline __noclone void crash_nmi_callback(struct pt_regs *regs)
313312
input->rip = trampoline_pa;
314313
input->arg = devirt_arg;
315314

316-
status = hv_do_hypercall(HVCALL_DISABLE_HYP_EX, input, NULL);
315+
(void)hv_do_hypercall(HVCALL_DISABLE_HYP_EX, input, NULL);
317316

318317
hv_panic_timeout_reboot();
319318
}

arch/x86/hyperv/hv_init.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ static int hyperv_init_ghcb(void)
103103
*/
104104
rdmsrq(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa);
105105

106-
/* Mask out vTOM bit. ioremap_cache() maps decrypted */
106+
/* Mask out vTOM bit and map as decrypted */
107107
ghcb_gpa &= ~ms_hyperv.shared_gpa_boundary;
108-
ghcb_va = (void *)ioremap_cache(ghcb_gpa, HV_HYP_PAGE_SIZE);
108+
ghcb_va = memremap(ghcb_gpa, HV_HYP_PAGE_SIZE, MEMREMAP_WB | MEMREMAP_DEC);
109109
if (!ghcb_va)
110110
return -ENOMEM;
111111

@@ -277,7 +277,7 @@ static int hv_cpu_die(unsigned int cpu)
277277
if (hv_ghcb_pg) {
278278
ghcb_va = (void **)this_cpu_ptr(hv_ghcb_pg);
279279
if (*ghcb_va)
280-
iounmap(*ghcb_va);
280+
memunmap(*ghcb_va);
281281
*ghcb_va = NULL;
282282
}
283283

@@ -558,7 +558,6 @@ void __init hyperv_init(void)
558558
memunmap(src);
559559

560560
hv_remap_tsc_clocksource();
561-
hv_root_crash_init();
562561
hv_sleep_notifiers_register();
563562
} else {
564563
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
@@ -567,6 +566,9 @@ void __init hyperv_init(void)
567566

568567
hv_set_hypercall_pg(hv_hypercall_pg);
569568

569+
if (hv_root_partition()) /* after set hypercall pg */
570+
hv_root_crash_init();
571+
570572
skip_hypercall_pg_init:
571573
/*
572574
* hyperv_init() is called before LAPIC is initialized: see
@@ -633,9 +635,13 @@ void hyperv_cleanup(void)
633635
hv_ivm_msr_write(HV_X64_MSR_GUEST_OS_ID, 0);
634636

635637
/*
636-
* Reset hypercall page reference before reset the page,
637-
* let hypercall operations fail safely rather than
638-
* panic the kernel for using invalid hypercall page
638+
* Reset hv_hypercall_pg before resetting it in the hypervisor.
639+
* hv_set_hypercall_pg(NULL) is not used because at this point in the
640+
* panic path other CPUs have been stopped, causing static_call_update()
641+
* to hang. So resetting hv_hypercall_pg to cause hypercalls to fail
642+
* cleanly is only operative on 32-bit builds. But this is OK as it is
643+
* just a preventative measure to ease detecting a hypercall being made
644+
* after this point, which shouldn't be happening anyway.
639645
*/
640646
hv_hypercall_pg = NULL;
641647

arch/x86/hyperv/hv_vtl.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ static void hv_vtl_ap_entry(void)
110110

111111
static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
112112
{
113-
u64 status;
113+
u64 status, rsp, rip;
114114
int ret = 0;
115115
struct hv_enable_vp_vtl *input;
116116
unsigned long irq_flags;
@@ -123,9 +123,11 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
123123
struct desc_struct *gdt;
124124

125125
struct task_struct *idle = idle_thread_get(cpu);
126-
u64 rsp = (unsigned long)idle->thread.sp;
126+
if (IS_ERR(idle))
127+
return PTR_ERR(idle);
127128

128-
u64 rip = (u64)&hv_vtl_ap_entry;
129+
rsp = (unsigned long)idle->thread.sp;
130+
rip = (u64)&hv_vtl_ap_entry;
129131

130132
native_store_gdt(&gdt_ptr);
131133
store_idt(&idt_ptr);

arch/x86/hyperv/ivm.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <asm/e820/api.h>
2626
#include <asm/desc.h>
2727
#include <asm/msr.h>
28+
#include <asm/segment.h>
2829
#include <uapi/asm/vmx.h>
2930

3031
#ifdef CONFIG_AMD_MEM_ENCRYPT
@@ -315,16 +316,16 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
315316
vmsa->gdtr.base = gdtr.address;
316317
vmsa->gdtr.limit = gdtr.size;
317318

318-
asm volatile("movl %%es, %%eax;" : "=a" (vmsa->es.selector));
319+
savesegment(es, vmsa->es.selector);
319320
hv_populate_vmcb_seg(vmsa->es, vmsa->gdtr.base);
320321

321-
asm volatile("movl %%cs, %%eax;" : "=a" (vmsa->cs.selector));
322+
savesegment(cs, vmsa->cs.selector);
322323
hv_populate_vmcb_seg(vmsa->cs, vmsa->gdtr.base);
323324

324-
asm volatile("movl %%ss, %%eax;" : "=a" (vmsa->ss.selector));
325+
savesegment(ss, vmsa->ss.selector);
325326
hv_populate_vmcb_seg(vmsa->ss, vmsa->gdtr.base);
326327

327-
asm volatile("movl %%ds, %%eax;" : "=a" (vmsa->ds.selector));
328+
savesegment(ds, vmsa->ds.selector);
328329
hv_populate_vmcb_seg(vmsa->ds, vmsa->gdtr.base);
329330

330331
vmsa->efer = native_read_msr(MSR_EFER);
@@ -391,7 +392,7 @@ u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2)
391392

392393
register u64 __r8 asm("r8") = param2;
393394
asm volatile("vmmcall"
394-
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
395+
: "=a" (hv_status),
395396
"+c" (control), "+d" (param1), "+r" (__r8)
396397
: : "cc", "memory", "r9", "r10", "r11");
397398

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,28 @@ int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
478478
}
479479
EXPORT_SYMBOL_GPL(hv_get_hypervisor_version);
480480

481+
/*
482+
* Reserved vectors hard coded in the hypervisor. If used outside, the hypervisor
483+
* will either crash or hang or attempt to break into debugger.
484+
*/
485+
static void hv_reserve_irq_vectors(void)
486+
{
487+
#define HYPERV_DBG_FASTFAIL_VECTOR 0x29
488+
#define HYPERV_DBG_ASSERT_VECTOR 0x2C
489+
#define HYPERV_DBG_SERVICE_VECTOR 0x2D
490+
491+
if (cpu_feature_enabled(X86_FEATURE_FRED))
492+
return;
493+
494+
if (test_and_set_bit(HYPERV_DBG_ASSERT_VECTOR, system_vectors) ||
495+
test_and_set_bit(HYPERV_DBG_SERVICE_VECTOR, system_vectors) ||
496+
test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors))
497+
BUG();
498+
499+
pr_info("Hyper-V: reserve vectors: %d %d %d\n", HYPERV_DBG_ASSERT_VECTOR,
500+
HYPERV_DBG_SERVICE_VECTOR, HYPERV_DBG_FASTFAIL_VECTOR);
501+
}
502+
481503
static void __init ms_hyperv_init_platform(void)
482504
{
483505
int hv_max_functions_eax, eax;
@@ -510,6 +532,9 @@ static void __init ms_hyperv_init_platform(void)
510532

511533
hv_identify_partition_type();
512534

535+
if (hv_root_partition())
536+
hv_reserve_irq_vectors();
537+
513538
if (cc_platform_has(CC_ATTR_SNP_SECURE_AVIC))
514539
ms_hyperv.hints |= HV_DEPRECATING_AEOI_RECOMMENDED;
515540

drivers/hv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
1515
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o
1616
mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \
1717
mshv_root_hv_call.o mshv_portid_table.o mshv_regions.o
18+
mshv_root-$(CONFIG_DEBUG_FS) += mshv_debugfs.o
1819
mshv_vtl-y := mshv_vtl_main.o
1920

2021
# Code that must be built-in

drivers/hv/hv.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
287287
simp.simp_enabled = 1;
288288

289289
if (ms_hyperv.paravisor_present || hv_root_partition()) {
290-
/* Mask out vTOM bit. ioremap_cache() maps decrypted */
290+
/* Mask out vTOM bit and map as decrypted */
291291
u64 base = (simp.base_simp_gpa << HV_HYP_PAGE_SHIFT) &
292292
~ms_hyperv.shared_gpa_boundary;
293293
hv_cpu->hyp_synic_message_page =
294-
(void *)ioremap_cache(base, HV_HYP_PAGE_SIZE);
294+
memremap(base, HV_HYP_PAGE_SIZE, MEMREMAP_WB | MEMREMAP_DEC);
295295
if (!hv_cpu->hyp_synic_message_page)
296296
pr_err("Fail to map synic message page.\n");
297297
} else {
@@ -306,11 +306,11 @@ void hv_hyp_synic_enable_regs(unsigned int cpu)
306306
siefp.siefp_enabled = 1;
307307

308308
if (ms_hyperv.paravisor_present || hv_root_partition()) {
309-
/* Mask out vTOM bit. ioremap_cache() maps decrypted */
309+
/* Mask out vTOM bit and map as decrypted */
310310
u64 base = (siefp.base_siefp_gpa << HV_HYP_PAGE_SHIFT) &
311311
~ms_hyperv.shared_gpa_boundary;
312312
hv_cpu->hyp_synic_event_page =
313-
(void *)ioremap_cache(base, HV_HYP_PAGE_SIZE);
313+
memremap(base, HV_HYP_PAGE_SIZE, MEMREMAP_WB | MEMREMAP_DEC);
314314
if (!hv_cpu->hyp_synic_event_page)
315315
pr_err("Fail to map synic event page.\n");
316316
} else {
@@ -429,7 +429,7 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
429429
simp.simp_enabled = 0;
430430
if (ms_hyperv.paravisor_present || hv_root_partition()) {
431431
if (hv_cpu->hyp_synic_message_page) {
432-
iounmap(hv_cpu->hyp_synic_message_page);
432+
memunmap(hv_cpu->hyp_synic_message_page);
433433
hv_cpu->hyp_synic_message_page = NULL;
434434
}
435435
} else {
@@ -443,7 +443,7 @@ void hv_hyp_synic_disable_regs(unsigned int cpu)
443443

444444
if (ms_hyperv.paravisor_present || hv_root_partition()) {
445445
if (hv_cpu->hyp_synic_event_page) {
446-
iounmap(hv_cpu->hyp_synic_event_page);
446+
memunmap(hv_cpu->hyp_synic_event_page);
447447
hv_cpu->hyp_synic_event_page = NULL;
448448
}
449449
} else {

drivers/hv/hv_common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,9 @@ static const struct hv_status_info hv_status_infos[] = {
793793
_STATUS_INFO(HV_STATUS_UNKNOWN_PROPERTY, -EIO),
794794
_STATUS_INFO(HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE, -EIO),
795795
_STATUS_INFO(HV_STATUS_INSUFFICIENT_MEMORY, -ENOMEM),
796+
_STATUS_INFO(HV_STATUS_INSUFFICIENT_CONTIGUOUS_MEMORY, -ENOMEM),
797+
_STATUS_INFO(HV_STATUS_INSUFFICIENT_ROOT_MEMORY, -ENOMEM),
798+
_STATUS_INFO(HV_STATUS_INSUFFICIENT_CONTIGUOUS_ROOT_MEMORY, -ENOMEM),
796799
_STATUS_INFO(HV_STATUS_INVALID_PARTITION_ID, -EINVAL),
797800
_STATUS_INFO(HV_STATUS_INVALID_VP_INDEX, -EINVAL),
798801
_STATUS_INFO(HV_STATUS_NOT_FOUND, -EIO),

drivers/hv/hv_proc.c

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,50 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
110110
}
111111
EXPORT_SYMBOL_GPL(hv_call_deposit_pages);
112112

113+
int hv_deposit_memory_node(int node, u64 partition_id,
114+
u64 hv_status)
115+
{
116+
u32 num_pages = 1;
117+
118+
switch (hv_result(hv_status)) {
119+
case HV_STATUS_INSUFFICIENT_MEMORY:
120+
break;
121+
case HV_STATUS_INSUFFICIENT_CONTIGUOUS_MEMORY:
122+
num_pages = HV_MAX_CONTIGUOUS_ALLOCATION_PAGES;
123+
break;
124+
125+
case HV_STATUS_INSUFFICIENT_CONTIGUOUS_ROOT_MEMORY:
126+
num_pages = HV_MAX_CONTIGUOUS_ALLOCATION_PAGES;
127+
fallthrough;
128+
case HV_STATUS_INSUFFICIENT_ROOT_MEMORY:
129+
if (!hv_root_partition()) {
130+
hv_status_err(hv_status, "Unexpected root memory deposit\n");
131+
return -ENOMEM;
132+
}
133+
partition_id = HV_PARTITION_ID_SELF;
134+
break;
135+
136+
default:
137+
hv_status_err(hv_status, "Unexpected!\n");
138+
return -ENOMEM;
139+
}
140+
return hv_call_deposit_pages(node, partition_id, num_pages);
141+
}
142+
EXPORT_SYMBOL_GPL(hv_deposit_memory_node);
143+
144+
bool hv_result_needs_memory(u64 status)
145+
{
146+
switch (hv_result(status)) {
147+
case HV_STATUS_INSUFFICIENT_MEMORY:
148+
case HV_STATUS_INSUFFICIENT_CONTIGUOUS_MEMORY:
149+
case HV_STATUS_INSUFFICIENT_ROOT_MEMORY:
150+
case HV_STATUS_INSUFFICIENT_CONTIGUOUS_ROOT_MEMORY:
151+
return true;
152+
}
153+
return false;
154+
}
155+
EXPORT_SYMBOL_GPL(hv_result_needs_memory);
156+
113157
int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
114158
{
115159
struct hv_input_add_logical_processor *input;
@@ -137,15 +181,16 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
137181
input, output);
138182
local_irq_restore(flags);
139183

140-
if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
184+
if (!hv_result_needs_memory(status)) {
141185
if (!hv_result_success(status)) {
142186
hv_status_err(status, "cpu %u apic ID: %u\n",
143187
lp_index, apic_id);
144188
ret = hv_result_to_errno(status);
145189
}
146190
break;
147191
}
148-
ret = hv_call_deposit_pages(node, hv_current_partition_id, 1);
192+
ret = hv_deposit_memory_node(node, hv_current_partition_id,
193+
status);
149194
} while (!ret);
150195

151196
return ret;
@@ -179,15 +224,15 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
179224
status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL);
180225
local_irq_restore(irq_flags);
181226

182-
if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) {
227+
if (!hv_result_needs_memory(status)) {
183228
if (!hv_result_success(status)) {
184229
hv_status_err(status, "vcpu: %u, lp: %u\n",
185230
vp_index, flags);
186231
ret = hv_result_to_errno(status);
187232
}
188233
break;
189234
}
190-
ret = hv_call_deposit_pages(node, partition_id, 1);
235+
ret = hv_deposit_memory_node(node, partition_id, status);
191236

192237
} while (!ret);
193238

drivers/hv/hyperv_vmbus.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
370370
* CHANNELMSG_UNLOAD_RESPONSE and we don't care about other messages
371371
* on crash.
372372
*/
373-
if (cmpxchg(&msg->header.message_type, old_msg_type,
374-
HVMSG_NONE) != old_msg_type)
373+
if (!try_cmpxchg(&msg->header.message_type,
374+
&old_msg_type, HVMSG_NONE))
375375
return;
376376

377377
/*

0 commit comments

Comments
 (0)