Linux-mtd Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mtd: maps: add INT0800 firmware-flash map driver
@ 2026-09-17  1:04 Stephen Bancroft
  2026-09-17  1:14 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Stephen Bancroft @ 2026-09-17  1:04 UTC (permalink / raw)
  To: linux-mtd; +Cc: miquel.raynal, richard, vigneshr, Stephen Bancroft

Add a read-only mapping driver that binds the ACPI INT0800 "Intel
82802 firmware hub" device and exposes the system firmware flash as an
MTD ROM device.

On x86 machines the boot flash is decoded into the physical address
space below 4 GB, so a plain ioremap() of the declared resource window
is sufficient for reads - no SPI or LPC controller access is needed.
The window may be larger than the real flash; undecoded holes read as
0xff.

This gives userspace a clean, safe way to read firmware flash contents
without flashrom or relaxed /dev/mem access - for firmware analysis,
and for extracting option ROMs stored inside EFI firmware volumes
(e.g. the NVIDIA VBIOS on EFI-booted Apple machines, which can then be
fed to nouveau via nouveau.config=NvBios=). There is deliberately no
write or erase support.

Tested on a MacBookPro4,1 (ICH8M): /dev/mtd0 reads are byte-identical
to a flashrom dump of the 2 MiB SST25VF016B, except for live NVRAM
variable-store regions.
---
 drivers/mtd/maps/Kconfig   | 17 +++++++
 drivers/mtd/maps/Makefile  |  1 +
 drivers/mtd/maps/int0800.c | 96 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
 create mode 100644 drivers/mtd/maps/int0800.c

diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 1bb3dba..649fd14 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -161,6 +161,23 @@ config MTD_AMD76XROM
 
 	  BE VERY CAREFUL.
 
+config MTD_INT0800
+	tristate "Read-only BIOS/firmware flash via ACPI INT0800"
+	depends on X86 && ACPI
+	select MTD_ROM
+	help
+	  Support for reading the system firmware (BIOS/EFI) flash chip
+	  through the memory window described by the ACPI INT0800
+	  "82802 firmware hub" device, present on most x86 machines.
+
+	  The flash is exposed read-only via the ROM chip driver, e.g.
+	  for firmware analysis or extracting option ROMs (such as
+	  video BIOS images embedded in EFI firmware volumes). There is
+	  no write or erase support.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called int0800.
+
 config MTD_ICHXROM
 	tristate "BIOS flash chip on Intel Controller Hub 2/3/4/5"
 	depends on X86 && MTD_JEDECPROBE
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 01745ec..2f1a737 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
 obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
 obj-$(CONFIG_MTD_ESB2ROM)	+= esb2rom.o
 obj-$(CONFIG_MTD_ICHXROM)	+= ichxrom.o
+obj-$(CONFIG_MTD_INT0800)	+= int0800.o
 obj-$(CONFIG_MTD_CK804XROM)	+= ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)	+= pxa2xx-flash.o
diff --git a/drivers/mtd/maps/int0800.c b/drivers/mtd/maps/int0800.c
new file mode 100644
index 0000000..2438d97
--- /dev/null
+++ b/drivers/mtd/maps/int0800.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Read-only MTD access to the system firmware flash behind the ACPI
+ * INT0800 "Intel 82802 firmware hub" device.
+ *
+ * On x86 systems the boot flash is decoded into the physical address
+ * space below 4 GB, so a plain ioremap() is sufficient to read it -
+ * no SPI or LPC controller access is required.  The declared _CRS
+ * window may be larger than the real flash (the whole top-16MiB
+ * decode range is commonly claimed); undecoded holes read as 0xff.
+ *
+ * The device is exposed read-only via the ROM chip driver; there is
+ * deliberately no write or erase support.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/platform_device.h>
+
+/* top-of-4GB firmware decode, used when _CRS reports no window */
+#define INT0800_DEFAULT_PHYS	0xffe00000UL
+#define INT0800_DEFAULT_SIZE	SZ_2M
+
+static struct map_info int0800_map = {
+	.name		= "int0800",
+	.bankwidth	= 1,
+};
+
+static struct mtd_info *int0800_mtd;
+
+static int int0800_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res) {
+		int0800_map.phys = res->start;
+		int0800_map.size = resource_size(res);
+	} else {
+		int0800_map.phys = INT0800_DEFAULT_PHYS;
+		int0800_map.size = INT0800_DEFAULT_SIZE;
+	}
+
+	/*
+	 * Plain ioremap on purpose: the window is already claimed by the
+	 * ACPI/pnp resource reservation, so devm_ioremap_resource() would
+	 * fail with -EBUSY.
+	 */
+	int0800_map.virt = ioremap(int0800_map.phys, int0800_map.size);
+	if (!int0800_map.virt)
+		return -ENOMEM;
+
+	simple_map_init(&int0800_map);
+	int0800_mtd = do_map_probe("map_rom", &int0800_map);
+	if (!int0800_mtd) {
+		iounmap(int0800_map.virt);
+		return -ENODEV;
+	}
+	int0800_mtd->dev.parent = &pdev->dev;
+
+	dev_info(&pdev->dev, "mapped firmware window 0x%lx-0x%lx\n",
+		 int0800_map.phys,
+		 int0800_map.phys + int0800_map.size - 1);
+
+	return mtd_device_register(int0800_mtd, NULL, 0);
+}
+
+static void int0800_remove(struct platform_device *pdev)
+{
+	mtd_device_unregister(int0800_mtd);
+	map_destroy(int0800_mtd);
+	iounmap(int0800_map.virt);
+}
+
+static const struct acpi_device_id int0800_ids[] = {
+	{ "INT0800", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, int0800_ids);
+
+static struct platform_driver int0800_driver = {
+	.probe	= int0800_probe,
+	.remove	= int0800_remove,
+	.driver	= {
+		.name		= "int0800",
+		.acpi_match_table = int0800_ids,
+	},
+};
+module_platform_driver(int0800_driver);
+
+MODULE_AUTHOR("Devin");
+MODULE_DESCRIPTION("Read-only MTD map over the INT0800 firmware flash window");
+MODULE_LICENSE("GPL");
-- 
2.43.0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] mtd: maps: add INT0800 firmware-flash map driver
  2026-09-17  1:04 [PATCH] mtd: maps: add INT0800 firmware-flash map driver Stephen Bancroft
@ 2026-09-17  1:14 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-09-17  1:14 UTC (permalink / raw)
  To: linux-mtd, Stephen Bancroft; +Cc: richard, vigneshr, miquel.raynal

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] mtd: memory and mapping leak on mtd_device_register() failure
- [Medium] mtd: shared state corruption via global variables in probe
- [Low] mtd: format string mismatch for resource_size_t in dev_info
--

commit a217a15f9e29300a155e6f6c8138325d4f178f7b
Author: Stephen Bancroft <stevereaver@gmail.com>

mtd: maps: add INT0800 firmware-flash map driver

This commit adds a read-only MTD mapping driver for the ACPI INT0800
firmware hub device on x86. It exposes the system firmware flash as an
MTD ROM device to allow userspace to read the firmware flash contents safely.

> diff --git a/drivers/mtd/maps/int0800.c b/drivers/mtd/maps/int0800.c
> new file mode 100644
> index 0000000000000..2438d970b9fa4
> --- /dev/null
> +++ b/drivers/mtd/maps/int0800.c
[ ... ]
> +static struct map_info int0800_map = {
> +	.name		= "int0800",
> +	.bankwidth	= 1,
> +};
> +
> +static struct mtd_info *int0800_mtd;
> +
> +static int int0800_probe(struct platform_device *pdev)
> +{
[ ... ]
> +	int0800_map.virt = ioremap(int0800_map.phys, int0800_map.size);

[Severity: Medium]
Since int0800_map and int0800_mtd are global variables, what happens if
multiple INT0800 devices are enumerated?

It looks like this unconditionally overwrites the global state during
int0800_probe(). Later, int0800_remove() will free these globally stored
pointers, which could destroy the state for all active instances or cause a
double-free.

[ ... ]
> +	dev_info(&pdev->dev, "mapped firmware window 0x%lx-0x%lx\n",
> +		 int0800_map.phys,
> +		 int0800_map.phys + int0800_map.size - 1);

[Severity: Low]
Does this format string cause issues on 32-bit architectures where
resource_size_t is a 64-bit integer?

Using %lx for resource_size_t can consume only half the value and misalign
subsequent arguments on the stack. Should this use %pa or an explicit cast
to u64 with %llx instead?

> +
> +	return mtd_device_register(int0800_mtd, NULL, 0);
> +}

[Severity: Medium]
If mtd_device_register() fails here, do we leak the memory mapping and the
MTD instance?

Normally, we would expect to see map_destroy() and iounmap() on this failure
path, similar to what is done in int0800_remove(), but here the error is
returned directly.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260917010431.29714-1-stevereaver@gmail.com?part=1

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-17  1:14 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17  1:04 [PATCH] mtd: maps: add INT0800 firmware-flash map driver Stephen Bancroft
2026-09-17  1:14 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox