aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/machine_kexec_64.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2013-01-24 15:20:03 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2013-01-29 18:26:26 -0500
commit084d1283986a530828b8898f206adf44d5d3146d (patch)
treecc05f142d48e05d2e2bcf260ec61d5d351dc77af /arch/x86/kernel/machine_kexec_64.c
parent577af55d802d9fe114287e750504e09e7c677c9c (diff)
x86, kexec: Set ident mapping for kernel that is above max_pfn
When first kernel is booted with memmap= or mem= to limit max_pfn. kexec can load second kernel above that max_pfn. We need to set ident mapping for whole image in this case instead of just for first 2M. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Link: http://lkml.kernel.org/r/1359058816-7615-23-git-send-email-yinghai@kernel.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel/machine_kexec_64.c')
-rw-r--r--arch/x86/kernel/machine_kexec_64.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index b3ea9db39db6..be14ee120c43 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -56,6 +56,25 @@ out:
56 return result; 56 return result;
57} 57}
58 58
59static int ident_mapping_init(struct kimage *image, pgd_t *level4p,
60 unsigned long mstart, unsigned long mend)
61{
62 int result;
63
64 mstart = round_down(mstart, PMD_SIZE);
65 mend = round_up(mend - 1, PMD_SIZE);
66
67 while (mstart < mend) {
68 result = init_one_level2_page(image, level4p, mstart);
69 if (result)
70 return result;
71
72 mstart += PMD_SIZE;
73 }
74
75 return 0;
76}
77
59static void init_level2_page(pmd_t *level2p, unsigned long addr) 78static void init_level2_page(pmd_t *level2p, unsigned long addr)
60{ 79{
61 unsigned long end_addr; 80 unsigned long end_addr;
@@ -184,22 +203,34 @@ err:
184 return result; 203 return result;
185} 204}
186 205
187
188static int init_pgtable(struct kimage *image, unsigned long start_pgtable) 206static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
189{ 207{
208 unsigned long mstart, mend;
190 pgd_t *level4p; 209 pgd_t *level4p;
191 int result; 210 int result;
211 int i;
212
192 level4p = (pgd_t *)__va(start_pgtable); 213 level4p = (pgd_t *)__va(start_pgtable);
193 result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT); 214 result = init_level4_page(image, level4p, 0, max_pfn << PAGE_SHIFT);
194 if (result) 215 if (result)
195 return result; 216 return result;
217
196 /* 218 /*
197 * image->start may be outside 0 ~ max_pfn, for example when 219 * segments's mem ranges could be outside 0 ~ max_pfn,
198 * jump back to original kernel from kexeced kernel 220 * for example when jump back to original kernel from kexeced kernel.
221 * or first kernel is booted with user mem map, and second kernel
222 * could be loaded out of that range.
199 */ 223 */
200 result = init_one_level2_page(image, level4p, image->start); 224 for (i = 0; i < image->nr_segments; i++) {
201 if (result) 225 mstart = image->segment[i].mem;
202 return result; 226 mend = mstart + image->segment[i].memsz;
227
228 result = ident_mapping_init(image, level4p, mstart, mend);
229
230 if (result)
231 return result;
232 }
233
203 return init_transition_pgtable(image, level4p); 234 return init_transition_pgtable(image, level4p);
204} 235}
205 236