Patchwork [3.8.y.z,extended,stable] Patch "x86/PCI: Map PCI setup data with ioremap() so it can be in highmem" has been added to staging queue

login
register
mail settings
Submitter Kamal Mostafa
Date June 7, 2013, 8:29 p.m.
Message ID <1370636966-2335-1-git-send-email-kamal@canonical.com>
Download mbox | patch
Permalink /patch/249847/
State New
Headers show

Comments

Kamal Mostafa - June 7, 2013, 8:29 p.m.
This is a note to let you know that I have just added a patch titled

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

to the linux-3.8.y-queue branch of the 3.8.y.z extended stable tree 
which can be found at:

 http://kernel.ubuntu.com/git?p=ubuntu/linux.git;a=shortlog;h=refs/heads/linux-3.8.y-queue

This patch is scheduled to be released in version 3.8.13.3.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.8.y.z tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

------

From 0e797044f189bf40d69c64c0cb3af8c522f5c643 Mon Sep 17 00:00:00 2001
From: Matt Fleming <matt.fleming@intel.com>
Date: Wed, 5 Jun 2013 15:15:41 +0100
Subject: 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: Kamal Mostafa <kamal@canonical.com>
---
 arch/x86/pci/common.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

--
1.8.1.2

Patch

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;
 }