Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754049Ab2HMVre (ORCPT ); Mon, 13 Aug 2012 17:47:34 -0400 Received: from tx2ehsobe004.messaging.microsoft.com ([65.55.88.14]:33901 "EHLO tx2outboundpool.messaging.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753863Ab2HMVr1 (ORCPT ); Mon, 13 Aug 2012 17:47:27 -0400 X-Forefront-Antispam-Report: CIP:163.181.249.109;KIP:(null);UIP:(null);IPV:NLI;H:ausb3twp02.amd.com;RD:none;EFVD:NLI X-SpamScore: 0 X-BigFish: VPS0(zzzz1202hzz8275bhz2dh668h839hd24he5bhf0ah107ah) X-WSS-ID: 0M8PR6W-02-BJ3-02 X-M-MSG: From: Jacob Shin To: X86-ML CC: LKML , Yinghai Lu , "H. Peter Anvin" , Andreas Herrmann , Tejun Heo , Borislav Petkov , Jacob Shin Subject: [PATCH 1/5] x86: Only direct map addresses that are marked as E820_RAM Date: Mon, 13 Aug 2012 16:47:00 -0500 Message-ID: <1344894424-4434-2-git-send-email-jacob.shin@amd.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1344894424-4434-1-git-send-email-jacob.shin@amd.com> References: <1344894424-4434-1-git-send-email-jacob.shin@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-OriginatorOrg: amd.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5701 Lines: 195 Currently direct mappings are created for [ 0 to max_low_pfn< --- arch/x86/include/asm/page_types.h | 9 ++++ arch/x86/kernel/setup.c | 108 +++++++++++++++++++++++++++++++------ 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index e21fdd1..409047a 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -3,6 +3,7 @@ #include #include +#include /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 @@ -40,12 +41,20 @@ #endif /* CONFIG_X86_64 */ #ifndef __ASSEMBLY__ +#include extern int devmem_is_allowed(unsigned long pagenr); extern unsigned long max_low_pfn_mapped; extern unsigned long max_pfn_mapped; +extern struct range pfn_mapped[E820_X_MAX]; +extern int nr_pfn_mapped; + +extern void add_pfn_range_mapped(unsigned long start_pfn, unsigned long end_pfn); +extern bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn); +extern bool pfn_is_mapped(unsigned long pfn); + static inline phys_addr_t get_max_mapped(void) { return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f4b9b80..f71fa310 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -115,13 +115,46 @@ #include /* - * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. - * The direct mapping extends to max_pfn_mapped, so that we can directly access - * apertures, ACPI and other tables without having to play with fixmaps. + * max_low_pfn_mapped: highest direct mapped pfn under 4GB + * max_pfn_mapped: highest direct mapped pfn over 4GB + * + * The direct mapping only covers E820_RAM regions, so the ranges and gaps are + * represented by pfn_mapped */ unsigned long max_low_pfn_mapped; unsigned long max_pfn_mapped; +struct range pfn_mapped[E820_X_MAX]; +int nr_pfn_mapped; + +void add_pfn_range_mapped(unsigned long start_pfn, unsigned long end_pfn) +{ + nr_pfn_mapped = add_range_with_merge(pfn_mapped, E820_X_MAX, + nr_pfn_mapped, start_pfn, end_pfn); + + max_pfn_mapped = max(max_pfn_mapped, end_pfn); + + if (end_pfn <= (1UL << (32 - PAGE_SHIFT))) + max_low_pfn_mapped = max(max_low_pfn_mapped, end_pfn); +} + +bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn) +{ + int i; + + for (i = 0; i < nr_pfn_mapped; i++) + if ((start_pfn >= pfn_mapped[i].start) && + (end_pfn <= pfn_mapped[i].end)) + return true; + + return false; +} + +bool pfn_is_mapped(unsigned long pfn) +{ + return pfn_range_is_mapped(pfn, pfn + 1); +} + #ifdef CONFIG_DMI RESERVE_BRK(dmi_alloc, 65536); #endif @@ -296,6 +329,61 @@ static void __init cleanup_highmap(void) } #endif +/* + * Iterate through E820 memory map and create direct mappings for only E820_RAM + * regions. We cannot simply create direct mappings for all pfns from + * [0 to max_low_pfn) and [4GB to max_pfn) because of possible memory holes in + * high addresses that cannot be marked as UC by fixed/variable range MTRRs. + */ +static void __init init_memory(void) +{ + int i; + unsigned long pfn; + + init_gbpages(); + + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + u64 start = ei->addr; + u64 end = ei->addr + ei->size; + + /* we only map E820_RAM */ + if (ei->type != E820_RAM) + continue; + + /* except we need to ignore gaps under 1MB */ + if (end <= ISA_END_ADDRESS) + continue; + + /* expand the first entry that spans 1MB to start at 0 */ + if (start <= ISA_END_ADDRESS) + start = 0; +#ifdef CONFIG_X86_32 + /* on 32 bit, we only map up to max_low_pfn */ + if ((start >> PAGE_SHIFT) >= max_low_pfn) + continue; + + if ((end >> PAGE_SHIFT) > max_low_pfn) + end = max_low_pfn << PAGE_SHIFT; +#endif + pfn = init_memory_mapping(start, end); + add_pfn_range_mapped(start >> PAGE_SHIFT, pfn); + } + + /* map 0 to 1MB if we haven't already */ + if (!pfn_range_is_mapped(0, ISA_END_ADDRESS << PAGE_SHIFT)) { + pfn = init_memory_mapping(0, ISA_END_ADDRESS); + add_pfn_range_mapped(0, pfn); + } + +#ifdef CONFIG_X86_64 + if (max_pfn > max_low_pfn) { + /* can we preseve max_low_pfn ?*/ + max_low_pfn = max_pfn; + } +#endif +} + static void __init reserve_brk(void) { if (_brk_end > _brk_start) @@ -911,20 +999,8 @@ void __init setup_arch(char **cmdline_p) setup_real_mode(); - init_gbpages(); - - /* max_pfn_mapped is updated here */ - max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn< max_low_pfn) { - max_pfn_mapped = init_memory_mapping(1UL<<32, - max_pfn<