public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
@ 2011-10-11 12:54 Matt Fleming
  2011-10-11 13:03 ` Matthew Garrett
  0 siblings, 1 reply; 6+ messages in thread
From: Matt Fleming @ 2011-10-11 12:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: x86, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Matthew Garrett, Zhang Rui, Huang Ying

From: Matt Fleming <matt.fleming@intel.com>

If we encounter an efi_memory_desc_t without EFI_MEMORY_WB set in
->attribute we currently call set_memory_uc(), which in turn calls
__pa() on a potentially ioremap'd address. On CONFIG_X86_32 this is
invalid, resulting in the following oops,

  BUG: unable to handle kernel paging request at f7f22280
  IP: [<c10257b9>] reserve_ram_pages_type+0x89/0x210
  *pdpt = 0000000001978001 *pde = 0000000001ffb067 *pte = 0000000000000000
  Oops: 0000 [#1] PREEMPT SMP
  Modules linked in:

  Pid: 0, comm: swapper Not tainted 3.0.0-acpi-efi-0805 #3
   EIP: 0060:[<c10257b9>] EFLAGS: 00010202 CPU: 0
   EIP is at reserve_ram_pages_type+0x89/0x210
   EAX: 0070e280 EBX: 38714000 ECX: f7814000 EDX: 00000000
   ESI: 00000000 EDI: 38715000 EBP: c189fef0 ESP: c189fea8
   DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
  Process swapper (pid: 0, ti=c189e000 task=c18bbe60 task.ti=c189e000)
  Stack:
   80000200 ff108000 00000000 c189ff00 00038714 00000000 00000000 c189fed0
   c104f8ca 00038714 00000000 00038715 00000000 00000000 00038715 00000000
   00000010 38715000 c189ff48 c1025aff 38715000 00000000 00000010 00000000
  Call Trace:
   [<c104f8ca>] ? page_is_ram+0x1a/0x40
   [<c1025aff>] reserve_memtype+0xdf/0x2f0
   [<c1024dc9>] set_memory_uc+0x49/0xa0
   [<c19334d0>] efi_enter_virtual_mode+0x1c2/0x3aa
   [<c19216d4>] start_kernel+0x291/0x2f2
   [<c19211c7>] ? loglevel+0x1b/0x1b
   [<c19210bf>] i386_start_kernel+0xbf/0xc8

Let efi_ioremap() handle marking regions as uncached, whether that is
by calling ioremap_nocache() or calling set_memory_uc() on a
non-ioremap'd address.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <ming@elte.hu>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Matthew Garrett <mjg@redhat.com>
Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Huang Ying <huang.ying.caritas@gmail.com>
Cc: stable@kernel.org
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
 arch/x86/include/asm/efi.h     |   11 +++++++++--
 arch/x86/platform/efi/efi.c    |   21 +++++++++++----------
 arch/x86/platform/efi/efi_64.c |   12 ++++++++++--
 3 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 7093e4a..d0ccbc4 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -33,7 +33,14 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6)	\
 	efi_call_virt(f, a1, a2, a3, a4, a5, a6)
 
-#define efi_ioremap(addr, size, type)		ioremap_cache(addr, size)
+static inline void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
+					u32 type, u64 attr)
+{
+	if (type == EFI_MEMORY_MAPPED_IO || !(attr & EFI_MEMORY_WB))
+		return ioremap_nocache(addr, size);
+	else
+		return ioremap_cache(addr, size);
+}
 
 #else /* !CONFIG_X86_32 */
 
@@ -85,7 +92,7 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
 		  (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
 
 extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
-				 u32 type);
+				 u32 type, u64 attr);
 
 #endif /* CONFIG_X86_32 */
 
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 3ae4128..87f2295 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -670,10 +670,18 @@ void __init efi_enter_virtual_mode(void)
 		end_pfn = PFN_UP(end);
 		if (end_pfn <= max_low_pfn_mapped
 		    || (end_pfn > (1UL << (32 - PAGE_SHIFT))
-			&& end_pfn <= max_pfn_mapped))
+			&& end_pfn <= max_pfn_mapped)) {
 			va = __va(md->phys_addr);
-		else
-			va = efi_ioremap(md->phys_addr, size, md->type);
+
+			if (!(md->attribute & EFI_MEMORY_WB)) {
+				addr = (u64) (unsigned long)va;
+				npages = md->num_pages;
+				memrange_efi_to_native(&addr, &npages);
+				set_memory_uc(addr, npages);
+			}
+		} else
+			va = efi_ioremap(md->phys_addr, size,
+					 md->type, md->attribute);
 
 		md->virt_addr = (u64) (unsigned long) va;
 
@@ -683,13 +691,6 @@ void __init efi_enter_virtual_mode(void)
 			continue;
 		}
 
-		if (!(md->attribute & EFI_MEMORY_WB)) {
-			addr = md->virt_addr;
-			npages = md->num_pages;
-			memrange_efi_to_native(&addr, &npages);
-			set_memory_uc(addr, npages);
-		}
-
 		systab = (u64) (unsigned long) efi_phys.systab;
 		if (md->phys_addr <= systab && systab < end) {
 			systab += md->virt_addr - md->phys_addr;
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index ac3aa54..6d6e877 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -82,9 +82,10 @@ void __init efi_call_phys_epilog(void)
 }
 
 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
-				 u32 type)
+				 u32 type, u64 attr)
 {
 	unsigned long last_map_pfn;
+	u64 addr, npages;
 
 	if (type == EFI_MEMORY_MAPPED_IO)
 		return ioremap(phys_addr, size);
@@ -92,7 +93,14 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
 	last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
 	if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
 		unsigned long top = last_map_pfn << PAGE_SHIFT;
-		efi_ioremap(top, size - (top - phys_addr), type);
+		efi_ioremap(top, size - (top - phys_addr), type, attr);
+	}
+
+	if (!(attr & EFI_MEMORY_WB)) {
+		addr = (u64)(unsigned long)__va(phys_addr);
+		npages = size >> EFI_PAGE_SHIFT;
+		memrange_efi_to_native(&addr, &npages);
+		set_memory_uc(addr, npages);
 	}
 
 	return (void __iomem *)__va(phys_addr);
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
  2011-10-11 12:54 [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid Matt Fleming
@ 2011-10-11 13:03 ` Matthew Garrett
  2011-10-11 13:10   ` Matt Fleming
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Garrett @ 2011-10-11 13:03 UTC (permalink / raw)
  To: Matt Fleming
  Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Zhang Rui, Huang Ying

Is there any chance of unifying the 32 and 64-bit code here as well?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
  2011-10-11 13:03 ` Matthew Garrett
@ 2011-10-11 13:10   ` Matt Fleming
  2011-10-11 15:45     ` hpanvin@gmail.com
  0 siblings, 1 reply; 6+ messages in thread
From: Matt Fleming @ 2011-10-11 13:10 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Zhang Rui, Huang Ying

On Tue, 2011-10-11 at 14:03 +0100, Matthew Garrett wrote:
> Is there any chance of unifying the 32 and 64-bit code here as well?

I was under the impression that this wasn't possible for the cached case
because the 32-bit code path uses ioremap_cache() whereas 64-bit uses
init_memory_mapping() and __va().

Unless I'm missing something?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
  2011-10-11 13:10   ` Matt Fleming
@ 2011-10-11 15:45     ` hpanvin@gmail.com
  2011-10-11 15:58       ` Matt Fleming
  0 siblings, 1 reply; 6+ messages in thread
From: hpanvin@gmail.com @ 2011-10-11 15:45 UTC (permalink / raw)
  To: Matt Fleming, Matthew Garrett
  Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Zhang Rui,
	Huang Ying

I think ioremap_cache() should work for either.

Matt Fleming <matt@console-pimps.org> wrote:

>On Tue, 2011-10-11 at 14:03 +0100, Matthew Garrett wrote:
>> Is there any chance of unifying the 32 and 64-bit code here as well?
>
>I was under the impression that this wasn't possible for the cached
>case
>because the 32-bit code path uses ioremap_cache() whereas 64-bit uses
>init_memory_mapping() and __va().
>
>Unless I'm missing something?

-- 
Sent from my Android phone with K-9 Mail. Please excuse my brevity.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
  2011-10-11 15:45     ` hpanvin@gmail.com
@ 2011-10-11 15:58       ` Matt Fleming
  2011-10-11 16:23         ` Matthew Garrett
  0 siblings, 1 reply; 6+ messages in thread
From: Matt Fleming @ 2011-10-11 15:58 UTC (permalink / raw)
  To: hpanvin@gmail.com
  Cc: Matthew Garrett, linux-kernel, x86, Thomas Gleixner, Ingo Molnar,
	Zhang Rui, Huang Ying

On Tue, 2011-10-11 at 08:45 -0700, hpanvin@gmail.com wrote:
> I think ioremap_cache() should work for either.

Sorry yeah, it will work but I don't think it's desirable (that's what I
meant, though I realise it's not what I wrote).

The reason being: aren't you doing an extra step of indirection because
you have to jump through the vmalloc space?

With 32-bit this is obviously necessary because of the lack of space for
the direct kernel map, but on 64-bit we can just extend the kernel map
and do quick conversions between physical and virtual space with __va()
and __pa().

Maybe the extra indirection isn't that bad and no one will care? If so,
then sure, a unified version sounds like a plan. I was just hesitant of
changing the existing 64-bit implementation for fear of receiving
replies like "you've now made the 64-bit path slower".

-- 
Matt Fleming, Intel Open Source Technology Center


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid
  2011-10-11 15:58       ` Matt Fleming
@ 2011-10-11 16:23         ` Matthew Garrett
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Garrett @ 2011-10-11 16:23 UTC (permalink / raw)
  To: Matt Fleming
  Cc: hpanvin@gmail.com, linux-kernel, x86, Thomas Gleixner,
	Ingo Molnar, Zhang Rui, Huang Ying

On Tue, Oct 11, 2011 at 04:58:09PM +0100, Matt Fleming wrote:

> Maybe the extra indirection isn't that bad and no one will care? If so,
> then sure, a unified version sounds like a plan. I was just hesitant of
> changing the existing 64-bit implementation for fear of receiving
> replies like "you've now made the 64-bit path slower".

If we have UEFI calls on the fast path then I think we're already 
losing. I'd favour simplicity over performance here, personally.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-10-11 16:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-11 12:54 [PATCH] x86, efi: Calling __pa() with an ioremap'd address is invalid Matt Fleming
2011-10-11 13:03 ` Matthew Garrett
2011-10-11 13:10   ` Matt Fleming
2011-10-11 15:45     ` hpanvin@gmail.com
2011-10-11 15:58       ` Matt Fleming
2011-10-11 16:23         ` Matthew Garrett

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox