From: Suresh Siddha <suresh.b.siddha@intel.com>
To: mingo@elte.hu, hpa@zytor.com, tglx@linutronix.de, arjan@linux.intel.com
Cc: linux-kernel@vger.kernel.org, Suresh Siddha <suresh.b.siddha@intel.com>
Subject: [patch 3/7] x86, cpa: make the kernel physical mapping initialization a two pass sequence
Date: Thu, 11 Sep 2008 13:30:51 -0700 [thread overview]
Message-ID: <20080911204150.717626000@linux-os.sc.intel.com> (raw)
In-Reply-To: 20080911203048.929515000@linux-os.sc.intel.com
[-- Attachment #1: fix_large_small_page_identity_mappings.patch --]
[-- Type: text/plain, Size: 8944 bytes --]
In the first pass, kernel physical mapping will be setup using large or
small pages but uses the same PTE attributes as that of the early
PTE attributes setup by early boot code in head_[32|64].S
After flushing TLB's, we go through the second pass, which setups the
direct mapped PTE's with the appropriate attributes (like NX, GLOBAL etc)
which are runtime detectable.
This two pass mechanism conforms to the TLB app note which says:
"Software should not write to a paging-structure entry in a way that would
change, for any linear address, both the page size and either the page frame
or attributes."
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
---
Index: tip/arch/x86/mm/init_32.c
===================================================================
--- tip.orig/arch/x86/mm/init_32.c 2008-09-11 12:59:35.000000000 -0700
+++ tip/arch/x86/mm/init_32.c 2008-09-11 13:02:34.000000000 -0700
@@ -196,11 +196,30 @@
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
- unsigned pages_2m = 0, pages_4k = 0;
+ unsigned pages_2m, pages_4k;
+ int mapping_iter;
+
+ /*
+ * First iteration will setup identity mapping using large/small pages
+ * based on use_pse, with other attributes same as set by
+ * the early code in head_32.S
+ *
+ * Second iteration will setup the appropriate attributes (NX, GLOBAL..)
+ * as desired for the kernel identity mapping.
+ *
+ * This two pass mechanism conforms to the TLB app note which says:
+ *
+ * "Software should not write to a paging-structure entry in a way
+ * that would change, for any linear address, both the page size
+ * and either the page frame or attributes."
+ */
+ mapping_iter = 1;
if (!cpu_has_pse)
use_pse = 0;
+repeat:
+ pages_2m = pages_4k = 0;
pfn = start_pfn;
pgd_idx = pgd_index((pfn<<PAGE_SHIFT) + PAGE_OFFSET);
pgd = pgd_base + pgd_idx;
@@ -226,6 +245,13 @@
if (use_pse) {
unsigned int addr2;
pgprot_t prot = PAGE_KERNEL_LARGE;
+ /*
+ * first pass will use the same initial
+ * identity mapping attribute + _PAGE_PSE.
+ */
+ pgprot_t init_prot =
+ __pgprot(PTE_IDENT_ATTR |
+ _PAGE_PSE);
addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE +
PAGE_OFFSET + PAGE_SIZE-1;
@@ -235,7 +261,10 @@
prot = PAGE_KERNEL_LARGE_EXEC;
pages_2m++;
- set_pmd(pmd, pfn_pmd(pfn, prot));
+ if (mapping_iter == 1)
+ set_pmd(pmd, pfn_pmd(pfn, init_prot));
+ else
+ set_pmd(pmd, pfn_pmd(pfn, prot));
pfn += PTRS_PER_PTE;
continue;
@@ -247,17 +276,43 @@
for (; pte_ofs < PTRS_PER_PTE && pfn < end_pfn;
pte++, pfn++, pte_ofs++, addr += PAGE_SIZE) {
pgprot_t prot = PAGE_KERNEL;
+ /*
+ * first pass will use the same initial
+ * identity mapping attribute.
+ */
+ pgprot_t init_prot = __pgprot(PTE_IDENT_ATTR);
if (is_kernel_text(addr))
prot = PAGE_KERNEL_EXEC;
pages_4k++;
- set_pte(pte, pfn_pte(pfn, prot));
+ if (mapping_iter == 1)
+ set_pte(pte, pfn_pte(pfn, init_prot));
+ else
+ set_pte(pte, pfn_pte(pfn, prot));
}
}
}
- update_page_count(PG_LEVEL_2M, pages_2m);
- update_page_count(PG_LEVEL_4K, pages_4k);
+ if (mapping_iter == 1) {
+ /*
+ * update direct mapping page count only in the first
+ * iteration.
+ */
+ update_page_count(PG_LEVEL_2M, pages_2m);
+ update_page_count(PG_LEVEL_4K, pages_4k);
+
+ /*
+ * local global flush tlb, which will flush the previous
+ * mappings present in both small and large page TLB's.
+ */
+ __flush_tlb_all();
+
+ /*
+ * Second iteration will set the actual desired PTE attributes.
+ */
+ mapping_iter = 2;
+ goto repeat;
+ }
}
/*
Index: tip/arch/x86/mm/init_64.c
===================================================================
--- tip.orig/arch/x86/mm/init_64.c 2008-09-11 12:59:35.000000000 -0700
+++ tip/arch/x86/mm/init_64.c 2008-09-11 13:00:04.000000000 -0700
@@ -326,6 +326,8 @@
early_iounmap(adr, PAGE_SIZE);
}
+static int physical_mapping_iter;
+
static unsigned long __meminit
phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end)
{
@@ -346,16 +348,19 @@
}
if (pte_val(*pte))
- continue;
+ goto repeat_set_pte;
if (0)
printk(" pte=%p addr=%lx pte=%016lx\n",
pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte);
+ pages++;
+repeat_set_pte:
set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL));
last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
- pages++;
}
- update_page_count(PG_LEVEL_4K, pages);
+
+ if (physical_mapping_iter == 1)
+ update_page_count(PG_LEVEL_4K, pages);
return last_map_addr;
}
@@ -374,7 +379,6 @@
{
unsigned long pages = 0;
unsigned long last_map_addr = end;
- unsigned long start = address;
int i = pmd_index(address);
@@ -397,15 +401,14 @@
last_map_addr = phys_pte_update(pmd, address,
end);
spin_unlock(&init_mm.page_table_lock);
+ continue;
}
- /* Count entries we're using from level2_ident_pgt */
- if (start == 0)
- pages++;
- continue;
+ goto repeat_set_pte;
}
if (page_size_mask & (1<<PG_LEVEL_2M)) {
pages++;
+repeat_set_pte:
spin_lock(&init_mm.page_table_lock);
set_pte((pte_t *)pmd,
pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
@@ -422,7 +425,8 @@
pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
spin_unlock(&init_mm.page_table_lock);
}
- update_page_count(PG_LEVEL_2M, pages);
+ if (physical_mapping_iter == 1)
+ update_page_count(PG_LEVEL_2M, pages);
return last_map_addr;
}
@@ -461,14 +465,18 @@
}
if (pud_val(*pud)) {
- if (!pud_large(*pud))
+ if (!pud_large(*pud)) {
last_map_addr = phys_pmd_update(pud, addr, end,
page_size_mask);
- continue;
+ continue;
+ }
+
+ goto repeat_set_pte;
}
if (page_size_mask & (1<<PG_LEVEL_1G)) {
pages++;
+repeat_set_pte:
spin_lock(&init_mm.page_table_lock);
set_pte((pte_t *)pud,
pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
@@ -486,7 +494,9 @@
spin_unlock(&init_mm.page_table_lock);
}
__flush_tlb_all();
- update_page_count(PG_LEVEL_1G, pages);
+
+ if (physical_mapping_iter == 1)
+ update_page_count(PG_LEVEL_1G, pages);
return last_map_addr;
}
@@ -550,15 +560,54 @@
direct_gbpages = 0;
}
+static int is_kernel(unsigned long pfn)
+{
+ unsigned long pg_addresss = pfn << PAGE_SHIFT;
+
+ if (pg_addresss >= (unsigned long) __pa(_text) &&
+ pg_addresss <= (unsigned long) __pa(_end))
+ return 1;
+
+ return 0;
+}
+
static unsigned long __init kernel_physical_mapping_init(unsigned long start,
unsigned long end,
unsigned long page_size_mask)
{
- unsigned long next, last_map_addr = end;
+ unsigned long next, last_map_addr;
+ u64 cached_supported_pte_mask = __supported_pte_mask;
+ unsigned long cache_start = start;
+ unsigned long cache_end = end;
+
+ /*
+ * First iteration will setup identity mapping using large/small pages
+ * based on page_size_mask, with other attributes same as set by
+ * the early code in head_64.S
+ *
+ * Second iteration will setup the appropriate attributes
+ * as desired for the kernel identity mapping.
+ *
+ * This two pass mechanism conforms to the TLB app note which says:
+ *
+ * "Software should not write to a paging-structure entry in a way
+ * that would change, for any linear address, both the page size
+ * and either the page frame or attributes."
+ *
+ * For now, only difference between very early PTE attributes used in
+ * head_64.S and here is _PAGE_NX.
+ */
+ BUILD_BUG_ON((__PAGE_KERNEL_LARGE & ~__PAGE_KERNEL_IDENT_LARGE_EXEC)
+ != _PAGE_NX);
+ __supported_pte_mask &= ~(_PAGE_NX);
+ physical_mapping_iter = 1;
- start = (unsigned long)__va(start);
- end = (unsigned long)__va(end);
+repeat:
+ last_map_addr = end;
+
+ start = (unsigned long)__va(cache_start);
+ end = (unsigned long)__va(cache_end);
for (; start < end; start = next) {
pgd_t *pgd = pgd_offset_k(start);
@@ -570,11 +619,21 @@
next = end;
if (pgd_val(*pgd)) {
+ /*
+ * Static identity mappings will be overwritten
+ * with run-time mappings. For example, this allows
+ * the static 0-1GB identity mapping to be mapped
+ * non-executable with this.
+ */
+ if (is_kernel(pte_pfn(*((pte_t *) pgd))))
+ goto realloc;
+
last_map_addr = phys_pud_update(pgd, __pa(start),
__pa(end), page_size_mask);
continue;
}
+realloc:
pud = alloc_low_page(&pud_phys);
last_map_addr = phys_pud_init(pud, __pa(start), __pa(next),
page_size_mask);
@@ -584,6 +643,16 @@
pgd_populate(&init_mm, pgd, __va(pud_phys));
spin_unlock(&init_mm.page_table_lock);
}
+ __flush_tlb_all();
+
+ if (physical_mapping_iter == 1) {
+ physical_mapping_iter = 2;
+ /*
+ * Second iteration will set the actual desired PTE attributes.
+ */
+ __supported_pte_mask = cached_supported_pte_mask;
+ goto repeat;
+ }
return last_map_addr;
}
--
next prev parent reply other threads:[~2008-09-11 21:35 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-11 20:30 [patch 0/7] x86, cpa: cpa related changes to be inline with TLB Application note Suresh Siddha
2008-09-11 20:30 ` [patch 1/7] x86, cpa: rename PTE attribute macros for kernel direct mapping in early boot Suresh Siddha
2008-09-11 20:30 ` [patch 2/7] x86, cpa: remove USER permission from the very early identity mapping attribute Suresh Siddha
2008-09-11 20:30 ` Suresh Siddha [this message]
2008-09-11 20:30 ` [patch 4/7] x86, cpa: dont use large pages for kernel identity mapping with DEBUG_PAGEALLOC Suresh Siddha
2008-09-11 20:30 ` [patch 5/7] x86, cpa: fix taking the pgd_lock with interrupts off Suresh Siddha
2008-09-11 20:30 ` [patch 6/7] x86, cpa: remove cpa pool code Suresh Siddha
2008-09-11 20:30 ` [patch 7/7] x86, cpa: global flush tlb after splitting large page and before doing cpa Suresh Siddha
2008-09-13 17:10 ` Jeremy Fitzhardinge
2008-09-14 15:29 ` [patch 0/7] x86, cpa: cpa related changes to be inline with TLB Application note Ingo Molnar
2008-09-14 16:59 ` Ingo Molnar
2008-09-16 5:44 ` Suresh Siddha
2008-09-14 15:40 ` Arjan van de Ven
2008-09-14 15:52 ` Ingo Molnar
-- strict thread matches above, loose matches on Subject: below --
2008-09-23 21:00 [patch 0/7] x86, cpa: cpa related changes to be inline with TLB Application note - v2 Suresh Siddha
2008-09-23 21:00 ` [patch 3/7] x86, cpa: make the kernel physical mapping initialization a two pass sequence Suresh Siddha
2008-10-06 20:48 ` Jeremy Fitzhardinge
2008-10-06 23:09 ` Jeremy Fitzhardinge
2008-10-07 1:58 ` Suresh Siddha
2008-10-07 15:28 ` Jeremy Fitzhardinge
2008-10-07 20:58 ` Suresh Siddha
2008-10-07 21:33 ` Jeremy Fitzhardinge
2008-10-08 19:46 ` Jeremy Fitzhardinge
2008-10-08 21:08 ` Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080911204150.717626000@linux-os.sc.intel.com \
--to=suresh.b.siddha@intel.com \
--cc=arjan@linux.intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.