diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-06-05 15:15:41 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-06-13 10:49:00 -0700 |
commit | f44b32e76bc1b03d3ec6e43ba4c789fb8462a795 (patch) | |
tree | 91d46a3dffd3c2d727b77f3fbd0bba6b1a5ca238 | |
parent | a9b4f1537955bfee22e87f9f049c29aa777d5ec9 (diff) |
x86/PCI: Map PCI setup data with ioremap() so it can be in highmem
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 <jani.nikula@intel.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Seth Forshee <seth.forshee@canonical.com>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | arch/x86/pci/common.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 901177d75ff..1dc3d7c86b8 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -617,7 +617,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; @@ -634,6 +636,7 @@ int pcibios_add_device(struct pci_dev *dev) } } pa_data = data->next; + iounmap(data); } return 0; } |