d158cbdf39
Make it possible to restore a hibernation image on x86_64 with the help of a kernel different from the one in the image. The idea is to split the core restoration code into two separate parts and to place each of them in a different page. The first part belongs to the boot kernel and is executed as the last step of the image kernel's memory restoration procedure. Before being executed, it is relocated to a safe page that won't be overwritten while copying the image kernel pages. The final operation performed by it is a jump to the second part of the core restoration code that belongs to the image kernel and has just been restored. This code makes the CPU switch to the image kernel's page tables and restores the state of general purpose registers (including the stack pointer) from before the hibernation. The main issue with this idea is that in order to jump to the second part of the core restoration code the boot kernel needs to know its address. However, this address may be passed to it in the image header. Namely, the part of the image header previously used for checking if the version of the image kernel is correct can be replaced with some architecture specific data that will allow the boot kernel to jump to the right address within the image kernel. These data should also be used for checking if the image kernel is compatible with the boot kernel (as far as the memory restroration procedure is concerned). It can be done, for example, with the help of a "magic" value that has to be equal in both kernels, so that they can be regarded as compatible. 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>
58 lines
1.7 KiB
C
58 lines
1.7 KiB
C
/*
|
|
* Copyright 2001-2003 Pavel Machek <pavel@suse.cz>
|
|
* Based on code
|
|
* Copyright 2001 Patrick Mochel <mochel@osdl.org>
|
|
*/
|
|
#include <asm/desc.h>
|
|
#include <asm/i387.h>
|
|
|
|
static inline int
|
|
arch_prepare_suspend(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* Image of the saved processor state. If you touch this, fix acpi_wakeup.S. */
|
|
struct saved_context {
|
|
u16 ds, es, fs, gs, ss;
|
|
unsigned long gs_base, gs_kernel_base, fs_base;
|
|
unsigned long cr0, cr2, cr3, cr4, cr8;
|
|
unsigned long efer;
|
|
u16 gdt_pad;
|
|
u16 gdt_limit;
|
|
unsigned long gdt_base;
|
|
u16 idt_pad;
|
|
u16 idt_limit;
|
|
unsigned long idt_base;
|
|
u16 ldt;
|
|
u16 tss;
|
|
unsigned long tr;
|
|
unsigned long safety;
|
|
unsigned long return_address;
|
|
unsigned long eflags;
|
|
} __attribute__((packed));
|
|
|
|
/* We'll access these from assembly, so we'd better have them outside struct */
|
|
extern unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx;
|
|
extern unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi;
|
|
extern unsigned long saved_context_r08, saved_context_r09, saved_context_r10, saved_context_r11;
|
|
extern unsigned long saved_context_r12, saved_context_r13, saved_context_r14, saved_context_r15;
|
|
extern unsigned long saved_context_eflags;
|
|
|
|
#define loaddebug(thread,register) \
|
|
set_debugreg((thread)->debugreg##register, register)
|
|
|
|
extern void fix_processor_context(void);
|
|
|
|
extern unsigned long saved_rip;
|
|
extern unsigned long saved_rsp;
|
|
extern unsigned long saved_rbp;
|
|
extern unsigned long saved_rbx;
|
|
extern unsigned long saved_rsi;
|
|
extern unsigned long saved_rdi;
|
|
|
|
/* routines for saving/restoring kernel state */
|
|
extern int acpi_save_state_mem(void);
|
|
extern char core_restore_code;
|
|
extern char restore_registers;
|