diff options
-rw-r--r-- | arch/x86/kernel/head64.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/head_64.S | 7 | ||||
-rw-r--r-- | arch/x86/mm/init_64.c | 27 | ||||
-rw-r--r-- | include/asm-x86/pgtable_64.h | 1 |
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) |
108 | ident_complete: | 108 | ident_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 | */ | ||
186 | void __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 */ |
175 | void __init | 202 | void __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 | ||
248 | extern int kern_addr_valid(unsigned long addr); | 248 | extern int kern_addr_valid(unsigned long addr); |
249 | extern 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) |