From: Dexuan Cui <[email protected]> Sent: Thursday, April 16, 2026 11:35 AM > > If vmbus_reserve_fb() in the kdump kernel fails to properly reserve the
This problem has wider scope than just kdump. Any kexec'ed kernel would see the same problem, though kdump is probably the most common case. But the discussion here, and the mention of kdump in the code comments, should be adjusted accordingly. > framebuffer MMIO range due to a Gen2 VM's screen.lfb_base being zero [1], > there is an MMIO conflict between the drivers hyperv_drm and pci-hyperv. You describe an MMIO "conflict" without giving the details. Is that intentional to keep the commit message from being too long? It might be helpful to future readers to say a little more about how PCI devices must not use MMIO space that the hypervisor has assigned to the frame buffer. > This is especially an issue if pci-hyperv is built-in and hyperv_drm is > built as a module. Consequently, the kdump kernel fails to detect PCI > devices via pci-hyperv, and may fail to mount the root file system, > which may reside in a NVMe disk. It might not just be pci-hyperv that conflicts. The recently submitted dxgkrnl driver also does vmbus_allocate_mmio(), but I haven't looked at the details of exactly what it is doing. > > On Gen2 VMs, if the screen.lfb_base is 0 in the kdump kernel, fall > back to the low MMIO base, which should be equal to the framebuffer > MMIO base (Tested on x64 Windows Server 2016, and on x64 and ARM64 Windows > Server 2025 and on Azure) [2]. In the first kernel, screen.lfb_base > is not 0; if the user specifies a high resolution, it's not enough to > only reserve 8MB: in this case, reserve half of the space below 4GB, but > cap the reservation to 128MB, which is the required framebuffer size of > the highest resolution 7680*4320 supported by Hyper-V. As you noted in the detailed discussion in the other email thread [2], there's a Gen1 VM case that this patch doesn't fix. For completeness, perhaps that case should be called out in this commit message. > > Add the cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) check, because a CoCo > VM (i.e. Confidential VM) on Hyper-V doesn't have any framebuffer > device, so there is no need to reserve any MMIO for it. > > While at it, fix the comparison "end > VTPM_BASE_ADDRESS" by changing > the > to >=. Here the 'end' is an inclusive end (typically, it's > 0xFFFF_FFFF). > > [1] > https://lore.kernel.org/all/sa1pr21mb692176c1bc53bfc9eae5cf8ebf...@sa1pr21mb6921.namprd21.prod.outlook.com/ > [2] > https://lore.kernel.org/all/sa1pr21mb69218f955b62dff62e3e88d2bf...@sa1pr21mb6921.namprd21.prod.outlook.com/ > > Fixes: 4daace0d8ce8 ("PCI: hv: Add paravirtual PCI front-end for Microsoft > Hyper-V VMs") > CC: [email protected] > Signed-off-by: Dexuan Cui <[email protected]> > --- > drivers/hv/vmbus_drv.c | 30 ++++++++++++++++++++++++++++-- > 1 file changed, 28 insertions(+), 2 deletions(-) > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > index f0d0803d1e16..a0b34f9e426a 100644 > --- a/drivers/hv/vmbus_drv.c > +++ b/drivers/hv/vmbus_drv.c > @@ -37,6 +37,7 @@ > #include <linux/dma-map-ops.h> > #include <linux/pci.h> > #include <linux/export.h> > +#include <linux/cc_platform.h> > #include <clocksource/hyperv_timer.h> > #include <asm/mshyperv.h> > #include "hyperv_vmbus.h" > @@ -2327,8 +2328,8 @@ static acpi_status vmbus_walk_resources(struct > acpi_resource *res, void *ctx) > return AE_NO_MEMORY; > > /* If this range overlaps the virtual TPM, truncate it. */ > - if (end > VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS) > - end = VTPM_BASE_ADDRESS; > + if (end >= VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS) > + end = VTPM_BASE_ADDRESS - 1; > > new_res->name = "hyperv mmio"; > new_res->flags = IORESOURCE_MEM; > @@ -2395,13 +2396,36 @@ static void vmbus_mmio_remove(void) > static void __maybe_unused vmbus_reserve_fb(void) > { > resource_size_t start = 0, size; > + resource_size_t low_mmio_base; > struct pci_dev *pdev; > > + /* Hyper-V CoCo guests do not have a framebuffer device. */ > + if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) > + return; This test is testing feature "A" (mem encryption) in order to determine the presence of feature "B" (no framebuffer), because current configurations happen to always have "A" and "B" at the same time. But the linkage between the features is tenuous, and if configurations should change in the future, testing this way could be bogus. It works now, but I'm leery of depending on the linkage between "A" and "B". You could set up a "can_have_framebuffer" flag in ms_hyperv_init_platform() if running in a CVM, and test that flag here. But I'd suggest just dropping this optimization. CVMs are always Gen2 (and that's not going to change), so they have plenty of low mmio space. And at the moment, CVMs don't support PCI devices, so can't encounter a conflict (though conceivably some new flavor of CVM in the future could support PCI devices). > + > if (efi_enabled(EFI_BOOT)) { > /* Gen2 VM: get FB base from EFI framebuffer */ > if (IS_ENABLED(CONFIG_SYSFB)) { > start = sysfb_primary_display.screen.lfb_base; > size = max_t(__u32, > sysfb_primary_display.screen.lfb_size, 0x800000); > + > + low_mmio_base = hyperv_mmio->start; > + if (!low_mmio_base || low_mmio_base >= SZ_4G || > + (start && start < low_mmio_base)) { > + pr_warn("Unexpected low mmio base 0x%pa\n", > &low_mmio_base); > + } else { > + /* > + * If the kdump kernel's lfb_base is 0, As mentioned earlier, this case isn't just kdump kernels. > + * fall back to the low mmio base. > + */ > + if (!start) > + start = low_mmio_base; > + /* > + * Reserve half of the space below 4GB for high > + * resolutions, but cap the reservation to > 128MB. > + */ > + size = min((SZ_4G - start) / 2, SZ_128M); > + } > } > } else { > /* Gen1 VM: get FB base from PCI */ > @@ -2433,6 +2457,8 @@ static void __maybe_unused vmbus_reserve_fb(void) > */ > for (; !fb_mmio && (size >= 0x100000); size >>= 1) > fb_mmio = __request_region(hyperv_mmio, start, size, > fb_mmio_name, 0); Just above this "for" loop, "start" is tested for 0. This patch eliminates the main reason start might be 0. But I guess it's still possible that the legacy PCI device BAR might return 0 for a Gen1 VM? Or you might get 0 if the pr_warn() about low mmio base is triggered. But I'm thinking maybe a pr_warn() should be done if start is zero. > + > + pr_info("hv_mmio=%pR,%pR fb=%pR\n", hyperv_mmio, hyperv_mmio->sibling, > fb_mmio); Outputting the above info is nice! Michael

