Commit 65694c5a authored by Matt Fleming's avatar Matt Fleming Committed by Bjorn Helgaas

x86/PCI: Map PCI setup data with ioremap() so it can be in highmem

f9a37be0 ("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: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: stable@vger.kernel.org	# v3.8+
parent f3f01175
...@@ -628,7 +628,9 @@ int pcibios_add_device(struct pci_dev *dev) ...@@ -628,7 +628,9 @@ int pcibios_add_device(struct pci_dev *dev)
pa_data = boot_params.hdr.setup_data; pa_data = boot_params.hdr.setup_data;
while (pa_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) { if (data->type == SETUP_PCI) {
rom = (struct pci_setup_rom *)data; rom = (struct pci_setup_rom *)data;
...@@ -645,6 +647,7 @@ int pcibios_add_device(struct pci_dev *dev) ...@@ -645,6 +647,7 @@ int pcibios_add_device(struct pci_dev *dev)
} }
} }
pa_data = data->next; pa_data = data->next;
iounmap(data);
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment