diff options
author | Zhimin Gu <kookoo.gu@intel.com> | 2018-09-21 02:28:11 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-10-03 05:56:34 -0400 |
commit | 32aa276437f6128df63111af13e57fe8f0272af3 (patch) | |
tree | 58a65d9e86baba9db8ba38c66eea8bd0a7d8e3fd /arch/x86/power | |
parent | 0b0a6b1f76835cbaf746e7c72edd374ec0fe818b (diff) |
x86-32, hibernate: Switch to original page table after resumed
After all the pages are restored to previous address, the page
table switches back to current swapper_pg_dir. However the
swapper_pg_dir currently in used might not be consistent with
previous page table, which might cause issue after resume.
Fix this issue by switching to original page table after resume,
and the address of the original page table is saved in the hibernation
image header.
Move the manipulation of restore_cr3 into common code blocks.
Signed-off-by: Zhimin Gu <kookoo.gu@intel.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Chen Yu <yu.c.chen@intel.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'arch/x86/power')
-rw-r--r-- | arch/x86/power/hibernate.c | 4 | ||||
-rw-r--r-- | arch/x86/power/hibernate_asm_32.S | 10 |
2 files changed, 9 insertions, 5 deletions
diff --git a/arch/x86/power/hibernate.c b/arch/x86/power/hibernate.c index e3409e4a9b6a..4935b8139229 100644 --- a/arch/x86/power/hibernate.c +++ b/arch/x86/power/hibernate.c | |||
@@ -160,6 +160,7 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) | |||
160 | #ifdef CONFIG_X86_64 | 160 | #ifdef CONFIG_X86_64 |
161 | rdr->jump_address = (unsigned long)restore_registers; | 161 | rdr->jump_address = (unsigned long)restore_registers; |
162 | rdr->jump_address_phys = __pa_symbol(restore_registers); | 162 | rdr->jump_address_phys = __pa_symbol(restore_registers); |
163 | #endif | ||
163 | 164 | ||
164 | /* | 165 | /* |
165 | * The restore code fixes up CR3 and CR4 in the following sequence: | 166 | * The restore code fixes up CR3 and CR4 in the following sequence: |
@@ -179,7 +180,6 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) | |||
179 | * have any of the PCID bits set. | 180 | * have any of the PCID bits set. |
180 | */ | 181 | */ |
181 | rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK; | 182 | rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK; |
182 | #endif | ||
183 | 183 | ||
184 | return hibernation_e820_save(rdr->e820_digest); | 184 | return hibernation_e820_save(rdr->e820_digest); |
185 | } | 185 | } |
@@ -201,8 +201,8 @@ int arch_hibernation_header_restore(void *addr) | |||
201 | #ifdef CONFIG_X86_64 | 201 | #ifdef CONFIG_X86_64 |
202 | restore_jump_address = rdr->jump_address; | 202 | restore_jump_address = rdr->jump_address; |
203 | jump_address_phys = rdr->jump_address_phys; | 203 | jump_address_phys = rdr->jump_address_phys; |
204 | restore_cr3 = rdr->cr3; | ||
205 | #endif | 204 | #endif |
205 | restore_cr3 = rdr->cr3; | ||
206 | 206 | ||
207 | if (hibernation_e820_mismatch(rdr->e820_digest)) { | 207 | if (hibernation_e820_mismatch(rdr->e820_digest)) { |
208 | pr_crit("Hibernate inconsistent memory map detected!\n"); | 208 | pr_crit("Hibernate inconsistent memory map detected!\n"); |
diff --git a/arch/x86/power/hibernate_asm_32.S b/arch/x86/power/hibernate_asm_32.S index f5103ae96582..6b2b94937113 100644 --- a/arch/x86/power/hibernate_asm_32.S +++ b/arch/x86/power/hibernate_asm_32.S | |||
@@ -25,6 +25,10 @@ ENTRY(swsusp_arch_suspend) | |||
25 | pushfl | 25 | pushfl |
26 | popl saved_context_eflags | 26 | popl saved_context_eflags |
27 | 27 | ||
28 | /* save cr3 */ | ||
29 | movl %cr3, %eax | ||
30 | movl %eax, restore_cr3 | ||
31 | |||
28 | FRAME_BEGIN | 32 | FRAME_BEGIN |
29 | call swsusp_save | 33 | call swsusp_save |
30 | FRAME_END | 34 | FRAME_END |
@@ -32,6 +36,8 @@ ENTRY(swsusp_arch_suspend) | |||
32 | ENDPROC(swsusp_arch_suspend) | 36 | ENDPROC(swsusp_arch_suspend) |
33 | 37 | ||
34 | ENTRY(restore_image) | 38 | ENTRY(restore_image) |
39 | movl restore_cr3, %ebp | ||
40 | |||
35 | movl mmu_cr4_features, %ecx | 41 | movl mmu_cr4_features, %ecx |
36 | movl temp_pgt, %eax | 42 | movl temp_pgt, %eax |
37 | movl %eax, %cr3 | 43 | movl %eax, %cr3 |
@@ -66,9 +72,7 @@ done: | |||
66 | .align PAGE_SIZE | 72 | .align PAGE_SIZE |
67 | ENTRY(restore_registers) | 73 | ENTRY(restore_registers) |
68 | /* go back to the original page tables */ | 74 | /* go back to the original page tables */ |
69 | movl $swapper_pg_dir, %eax | 75 | movl %ebp, %cr3 |
70 | subl $__PAGE_OFFSET, %eax | ||
71 | movl %eax, %cr3 | ||
72 | movl mmu_cr4_features, %ecx | 76 | movl mmu_cr4_features, %ecx |
73 | jecxz 1f # cr4 Pentium and higher, skip if zero | 77 | jecxz 1f # cr4 Pentium and higher, skip if zero |
74 | movl %ecx, %cr4; # turn PGE back on | 78 | movl %ecx, %cr4; # turn PGE back on |