Patchwork [29/84] x86/PCI: Map PCI setup data with ioremap() so it can be in highmem

mail settings
Submitter Kamal Mostafa
Date June 17, 2013, 5:30 p.m.
Message ID <>
Download mbox | patch
Permalink /patch/251960/
State New
Headers show


Kamal Mostafa - June 17, 2013, 5:30 p.m. -stable review patch.  If anyone has any objections, please let me know.


From: Matt Fleming <>

commit 65694c5aaddfedd9da082e4e150cafc6b3fc8a6a upstream.

f9a37be0f0 ("x86: Use PCI setup data") added support for using PCI ROM
images from setup_data.  This used phys_to_virt(), which is not valid for
highmem addresses, and can cause a crash when booting a 32-bit kernel via
the EFI boot stub.

pcibios_add_device() assumes that the physical addresses stored in
setup_data are accessible via the direct kernel mapping, and that calling
phys_to_virt() is valid.  This isn't guaranteed to be true on x86 where the
direct mapping range is much smaller than on x86-64.

Calling phys_to_virt() on a highmem address results in the following:

 BUG: unable to handle kernel paging request at 39a3c198
 IP: [<c262be0f>] pcibios_add_device+0x2f/0x90
 Call Trace:
  [<c2370c73>] pci_device_add+0xe3/0x130
  [<c274640b>] pci_scan_single_device+0x8b/0xb0
  [<c2370d08>] pci_scan_slot+0x48/0x100
  [<c2371904>] pci_scan_child_bus+0x24/0xc0
  [<c262a7b0>] pci_acpi_scan_root+0x2c0/0x490
  [<c23b7203>] acpi_pci_root_add+0x312/0x42f

The solution is to use ioremap() instead of phys_to_virt() to map the
setup data into the kernel address space.

[bhelgaas: changelog]
Tested-by: Jani Nikula <>
Signed-off-by: Matt Fleming <>
Signed-off-by: Bjorn Helgaas <>
Cc: Matthew Garrett <>
Cc: Seth Forshee <>
Cc: Jesse Barnes <>
Signed-off-by: Kamal Mostafa <>
 arch/x86/pci/common.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)


diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index ccd0ab3..f24ba14 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -618,7 +618,9 @@  int pcibios_add_device(struct pci_dev *dev)
 	pa_data = boot_params.hdr.setup_data;
 	while (pa_data) {
-		data = phys_to_virt(pa_data);
+		data = ioremap(pa_data, sizeof(*rom));
+		if (!data)
+			return -ENOMEM;
 		if (data->type == SETUP_PCI) {
 			rom = (struct pci_setup_rom *)data;
@@ -635,6 +637,7 @@  int pcibios_add_device(struct pci_dev *dev)
 		pa_data = data->next;
+		iounmap(data);
 	return 0;