aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2007-10-18 06:04:54 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:20 -0400
commitefa4d2fb047b25a6be67fe92178a2a78da6b3f6a (patch)
tree82f2e7bc66d3867fcd4f66c424403d35b9d49812 /arch/x86/kernel
parentc30bb68c26ad7e9277f2d1dfed8347f329e1cf27 (diff)
Hibernation: Use temporary page tables for kernel text mapping on x86_64
Use temporary page tables for the kernel text mapping during hibernation restore on x86_64. Without the patch, the original boot kernel's page tables that represent the kernel text mapping are used while the core of the image kernel is being restored. However, in principle, if the boot kernel is not identical to the image kernel, the location of these page tables in the image kernel need not be the same, so we should create a safe copy of the kernel text mapping prior to restoring the core of the image kernel. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/suspend_64.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c
index da10eef4c3ef..f8fafe527ff1 100644
--- a/arch/x86/kernel/suspend_64.c
+++ b/arch/x86/kernel/suspend_64.c
@@ -197,25 +197,42 @@ static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long en
197 return 0; 197 return 0;
198} 198}
199 199
200static int res_kernel_text_pud_init(pud_t *pud, unsigned long start)
201{
202 pmd_t *pmd;
203 unsigned long paddr;
204
205 pmd = (pmd_t *)get_safe_page(GFP_ATOMIC);
206 if (!pmd)
207 return -ENOMEM;
208 set_pud(pud + pud_index(start), __pud(__pa(pmd) | _KERNPG_TABLE));
209 for (paddr = 0; paddr < KERNEL_TEXT_SIZE; pmd++, paddr += PMD_SIZE) {
210 unsigned long pe;
211
212 pe = __PAGE_KERNEL_LARGE_EXEC | _PAGE_GLOBAL | paddr;
213 pe &= __supported_pte_mask;
214 set_pmd(pmd, __pmd(pe));
215 }
216
217 return 0;
218}
219
200static int set_up_temporary_mappings(void) 220static int set_up_temporary_mappings(void)
201{ 221{
202 unsigned long start, end, next; 222 unsigned long start, end, next;
223 pud_t *pud;
203 int error; 224 int error;
204 225
205 temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC); 226 temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC);
206 if (!temp_level4_pgt) 227 if (!temp_level4_pgt)
207 return -ENOMEM; 228 return -ENOMEM;
208 229
209 /* It is safe to reuse the original kernel mapping */
210 set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map),
211 init_level4_pgt[pgd_index(__START_KERNEL_map)]);
212
213 /* Set up the direct mapping from scratch */ 230 /* Set up the direct mapping from scratch */
214 start = (unsigned long)pfn_to_kaddr(0); 231 start = (unsigned long)pfn_to_kaddr(0);
215 end = (unsigned long)pfn_to_kaddr(end_pfn); 232 end = (unsigned long)pfn_to_kaddr(end_pfn);
216 233
217 for (; start < end; start = next) { 234 for (; start < end; start = next) {
218 pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC); 235 pud = (pud_t *)get_safe_page(GFP_ATOMIC);
219 if (!pud) 236 if (!pud)
220 return -ENOMEM; 237 return -ENOMEM;
221 next = start + PGDIR_SIZE; 238 next = start + PGDIR_SIZE;
@@ -226,7 +243,17 @@ static int set_up_temporary_mappings(void)
226 set_pgd(temp_level4_pgt + pgd_index(start), 243 set_pgd(temp_level4_pgt + pgd_index(start),
227 mk_kernel_pgd(__pa(pud))); 244 mk_kernel_pgd(__pa(pud)));
228 } 245 }
229 return 0; 246
247 /* Set up the kernel text mapping from scratch */
248 pud = (pud_t *)get_safe_page(GFP_ATOMIC);
249 if (!pud)
250 return -ENOMEM;
251 error = res_kernel_text_pud_init(pud, __START_KERNEL_map);
252 if (!error)
253 set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map),
254 __pgd(__pa(pud) | _PAGE_TABLE));
255
256 return error;
230} 257}
231 258
232int swsusp_arch_resume(void) 259int swsusp_arch_resume(void)