18312c1
Path: news.gmane.org!not-for-mail
18312c1
From: Matt Fleming <matt@console-pimps.org>
18312c1
Newsgroups: gmane.linux.kernel
18312c1
Subject: [PATCH v2] x86, efi: Calling __pa() with an ioremap'd address is invalid
18312c1
Date: Fri, 14 Oct 2011 12:36:45 +0100
18312c1
Lines: 160
18312c1
Approved: news@gmane.org
18312c1
Message-ID: <1318592205-11193-1-git-send-email-matt@console-pimps.org>
18312c1
NNTP-Posting-Host: lo.gmane.org
18312c1
X-Trace: dough.gmane.org 1318592224 30879 80.91.229.12 (14 Oct 2011 11:37:04 GMT)
18312c1
X-Complaints-To: usenet@dough.gmane.org
18312c1
NNTP-Posting-Date: Fri, 14 Oct 2011 11:37:04 +0000 (UTC)
18312c1
Cc: Thomas Gleixner <tglx@linutronix.de>, Ingo Molnar <mingo@elte.hu>,
18312c1
	"H. Peter Anvin" <hpa@zytor.com>, Zhang Rui <rui.zhang@intel.com>,
18312c1
	Huang Ying <huang.ying.caritas@gmail.com>,
18312c1
	linux-kernel@vger.kernel.org
18312c1
To: Matthew Garrett <mjg@redhat.com>
18312c1
Original-X-From: linux-kernel-owner@vger.kernel.org Fri Oct 14 13:36:59 2011
18312c1
Return-path: <linux-kernel-owner@vger.kernel.org>
18312c1
Envelope-to: glk-linux-kernel-3@lo.gmane.org
18312c1
Original-Received: from vger.kernel.org ([209.132.180.67])
18312c1
	by lo.gmane.org with esmtp (Exim 4.69)
18312c1
	(envelope-from <linux-kernel-owner@vger.kernel.org>)
18312c1
	id 1REg4Q-0001UQ-SA
18312c1
	for glk-linux-kernel-3@lo.gmane.org; Fri, 14 Oct 2011 13:36:59 +0200
18312c1
Original-Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
18312c1
	id S1755420Ab1JNLgv (ORCPT <rfc822;glk-linux-kernel-3@m.gmane.org>);
18312c1
	Fri, 14 Oct 2011 07:36:51 -0400
18312c1
Original-Received: from arkanian.console-pimps.org ([212.110.184.194]:46859 "EHLO
18312c1
	arkanian.console-pimps.org" rhost-flags-OK-OK-OK-OK)
18312c1
	by vger.kernel.org with ESMTP id S1751315Ab1JNLgu (ORCPT
18312c1
	<rfc822;linux-kernel@vger.kernel.org>);
18312c1
	Fri, 14 Oct 2011 07:36:50 -0400
18312c1
Original-Received: by arkanian.console-pimps.org (Postfix, from userid 1002)
18312c1
	id 443C1C0009; Fri, 14 Oct 2011 12:36:49 +0100 (BST)
18312c1
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on
18312c1
	arkanian.vm.bytemark.co.uk
18312c1
X-Spam-Level: 
18312c1
X-Spam-Status: No, score=-5.3 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00
18312c1
	autolearn=ham version=3.2.5
18312c1
Original-Received: from localhost (02ddb86b.bb.sky.com [2.221.184.107])
18312c1
	by arkanian.console-pimps.org (Postfix) with ESMTPSA id F0D40C0008;
18312c1
	Fri, 14 Oct 2011 12:36:47 +0100 (BST)
18312c1
X-Mailer: git-send-email 1.7.4.4
18312c1
Original-Sender: linux-kernel-owner@vger.kernel.org
18312c1
Precedence: bulk
18312c1
List-ID: <linux-kernel.vger.kernel.org>
18312c1
X-Mailing-List: linux-kernel@vger.kernel.org
18312c1
Xref: news.gmane.org gmane.linux.kernel:1203294
18312c1
Archived-At: <http://permalink.gmane.org/gmane.linux.kernel/1203294>
18312c1
18312c1
From: Matt Fleming <matt.fleming@intel.com>
18312c1
18312c1
If we encounter an efi_memory_desc_t without EFI_MEMORY_WB set in
18312c1
->attribute we currently call set_memory_uc(), which in turn calls
18312c1
__pa() on a potentially ioremap'd address. On CONFIG_X86_32 this is
18312c1
invalid, resulting in the following oops,
18312c1
18312c1
  BUG: unable to handle kernel paging request at f7f22280
18312c1
  IP: [<c10257b9>] reserve_ram_pages_type+0x89/0x210
18312c1
  *pdpt = 0000000001978001 *pde = 0000000001ffb067 *pte = 0000000000000000
18312c1
  Oops: 0000 [#1] PREEMPT SMP
18312c1
  Modules linked in:
18312c1
18312c1
  Pid: 0, comm: swapper Not tainted 3.0.0-acpi-efi-0805 #3
18312c1
   EIP: 0060:[<c10257b9>] EFLAGS: 00010202 CPU: 0
18312c1
   EIP is at reserve_ram_pages_type+0x89/0x210
18312c1
   EAX: 0070e280 EBX: 38714000 ECX: f7814000 EDX: 00000000
18312c1
   ESI: 00000000 EDI: 38715000 EBP: c189fef0 ESP: c189fea8
18312c1
   DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
18312c1
  Process swapper (pid: 0, ti=c189e000 task=c18bbe60 task.ti=c189e000)
18312c1
  Stack:
18312c1
   80000200 ff108000 00000000 c189ff00 00038714 00000000 00000000 c189fed0
18312c1
   c104f8ca 00038714 00000000 00038715 00000000 00000000 00038715 00000000
18312c1
   00000010 38715000 c189ff48 c1025aff 38715000 00000000 00000010 00000000
18312c1
  Call Trace:
18312c1
   [<c104f8ca>] ? page_is_ram+0x1a/0x40
18312c1
   [<c1025aff>] reserve_memtype+0xdf/0x2f0
18312c1
   [<c1024dc9>] set_memory_uc+0x49/0xa0
18312c1
   [<c19334d0>] efi_enter_virtual_mode+0x1c2/0x3aa
18312c1
   [<c19216d4>] start_kernel+0x291/0x2f2
18312c1
   [<c19211c7>] ? loglevel+0x1b/0x1b
18312c1
   [<c19210bf>] i386_start_kernel+0xbf/0xc8
18312c1
18312c1
So, if we're ioremap'ing an address range let's setup the mapping with
18312c1
the correct caching attribute instead of modifying it after the fact.
18312c1
18312c1
Also, take this opportunity to unify the 32/64-bit efi_ioremap()
18312c1
implementations because they can both be implemented with
18312c1
ioremap_{cache,nocache}. When asked about the original reason behind
18312c1
using init_memory_mapping() for the 64-bit version Huang Ying said,
18312c1
18312c1
  "The intention of init_memory_mapping() usage is to make EFI virtual
18312c1
  address unchanged after kexec.  But in fact, init_memory_mapping()
18312c1
  can not handle some memory range, so ioremap_xxx() is introduced as
18312c1
  a fix.  Now we decide to use ioremap_xxx() anyway and use some other
18312c1
  scheme for kexec support, so init_memory_mapping() here is
18312c1
  unnecessary.  IMHO, init_memory_mapping() is not as good as
18312c1
  ioremap_xxx() here."
18312c1
18312c1
And because efi_ioremap() now consists of 4 lines, let's just inline
18312c1
it directly into the one callsite in efi_enter_virtual_mode().
18312c1
18312c1
Cc: Thomas Gleixner <tglx@linutronix.de>
18312c1
Cc: Ingo Molnar <mingo@elte.hu>
18312c1
Cc: H. Peter Anvin <hpa@zytor.com>
18312c1
Cc: Matthew Garrett <mjg@redhat.com>
18312c1
Cc: Zhang Rui <rui.zhang@intel.com>
18312c1
Cc: Huang Ying <huang.ying.caritas@gmail.com>
18312c1
Cc: stable@kernel.org
18312c1
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
18312c1
---
18312c1
 arch/x86/include/asm/efi.h     |    5 -----
18312c1
 arch/x86/platform/efi/efi.c    |   24 ++++++++++++++----------
18312c1
 arch/x86/platform/efi/efi_64.c |   17 -----------------
18312c1
 3 files changed, 14 insertions(+), 32 deletions(-)
18312c1
18312c1
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
18312c1
index 7093e4a..b8d8bfc 100644
18312c1
--- a/arch/x86/include/asm/efi.h
18312c1
+++ b/arch/x86/include/asm/efi.h
18312c1
@@ -33,8 +33,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
18312c1
 #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6)	\
18312c1
 	efi_call_virt(f, a1, a2, a3, a4, a5, a6)
18312c1
 
18312c1
-#define efi_ioremap(addr, size, type)		ioremap_cache(addr, size)
18312c1
-
18312c1
 #else /* !CONFIG_X86_32 */
18312c1
 
18312c1
 extern u64 efi_call0(void *fp);
18312c1
@@ -84,9 +82,6 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
18312c1
 	efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
18312c1
 		  (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
18312c1
 
18312c1
-extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
18312c1
-				 u32 type);
18312c1
-
18312c1
 #endif /* CONFIG_X86_32 */
18312c1
 
18312c1
 extern int add_efi_memmap;
18312c1
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
18312c1
index 3ae4128..6ea011c 100644
18312c1
--- a/arch/x86/platform/efi/efi.c
18312c1
+++ b/arch/x86/platform/efi/efi.c
18312c1
@@ -670,10 +670,21 @@ void __init efi_enter_virtual_mode(void)
18312c1
 		end_pfn = PFN_UP(end);
18312c1
 		if (end_pfn <= max_low_pfn_mapped
18312c1
 		    || (end_pfn > (1UL << (32 - PAGE_SHIFT))
18312c1
-			&& end_pfn <= max_pfn_mapped))
18312c1
+			&& end_pfn <= max_pfn_mapped)) {
18312c1
 			va = __va(md->phys_addr);
18312c1
-		else
18312c1
-			va = efi_ioremap(md->phys_addr, size, md->type);
18312c1
+
18312c1
+			if (!(md->attribute & EFI_MEMORY_WB)) {
18312c1
+				addr = (u64) (unsigned long)va;
18312c1
+				npages = md->num_pages;
18312c1
+				memrange_efi_to_native(&addr, &npages);
18312c1
+				set_memory_uc(addr, npages);
18312c1
+			}
18312c1
+		} else {
18312c1
+			if (!(md->attribute & EFI_MEMORY_WB))
18312c1
+				va = ioremap_nocache(md->phys_addr, size);
18312c1
+			else
18312c1
+				va = ioremap_cache(md->phys_addr, size);
18312c1
+		}
18312c1
 
18312c1
 		md->virt_addr = (u64) (unsigned long) va;
18312c1
 
18312c1
@@ -683,13 +694,6 @@ void __init efi_enter_virtual_mode(void)
18312c1
 			continue;
18312c1
 		}
18312c1
 
18312c1
-		if (!(md->attribute & EFI_MEMORY_WB)) {
18312c1
-			addr = md->virt_addr;
18312c1
-			npages = md->num_pages;
18312c1
-			memrange_efi_to_native(&addr, &npages);
18312c1
-			set_memory_uc(addr, npages);
18312c1
-		}
18312c1
-
18312c1
 		systab = (u64) (unsigned long) efi_phys.systab;
18312c1
 		if (md->phys_addr <= systab && systab < end) {
18312c1
 			systab += md->virt_addr - md->phys_addr;
18312c1
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
18312c1
index ac3aa54..312250c 100644
18312c1
--- a/arch/x86/platform/efi/efi_64.c
18312c1
+++ b/arch/x86/platform/efi/efi_64.c
18312c1
@@ -80,20 +80,3 @@ void __init efi_call_phys_epilog(void)
18312c1
 	local_irq_restore(efi_flags);
18312c1
 	early_code_mapping_set_exec(0);
18312c1
 }
18312c1
-
18312c1
-void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
18312c1
-				 u32 type)
18312c1
-{
18312c1
-	unsigned long last_map_pfn;
18312c1
-
18312c1
-	if (type == EFI_MEMORY_MAPPED_IO)
18312c1
-		return ioremap(phys_addr, size);
18312c1
-
18312c1
-	last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
18312c1
-	if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
18312c1
-		unsigned long top = last_map_pfn << PAGE_SHIFT;
18312c1
-		efi_ioremap(top, size - (top - phys_addr), type);
18312c1
-	}
18312c1
-
18312c1
-	return (void __iomem *)__va(phys_addr);
18312c1
-}
18312c1
-- 
18312c1
1.7.4.4
18312c1