From: "Michael S. Tsirkin" <mst@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: Alex Williamson <alex@shazbot.org>, kvm@vger.kernel.org
Subject: [PATCH] vfio/pci: read ROM via ACPI _ROM when hardware ROM is unreadable
Date: Tue, 13 Oct 2026 19:25:15 -0400 [thread overview]
Message-ID: <31aa2fb273d7ff7ea535c74e0780e279aa9a119c.1791933554.git.mst@redhat.com> (raw)
Some GPUs (e.g. NVIDIA Quadro P2000 Mobile in a laptop) have a ROM
BAR that exists but is unreadable because the GPU was never POSTed
by the system BIOS. On these systems the VBIOS is available via the
ACPI _ROM method provided by the platform firmware.
Add an ACPI _ROM fallback in the VFIO PCI ROM region handler. When
both pci_map_rom() and the platform ROM (pdev->rom) fail, evaluate
the device's ACPI _ROM method to read the ROM.
Assisted-by: LLM
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
Hi Alex,
this makes this box I found in the dumpster go brr) Pls take a look.
drivers/vfio/pci/vfio_pci_core.c | 9 +++
drivers/vfio/pci/vfio_pci_priv.h | 9 +++
drivers/vfio/pci/vfio_pci_rdwr.c | 124 +++++++++++++++++++++++++++++++
3 files changed, 142 insertions(+)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 6757054e9d87..53f53653421e 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -1193,6 +1193,15 @@ int vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev,
info->size = roundup_pow_of_two(pdev->romlen);
}
+ if (!info->size) {
+ size_t acpi_size = vfio_pci_acpi_rom_size(pdev);
+
+ if (acpi_size) {
+ info->flags = VFIO_REGION_INFO_FLAG_READ;
+ info->size = roundup_pow_of_two(acpi_size);
+ }
+ }
+
break;
}
case VFIO_PCI_VGA_REGION_INDEX:
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index 4e7162234a2e..07c23507832c 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -44,6 +44,15 @@ ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev,
ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite);
+#ifdef CONFIG_ACPI
+size_t vfio_pci_acpi_rom_size(struct pci_dev *pdev);
+#else
+static inline size_t vfio_pci_acpi_rom_size(struct pci_dev *pdev)
+{
+ return 0;
+}
+#endif
+
#ifdef CONFIG_VFIO_PCI_VGA
ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite);
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index 7f14dd46de17..654af45e8edc 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -10,6 +10,7 @@
* Author: Tom Lyon, pugs@cisco.com
*/
+#include <linux/acpi.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
@@ -198,6 +199,112 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
}
EXPORT_SYMBOL_GPL(vfio_pci_core_do_io_rw);
+#ifdef CONFIG_ACPI
+static int vfio_pci_acpi_rom_read(struct pci_dev *pdev, void *buf,
+ loff_t offset, size_t length)
+{
+ acpi_handle handle, rom_handle;
+ acpi_status status;
+ union acpi_object rom_arg[2];
+ struct acpi_object_list rom_args;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ status = acpi_get_handle(handle, "_ROM", &rom_handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ rom_args.count = 2;
+ rom_args.pointer = rom_arg;
+ rom_arg[0].type = ACPI_TYPE_INTEGER;
+ rom_arg[0].integer.value = offset;
+ rom_arg[1].type = ACPI_TYPE_INTEGER;
+ rom_arg[1].integer.value = length;
+
+ status = acpi_evaluate_object(rom_handle, NULL, &rom_args, &buffer);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ kfree(buffer.pointer);
+ return -EIO;
+ }
+ length = min(length, (size_t)obj->buffer.length);
+ memcpy(buf, obj->buffer.pointer, length);
+ kfree(buffer.pointer);
+ return length;
+}
+
+static ssize_t vfio_pci_acpi_rom_rw(struct vfio_pci_core_device *vdev,
+ char __user *buf, size_t count,
+ loff_t pos, bool iswrite)
+{
+ struct pci_dev *pdev = vdev->pdev;
+ void *chunk;
+ ssize_t done = 0;
+ int ret;
+
+ if (iswrite)
+ return -EINVAL;
+
+ chunk = kmalloc(0x1000, GFP_KERNEL);
+ if (!chunk)
+ return -ENOMEM;
+
+ while (count) {
+ size_t n = min(count, (size_t)0x1000);
+
+ ret = vfio_pci_acpi_rom_read(pdev, chunk, pos, n);
+ if (ret <= 0) {
+ if (ret < 0 && !done)
+ done = ret;
+ break;
+ }
+
+ if (copy_to_user(buf, chunk, ret)) {
+ done = done ? done : -EFAULT;
+ break;
+ }
+
+ buf += ret;
+ pos += ret;
+ done += ret;
+ count -= ret;
+
+ if (ret < n)
+ break;
+ }
+
+ kfree(chunk);
+ return done;
+}
+
+size_t vfio_pci_acpi_rom_size(struct pci_dev *pdev)
+{
+ void *buf;
+ size_t size = 0;
+ int ret;
+
+ buf = kmalloc(0x1000, GFP_KERNEL);
+ if (!buf)
+ return 0;
+
+ do {
+ ret = vfio_pci_acpi_rom_read(pdev, buf, size, 0x1000);
+ if (ret > 0)
+ size += ret;
+ } while (ret == 0x1000);
+
+ kfree(buf);
+ return size;
+}
+#endif /* CONFIG_ACPI */
+
ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite)
{
@@ -215,6 +322,14 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
end = pci_resource_len(pdev, bar);
else if (bar == PCI_ROM_RESOURCE && pdev->rom && pdev->romlen)
end = roundup_pow_of_two(pdev->romlen);
+#ifdef CONFIG_ACPI
+ else if (bar == PCI_ROM_RESOURCE) {
+ end = vfio_pci_acpi_rom_size(pdev);
+ if (!end)
+ return -EINVAL;
+ end = roundup_pow_of_two(end);
+ }
+#endif
else
return -EINVAL;
@@ -235,6 +350,15 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
io = ioremap(pdev->rom, pdev->romlen);
x_start = pdev->romlen;
}
+#ifdef CONFIG_ACPI
+ if (!io) {
+ done = vfio_pci_acpi_rom_rw(vdev, buf, count,
+ pos, iswrite);
+ if (done >= 0)
+ *ppos += done;
+ return done;
+ }
+#endif
if (!io)
return -ENOMEM;
x_end = end;
--
MST
next reply other threads:[~2026-10-13 23:25 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 23:25 Michael S. Tsirkin [this message]
2026-10-15 17:27 ` Alex Williamson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=31aa2fb273d7ff7ea535c74e0780e279aa9a119c.1791933554.git.mst@redhat.com \
--to=mst@redhat.com \
--cc=alex@shazbot.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®