aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2009-03-09 22:57:04 -0400
committerH. Peter Anvin <hpa@zytor.com>2009-03-10 21:13:25 -0400
commit5359454701ce51a4626b1ef6eb7b16ec35bd458d (patch)
tree44f8d60b3cb1d06ec215387eb7e35fdbb64e70c8
parentfef3a7a17418814733ebde0b40d8e32747677c8f (diff)
x86, kexec: x86_64: add identity map for pages at image->start
Impact: Fix corner case that cannot yet occur image->start may be outside of 0 ~ max_pfn, for example when jumping back to original kernel from kexeced kenrel. This patch add identity map for pages at image->start. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--arch/x86/kernel/machine_kexec_64.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index f8c796fffa0f..7cc5d3d01483 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -18,6 +18,41 @@
18#include <asm/tlbflush.h> 18#include <asm/tlbflush.h>
19#include <asm/mmu_context.h> 19#include <asm/mmu_context.h>
20 20
21static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
22 unsigned long addr)
23{
24 pud_t *pud;
25 pmd_t *pmd;
26 struct page *page;
27 int result = -ENOMEM;
28
29 addr &= PMD_MASK;
30 pgd += pgd_index(addr);
31 if (!pgd_present(*pgd)) {
32 page = kimage_alloc_control_pages(image, 0);
33 if (!page)
34 goto out;
35 pud = (pud_t *)page_address(page);
36 memset(pud, 0, PAGE_SIZE);
37 set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
38 }
39 pud = pud_offset(pgd, addr);
40 if (!pud_present(*pud)) {
41 page = kimage_alloc_control_pages(image, 0);
42 if (!page)
43 goto out;
44 pmd = (pmd_t *)page_address(page);
45 memset(pmd, 0, PAGE_SIZE);
46 set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
47 }
48 pmd = pmd_offset(pud, addr);
49 if (!pmd_present(*pmd))
50 set_pmd(pmd, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
51 result = 0;
52out:
53 return result;
54}
55
21static void init_level2_page(pmd_t *level2p, unsigned long addr) 56static void init_level2_page(pmd_t *level2p, unsigned long addr)
22{ 57{
23 unsigned long end_addr; 58 unsigned long end_addr;
@@ -155,6 +190,13 @@ static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
155 result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT); 190 result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
156 if (result) 191 if (result)
157 return result; 192 return result;
193 /*
194 * image->start may be outside 0 ~ max_pfn, for example when
195 * jump back to original kernel from kexeced kernel
196 */
197 result = init_one_level2_page(image, level4p, image->start);
198 if (result)
199 return result;
158 return init_transition_pgtable(image, level4p); 200 return init_transition_pgtable(image, level4p);
159} 201}
160 202