diff options
Diffstat (limited to 'arch/x86/kernel/suspend_64.c')
-rw-r--r-- | arch/x86/kernel/suspend_64.c | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/arch/x86/kernel/suspend_64.c b/arch/x86/kernel/suspend_64.c index 573c0a6e0ac6..01fbfb018ca9 100644 --- a/arch/x86/kernel/suspend_64.c +++ b/arch/x86/kernel/suspend_64.c | |||
@@ -150,8 +150,16 @@ void fix_processor_context(void) | |||
150 | /* Defined in arch/x86_64/kernel/suspend_asm.S */ | 150 | /* Defined in arch/x86_64/kernel/suspend_asm.S */ |
151 | extern int restore_image(void); | 151 | extern int restore_image(void); |
152 | 152 | ||
153 | /* | ||
154 | * Address to jump to in the last phase of restore in order to get to the image | ||
155 | * kernel's text (this value is passed in the image header). | ||
156 | */ | ||
157 | unsigned long restore_jump_address; | ||
158 | |||
153 | pgd_t *temp_level4_pgt; | 159 | pgd_t *temp_level4_pgt; |
154 | 160 | ||
161 | void *relocated_restore_code; | ||
162 | |||
155 | static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) | 163 | static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) |
156 | { | 164 | { |
157 | long i, j; | 165 | long i, j; |
@@ -175,7 +183,7 @@ static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long en | |||
175 | 183 | ||
176 | if (paddr >= end) | 184 | if (paddr >= end) |
177 | break; | 185 | break; |
178 | pe = _PAGE_NX | _PAGE_PSE | _KERNPG_TABLE | paddr; | 186 | pe = __PAGE_KERNEL_LARGE_EXEC | paddr; |
179 | pe &= __supported_pte_mask; | 187 | pe &= __supported_pte_mask; |
180 | set_pmd(pmd, __pmd(pe)); | 188 | set_pmd(pmd, __pmd(pe)); |
181 | } | 189 | } |
@@ -222,6 +230,13 @@ int swsusp_arch_resume(void) | |||
222 | /* We have got enough memory and from now on we cannot recover */ | 230 | /* We have got enough memory and from now on we cannot recover */ |
223 | if ((error = set_up_temporary_mappings())) | 231 | if ((error = set_up_temporary_mappings())) |
224 | return error; | 232 | return error; |
233 | |||
234 | relocated_restore_code = (void *)get_safe_page(GFP_ATOMIC); | ||
235 | if (!relocated_restore_code) | ||
236 | return -ENOMEM; | ||
237 | memcpy(relocated_restore_code, &core_restore_code, | ||
238 | &restore_registers - &core_restore_code); | ||
239 | |||
225 | restore_image(); | 240 | restore_image(); |
226 | return 0; | 241 | return 0; |
227 | } | 242 | } |
@@ -236,4 +251,41 @@ int pfn_is_nosave(unsigned long pfn) | |||
236 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; | 251 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; |
237 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | 252 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); |
238 | } | 253 | } |
254 | |||
255 | struct restore_data_record { | ||
256 | unsigned long jump_address; | ||
257 | unsigned long control; | ||
258 | }; | ||
259 | |||
260 | #define RESTORE_MAGIC 0x0123456789ABCDEFUL | ||
261 | |||
262 | /** | ||
263 | * arch_hibernation_header_save - populate the architecture specific part | ||
264 | * of a hibernation image header | ||
265 | * @addr: address to save the data at | ||
266 | */ | ||
267 | int arch_hibernation_header_save(void *addr, unsigned int max_size) | ||
268 | { | ||
269 | struct restore_data_record *rdr = addr; | ||
270 | |||
271 | if (max_size < sizeof(struct restore_data_record)) | ||
272 | return -EOVERFLOW; | ||
273 | rdr->jump_address = restore_jump_address; | ||
274 | rdr->control = (restore_jump_address ^ RESTORE_MAGIC); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * arch_hibernation_header_restore - read the architecture specific data | ||
280 | * from the hibernation image header | ||
281 | * @addr: address to read the data from | ||
282 | */ | ||
283 | int arch_hibernation_header_restore(void *addr) | ||
284 | { | ||
285 | struct restore_data_record *rdr = addr; | ||
286 | |||
287 | restore_jump_address = rdr->jump_address; | ||
288 | return (rdr->control == (restore_jump_address ^ RESTORE_MAGIC)) ? | ||
289 | 0 : -EINVAL; | ||
290 | } | ||
239 | #endif /* CONFIG_HIBERNATION */ | 291 | #endif /* CONFIG_HIBERNATION */ |