Return-Path: From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jani Nikula , Matt Fleming , Bjorn Helgaas , Matthew Garrett , Seth Forshee , Jesse Barnes Subject: [ 09/79] x86/PCI: Map PCI setup data with ioremap() so it can be in highmem Date: Tue, 11 Jun 2013 13:02:35 -0700 Message-Id: <20130611195313.629553357@linuxfoundation.org> In-Reply-To: <20130611195312.352656079@linuxfoundation.org> References: <20130611195312.352656079@linuxfoundation.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: 3.9-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: [] pcibios_add_device+0x2f/0x90 ... Call Trace: [] pci_device_add+0xe3/0x130 [] pci_scan_single_device+0x8b/0xb0 [] pci_scan_slot+0x48/0x100 [] pci_scan_child_bus+0x24/0xc0 [] pci_acpi_scan_root+0x2c0/0x490 [] 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: Greg Kroah-Hartman --- arch/x86/pci/common.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -617,7 +617,9 @@ int pcibios_add_device(struct pci_dev *d 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 *d } } pa_data = data->next; + iounmap(data); } return 0; }