aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/suspend_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/suspend_64.c')
-rw-r--r--arch/x86/kernel/suspend_64.c54
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 */
151extern int restore_image(void); 151extern 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 */
157unsigned long restore_jump_address;
158
153pgd_t *temp_level4_pgt; 159pgd_t *temp_level4_pgt;
154 160
161void *relocated_restore_code;
162
155static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) 163static 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
255struct 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 */
267int 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 */
283int 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 */