aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-15 11:29:12 -0500
committerThomas Gleixner <tglx@linutronix.de>2008-02-18 14:54:14 -0500
commit31eedd823c1bf3650c450346a0d0c39431034eb9 (patch)
treeaf65f4c77b88f5d907aa54ff1e67b1bdf1488d67
parentc31c7d4844ea4817692ae16bf70f9c96c05a50eb (diff)
x86: zap invalid and unused pmds in early boot
The early boot code maps KERNEL_TEXT_SIZE (currently 40MB) starting from __START_KERNEL_map. The kernel itself only needs _text to _end mapped in the high alias. On relocatible kernels the ASM setup code adjusts the compile time created high mappings to the relocation. This creates invalid pmd entries for negative offsets: 0xffffffff80000000 -> pmd entry: ffffffffff2001e3 It points outside of the physical address space and is marked present. This starts at the virtual address __START_KERNEL_map and goes up to the point where the first valid physical address (0x0) is mapped. Zap the mappings before _text and after _end right away in early boot. This removes also the invalid entries. Furthermore it simplifies the range check for high aliases. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/head64.c3
-rw-r--r--arch/x86/kernel/head_64.S7
-rw-r--r--arch/x86/mm/init_64.c27
-rw-r--r--include/asm-x86/pgtable_64.h1
4 files changed, 37 insertions, 1 deletions
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 24dbf56928d7..ad2440832de0 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -88,6 +88,9 @@ void __init x86_64_start_kernel(char * real_mode_data)
88 /* Make NULL pointers segfault */ 88 /* Make NULL pointers segfault */
89 zap_identity_mappings(); 89 zap_identity_mappings();
90 90
91 /* Cleanup the over mapped high alias */
92 cleanup_highmap();
93
91 for (i = 0; i < IDT_ENTRIES; i++) { 94 for (i = 0; i < IDT_ENTRIES; i++) {
92#ifdef CONFIG_EARLY_PRINTK 95#ifdef CONFIG_EARLY_PRINTK
93 set_intr_gate(i, &early_idt_handlers[i]); 96 set_intr_gate(i, &early_idt_handlers[i]);
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 09b38d539b09..53e5820d6054 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -107,8 +107,13 @@ startup_64:
107 movq %rdx, 0(%rbx, %rax, 8) 107 movq %rdx, 0(%rbx, %rax, 8)
108ident_complete: 108ident_complete:
109 109
110 /* Fixup the kernel text+data virtual addresses 110 /*
111 * Fixup the kernel text+data virtual addresses. Note that
112 * we might write invalid pmds, when the kernel is relocated
113 * cleanup_highmap() fixes this up along with the mappings
114 * beyond _end.
111 */ 115 */
116
112 leaq level2_kernel_pgt(%rip), %rdi 117 leaq level2_kernel_pgt(%rip), %rdi
113 leaq 4096(%rdi), %r8 118 leaq 4096(%rdi), %r8
114 /* See if it is a valid page table entry */ 119 /* See if it is a valid page table entry */
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index a4a9cccdd4f2..bb652f5a93fb 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -171,6 +171,33 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
171 __flush_tlb_one(vaddr); 171 __flush_tlb_one(vaddr);
172} 172}
173 173
174/*
175 * The head.S code sets up the kernel high mapping from:
176 * __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE
177 *
178 * phys_addr holds the negative offset to the kernel, which is added
179 * to the compile time generated pmds. This results in invalid pmds up
180 * to the point where we hit the physaddr 0 mapping.
181 *
182 * We limit the mappings to the region from _text to _end. _end is
183 * rounded up to the 2MB boundary. This catches the invalid pmds as
184 * well, as they are located before _text:
185 */
186void __init cleanup_highmap(void)
187{
188 unsigned long vaddr = __START_KERNEL_map;
189 unsigned long end = round_up((unsigned long)_end, PMD_SIZE) - 1;
190 pmd_t *pmd = level2_kernel_pgt;
191 pmd_t *last_pmd = pmd + PTRS_PER_PMD;
192
193 for (; pmd < last_pmd; pmd++, vaddr += PMD_SIZE) {
194 if (!pmd_present(*pmd))
195 continue;
196 if (vaddr < (unsigned long) _text || vaddr > end)
197 set_pmd(pmd, __pmd(0));
198 }
199}
200
174/* NOTE: this is meant to be run only at boot */ 201/* NOTE: this is meant to be run only at boot */
175void __init 202void __init
176__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) 203__set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index bd4740a60f29..7fd5e0e2361e 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -246,6 +246,7 @@ static inline int pud_large(pud_t pte)
246#define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) 246#define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val })
247 247
248extern int kern_addr_valid(unsigned long addr); 248extern int kern_addr_valid(unsigned long addr);
249extern void cleanup_highmap(void);
249 250
250#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ 251#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
251 remap_pfn_range(vma, vaddr, pfn, size, prot) 252 remap_pfn_range(vma, vaddr, pfn, size, prot)