Skip to content

Commit c00b285

Browse files
committed
Merge tag 'hyperv-next-signed-20250602' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull hyperv updates from Wei Liu: - Support for Virtual Trust Level (VTL) on arm64 (Roman Kisel) - Fixes for Hyper-V UIO driver (Long Li) - Fixes for Hyper-V PCI driver (Michael Kelley) - Select CONFIG_SYSFB for Hyper-V guests (Michael Kelley) - Documentation updates for Hyper-V VMBus (Michael Kelley) - Enhance logging for hv_kvp_daemon (Shradha Gupta) * tag 'hyperv-next-signed-20250602' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (23 commits) Drivers: hv: Always select CONFIG_SYSFB for Hyper-V guests Drivers: hv: vmbus: Add comments about races with "channels" sysfs dir Documentation: hyperv: Update VMBus doc with new features and info PCI: hv: Remove unnecessary flex array in struct pci_packet Drivers: hv: Remove hv_alloc/free_* helpers Drivers: hv: Use kzalloc for panic page allocation uio_hv_generic: Align ring size to system page uio_hv_generic: Use correct size for interrupt and monitor pages Drivers: hv: Allocate interrupt and monitor pages aligned to system page boundary arch/x86: Provide the CPU number in the wakeup AP callback x86/hyperv: Fix APIC ID and VP index confusion in hv_snp_boot_ap() PCI: hv: Get vPCI MSI IRQ domain from DeviceTree ACPI: irq: Introduce acpi_get_gsi_dispatcher() Drivers: hv: vmbus: Introduce hv_get_vmbus_root_device() Drivers: hv: vmbus: Get the IRQ number from DeviceTree dt-bindings: microsoft,vmbus: Add interrupt and DMA coherence properties arm64, x86: hyperv: Report the VTL the system boots in arm64: hyperv: Initialize the Virtual Trust Level field Drivers: hv: Provide arch-neutral implementation of get_vtl() Drivers: hv: Enable VTL mode for arm64 ...
2 parents 04446ee + 9695928 commit c00b285

File tree

30 files changed

+562
-235
lines changed

30 files changed

+562
-235
lines changed

Documentation/devicetree/bindings/bus/microsoft,vmbus.yaml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ maintainers:
1010
- Saurabh Sengar <ssengar@linux.microsoft.com>
1111

1212
description:
13-
VMBus is a software bus that implement the protocols for communication
14-
between the root or host OS and guest OSs (virtual machines).
13+
VMBus is a software bus that implements the protocols for communication
14+
between the root or host OS and guest OS'es (virtual machines).
1515

1616
properties:
1717
compatible:
@@ -25,16 +25,25 @@ properties:
2525
'#size-cells':
2626
const: 1
2727

28+
dma-coherent: true
29+
30+
interrupts:
31+
maxItems: 1
32+
description: Interrupt is used to report a message from the host.
33+
2834
required:
2935
- compatible
3036
- ranges
37+
- interrupts
3138
- '#address-cells'
3239
- '#size-cells'
3340

3441
additionalProperties: false
3542

3643
examples:
3744
- |
45+
#include <dt-bindings/interrupt-controller/irq.h>
46+
#include <dt-bindings/interrupt-controller/arm-gic.h>
3847
soc {
3948
#address-cells = <2>;
4049
#size-cells = <1>;
@@ -49,6 +58,9 @@ examples:
4958
#address-cells = <2>;
5059
#size-cells = <1>;
5160
ranges = <0x0f 0xf0000000 0x0f 0xf0000000 0x10000000>;
61+
dma-coherent;
62+
interrupt-parent = <&gic>;
63+
interrupts = <GIC_PPI 2 IRQ_TYPE_EDGE_RISING>;
5264
};
5365
};
5466
};

Documentation/virt/hyperv/vmbus.rst

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,18 @@ interrupts are not Linux IRQs, there are no entries in /proc/interrupts
250250
or /proc/irq corresponding to individual VMBus channel interrupts.
251251

252252
An online CPU in a Linux guest may not be taken offline if it has
253-
VMBus channel interrupts assigned to it. Any such channel
254-
interrupts must first be manually reassigned to another CPU as
255-
described above. When no channel interrupts are assigned to the
256-
CPU, it can be taken offline.
253+
VMBus channel interrupts assigned to it. Starting in kernel v6.15,
254+
any such interrupts are automatically reassigned to some other CPU
255+
at the time of offlining. The "other" CPU is chosen by the
256+
implementation and is not load balanced or otherwise intelligently
257+
determined. If the CPU is onlined again, channel interrupts previously
258+
assigned to it are not moved back. As a result, after multiple CPUs
259+
have been offlined, and perhaps onlined again, the interrupt-to-CPU
260+
mapping may be scrambled and non-optimal. In such a case, optimal
261+
assignments must be re-established manually. For kernels v6.14 and
262+
earlier, any conflicting channel interrupts must first be manually
263+
reassigned to another CPU as described above. Then when no channel
264+
interrupts are assigned to the CPU, it can be taken offline.
257265

258266
The VMBus channel interrupt handling code is designed to work
259267
correctly even if an interrupt is received on a CPU other than the
@@ -324,3 +332,15 @@ rescinded, neither Hyper-V nor Linux retains any state about
324332
its previous existence. Such a device might be re-added later,
325333
in which case it is treated as an entirely new device. See
326334
vmbus_onoffer_rescind().
335+
336+
For some devices, such as the KVP device, Hyper-V automatically
337+
sends a rescind message when the primary channel is closed,
338+
likely as a result of unbinding the device from its driver.
339+
The rescind causes Linux to remove the device. But then Hyper-V
340+
immediately reoffers the device to the guest, causing a new
341+
instance of the device to be created in Linux. For other
342+
devices, such as the synthetic SCSI and NIC devices, closing the
343+
primary channel does *not* result in Hyper-V sending a rescind
344+
message. The device continues to exist in Linux on the VMBus,
345+
but with no driver bound to it. The same driver or a new driver
346+
can subsequently be bound to the existing instance of the device.

arch/arm64/hyperv/mshyperv.c

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,48 @@ int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
2828
}
2929
EXPORT_SYMBOL_GPL(hv_get_hypervisor_version);
3030

31+
#ifdef CONFIG_ACPI
32+
33+
static bool __init hyperv_detect_via_acpi(void)
34+
{
35+
if (acpi_disabled)
36+
return false;
37+
/*
38+
* Hypervisor ID is only available in ACPI v6+, and the
39+
* structure layout was extended in v6 to accommodate that
40+
* new field.
41+
*
42+
* At the very minimum, this check makes sure not to read
43+
* past the FADT structure.
44+
*
45+
* It is also needed to catch running in some unknown
46+
* non-Hyper-V environment that has ACPI 5.x or less.
47+
* In such a case, it can't be Hyper-V.
48+
*/
49+
if (acpi_gbl_FADT.header.revision < 6)
50+
return false;
51+
return strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8) == 0;
52+
}
53+
54+
#else
55+
56+
static bool __init hyperv_detect_via_acpi(void)
57+
{
58+
return false;
59+
}
60+
61+
#endif
62+
63+
static bool __init hyperv_detect_via_smccc(void)
64+
{
65+
uuid_t hyperv_uuid = UUID_INIT(
66+
0x58ba324d, 0x6447, 0x24cd,
67+
0x75, 0x6c, 0xef, 0x8e,
68+
0x24, 0x70, 0x59, 0x16);
69+
70+
return arm_smccc_hypervisor_has_uuid(&hyperv_uuid);
71+
}
72+
3173
static int __init hyperv_init(void)
3274
{
3375
struct hv_get_vp_registers_output result;
@@ -36,13 +78,11 @@ static int __init hyperv_init(void)
3678

3779
/*
3880
* Allow for a kernel built with CONFIG_HYPERV to be running in
39-
* a non-Hyper-V environment, including on DT instead of ACPI.
81+
* a non-Hyper-V environment.
82+
*
4083
* In such cases, do nothing and return success.
4184
*/
42-
if (acpi_disabled)
43-
return 0;
44-
45-
if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
85+
if (!hyperv_detect_via_acpi() && !hyperv_detect_via_smccc())
4686
return 0;
4787

4888
/* Setup the guest ID */
@@ -77,6 +117,9 @@ static int __init hyperv_init(void)
77117

78118
if (ms_hyperv.priv_high & HV_ACCESS_PARTITION_ID)
79119
hv_get_partition_id();
120+
ms_hyperv.vtl = get_vtl();
121+
if (ms_hyperv.vtl > 0) /* non default VTL */
122+
pr_info("Linux runs in Hyper-V Virtual Trust Level %d\n", ms_hyperv.vtl);
80123

81124
ms_hyperv_late_init();
82125

arch/arm64/kvm/hypercalls.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
270270
u32 feature;
271271
u8 action;
272272
gpa_t gpa;
273+
uuid_t uuid;
273274

274275
action = kvm_smccc_get_action(vcpu, func_id);
275276
switch (action) {
@@ -355,10 +356,11 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
355356
val[0] = gpa;
356357
break;
357358
case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
358-
val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
359-
val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
360-
val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
361-
val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
359+
uuid = ARM_SMCCC_VENDOR_HYP_UID_KVM;
360+
val[0] = smccc_uuid_to_reg(&uuid, 0);
361+
val[1] = smccc_uuid_to_reg(&uuid, 1);
362+
val[2] = smccc_uuid_to_reg(&uuid, 2);
363+
val[3] = smccc_uuid_to_reg(&uuid, 3);
362364
break;
363365
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
364366
val[0] = smccc_feat->vendor_hyp_bmap;

arch/x86/coco/sev/core.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -869,12 +869,12 @@ static void *snp_alloc_vmsa_page(int cpu)
869869
return page_address(p + 1);
870870
}
871871

872-
static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
872+
static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned int cpu)
873873
{
874874
struct sev_es_save_area *cur_vmsa, *vmsa;
875875
struct svsm_ca *caa;
876876
u8 sipi_vector;
877-
int cpu, ret;
877+
int ret;
878878
u64 cr4;
879879

880880
/*
@@ -895,15 +895,6 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
895895

896896
/* Override start_ip with known protected guest start IP */
897897
start_ip = real_mode_header->sev_es_trampoline_start;
898-
899-
/* Find the logical CPU for the APIC ID */
900-
for_each_present_cpu(cpu) {
901-
if (arch_match_cpu_phys_id(cpu, apic_id))
902-
break;
903-
}
904-
if (cpu >= nr_cpu_ids)
905-
return -EINVAL;
906-
907898
cur_vmsa = per_cpu(sev_vmsa, cpu);
908899

909900
/*

arch/x86/hyperv/hv_init.c

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -391,40 +391,6 @@ static void __init hv_stimer_setup_percpu_clockev(void)
391391
old_setup_percpu_clockev();
392392
}
393393

394-
#if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
395-
static u8 __init get_vtl(void)
396-
{
397-
u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_REGISTERS;
398-
struct hv_input_get_vp_registers *input;
399-
struct hv_output_get_vp_registers *output;
400-
unsigned long flags;
401-
u64 ret;
402-
403-
local_irq_save(flags);
404-
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
405-
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
406-
407-
memset(input, 0, struct_size(input, names, 1));
408-
input->partition_id = HV_PARTITION_ID_SELF;
409-
input->vp_index = HV_VP_INDEX_SELF;
410-
input->input_vtl.as_uint8 = 0;
411-
input->names[0] = HV_REGISTER_VSM_VP_STATUS;
412-
413-
ret = hv_do_hypercall(control, input, output);
414-
if (hv_result_success(ret)) {
415-
ret = output->values[0].reg8 & HV_X64_VTL_MASK;
416-
} else {
417-
pr_err("Failed to get VTL(error: %lld) exiting...\n", ret);
418-
BUG();
419-
}
420-
421-
local_irq_restore(flags);
422-
return ret;
423-
}
424-
#else
425-
static inline u8 get_vtl(void) { return 0; }
426-
#endif
427-
428394
/*
429395
* This function is to be invoked early in the boot sequence after the
430396
* hypervisor has been detected.
@@ -707,3 +673,36 @@ bool hv_is_hyperv_initialized(void)
707673
return hypercall_msr.enable;
708674
}
709675
EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
676+
677+
int hv_apicid_to_vp_index(u32 apic_id)
678+
{
679+
u64 control;
680+
u64 status;
681+
unsigned long irq_flags;
682+
struct hv_get_vp_from_apic_id_in *input;
683+
u32 *output, ret;
684+
685+
local_irq_save(irq_flags);
686+
687+
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
688+
memset(input, 0, sizeof(*input));
689+
input->partition_id = HV_PARTITION_ID_SELF;
690+
input->apic_ids[0] = apic_id;
691+
692+
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
693+
694+
control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_INDEX_FROM_APIC_ID;
695+
status = hv_do_hypercall(control, input, output);
696+
ret = output[0];
697+
698+
local_irq_restore(irq_flags);
699+
700+
if (!hv_result_success(status)) {
701+
pr_err("failed to get vp index from apic id %d, status %#llx\n",
702+
apic_id, status);
703+
return -EINVAL;
704+
}
705+
706+
return ret;
707+
}
708+
EXPORT_SYMBOL_GPL(hv_apicid_to_vp_index);

arch/x86/hyperv/hv_vtl.c

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ static void __noreturn hv_vtl_restart(char __maybe_unused *cmd)
5656

5757
void __init hv_vtl_init_platform(void)
5858
{
59-
pr_info("Linux runs in Hyper-V Virtual Trust Level\n");
59+
/*
60+
* This function is a no-op if the VTL mode is not enabled.
61+
* If it is, this function runs if and only the kernel boots in
62+
* VTL2 which the x86 hv initialization path makes sure of.
63+
*/
64+
pr_info("Linux runs in Hyper-V Virtual Trust Level %d\n", ms_hyperv.vtl);
6065

6166
x86_platform.realmode_reserve = x86_init_noop;
6267
x86_platform.realmode_init = x86_init_noop;
@@ -207,63 +212,23 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
207212
return ret;
208213
}
209214

210-
static int hv_vtl_apicid_to_vp_id(u32 apic_id)
211-
{
212-
u64 control;
213-
u64 status;
214-
unsigned long irq_flags;
215-
struct hv_get_vp_from_apic_id_in *input;
216-
u32 *output, ret;
217-
218-
local_irq_save(irq_flags);
219-
220-
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
221-
memset(input, 0, sizeof(*input));
222-
input->partition_id = HV_PARTITION_ID_SELF;
223-
input->apic_ids[0] = apic_id;
224-
225-
output = *this_cpu_ptr(hyperv_pcpu_output_arg);
226-
227-
control = HV_HYPERCALL_REP_COMP_1 | HVCALL_GET_VP_ID_FROM_APIC_ID;
228-
status = hv_do_hypercall(control, input, output);
229-
ret = output[0];
230-
231-
local_irq_restore(irq_flags);
232-
233-
if (!hv_result_success(status)) {
234-
pr_err("failed to get vp id from apic id %d, status %#llx\n",
235-
apic_id, status);
236-
return -EINVAL;
237-
}
238-
239-
return ret;
240-
}
241-
242-
static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip)
215+
static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip, unsigned int cpu)
243216
{
244-
int vp_id, cpu;
245-
246-
/* Find the logical CPU for the APIC ID */
247-
for_each_present_cpu(cpu) {
248-
if (arch_match_cpu_phys_id(cpu, apicid))
249-
break;
250-
}
251-
if (cpu >= nr_cpu_ids)
252-
return -EINVAL;
217+
int vp_index;
253218

254219
pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid);
255-
vp_id = hv_vtl_apicid_to_vp_id(apicid);
220+
vp_index = hv_apicid_to_vp_index(apicid);
256221

257-
if (vp_id < 0) {
222+
if (vp_index < 0) {
258223
pr_err("Couldn't find CPU with APIC ID %d\n", apicid);
259224
return -EINVAL;
260225
}
261-
if (vp_id > ms_hyperv.max_vp_index) {
262-
pr_err("Invalid CPU id %d for APIC ID %d\n", vp_id, apicid);
226+
if (vp_index > ms_hyperv.max_vp_index) {
227+
pr_err("Invalid CPU id %d for APIC ID %d\n", vp_index, apicid);
263228
return -EINVAL;
264229
}
265230

266-
return hv_vtl_bringup_vcpu(vp_id, cpu, start_eip);
231+
return hv_vtl_bringup_vcpu(vp_index, cpu, start_eip);
267232
}
268233

269234
int __init hv_vtl_early_init(void)

0 commit comments

Comments
 (0)