summaryrefslogtreecommitdiffstats
path: root/arch/x86/power
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-04-05 22:42:22 +0200
committerH. Peter Anvin <hpa@linux.intel.com>2013-04-12 00:40:17 +0200
commit84e70971e67d97bc2db18a4e76d42846272a54bd (patch)
tree8e2fdc1abdf9a9a347f36fd8d15abe26e610623c /arch/x86/power
parentx86-64, gdt: Store/load GDT for ACPI S3 or hibernate/resume path is not needed. (diff)
downloadlinux-84e70971e67d97bc2db18a4e76d42846272a54bd.tar.xz
linux-84e70971e67d97bc2db18a4e76d42846272a54bd.zip
x86-32, gdt: Store/load GDT for ACPI S3 or hibernation/resume path is not needed
During the ACPI S3 suspend, we store the GDT in the wakup_header (see wakeup_asm.s) field called 'pmode_gdt'. Which is then used during the resume path and has the same exact value as what the store/load_gdt do with the saved_context (which is saved/restored via save/restore_processor_state()). The flow during resume from ACPI S3 is simpler than the 64-bit counterpart. We only use the early bootstrap once (wakeup_gdt) and do various checks in real mode. After the checks are completed, we load the saved GDT ('pmode_gdt') and continue on with the resume (by heading to startup_32 in trampoline_32.S) - which quickly jumps to what was saved in 'pmode_entry' aka 'wakeup_pmode_return'. The 'wakeup_pmode_return' restores the GDT (saved_gdt) again (which was saved in do_suspend_lowlevel initially). After that it ends up calling the 'ret_point' which calls 'restore_processor_state()'. We have two opportunities to remove code where we restore the same GDT twice. Here is the call chain: wakeup_start |- lgdtl wakeup_gdt [the work-around broken BIOSes] | | - lgdtl pmode_gdt [the real one] | \-- startup_32 (in trampoline_32.S) \-- wakeup_pmode_return (in wakeup_32.S) |- lgdtl saved_gdt [the real one] \-- ret_point |.. |- call restore_processor_state The hibernate path is much simpler. During the saving of the hibernation image we call save_processor_state() and save the contents of that along with the rest of the kernel in the hibernation image destination. We save the EIP of 'restore_registers' (restore_jump_address) and cr3 (restore_cr3). During hibernate resume, the 'restore_registers' (via the 'restore_jump_address) in hibernate_asm_32.S is invoked which restores the contents of most registers. Naturally the resume path benefits from already being in 32-bit mode, so it does not have to reload the GDT. It only reloads the cr3 (from restore_cr3) and continues on. Note that the restoration of the restore image page-tables is done prior to this. After the 'restore_registers' it returns and we end up called restore_processor_state() - where we reload the GDT. The reload of the GDT is not needed as bootup kernel has already loaded the GDT which is at the same physical location as the the restored kernel. Note that the hibernation path assumes the GDT is correct during its 'restore_registers'. The assumption in the code is that the restored image is the same as saved - meaning we are not trying to restore an different kernel in the virtual address space of a new kernel. Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Link: http://lkml.kernel.org/r/1365194544-14648-3-git-send-email-konrad.wilk@oracle.com Cc: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/power')
-rw-r--r--arch/x86/power/cpu.c2
1 files changed, 0 insertions, 2 deletions
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 6bd94233669c..82c39c532349 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -61,7 +61,6 @@ static void __save_processor_state(struct saved_context *ctxt)
* descriptor tables
*/
#ifdef CONFIG_X86_32
- store_gdt(&ctxt->gdt);
store_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
@@ -181,7 +180,6 @@ static void __restore_processor_state(struct saved_context *ctxt)
* ltr is done i fix_processor_context().
*/
#ifdef CONFIG_X86_32
- load_gdt(&ctxt->gdt);
load_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */