aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-04-05 16:42:22 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-04-11 18:40:17 -0400
commit84e70971e67d97bc2db18a4e76d42846272a54bd (patch)
tree8e2fdc1abdf9a9a347f36fd8d15abe26e610623c /arch/x86
parente7a5cd063c7b4c58417f674821d63f5eb6747e37 (diff)
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')
-rw-r--r--arch/x86/include/asm/suspend_32.h1
-rw-r--r--arch/x86/kernel/acpi/wakeup_32.S3
-rw-r--r--arch/x86/power/cpu.c2
3 files changed, 0 insertions, 6 deletions
diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h
index 487055c8c1aa..f6064b7385b0 100644
--- a/arch/x86/include/asm/suspend_32.h
+++ b/arch/x86/include/asm/suspend_32.h
@@ -15,7 +15,6 @@ struct saved_context {
15 unsigned long cr0, cr2, cr3, cr4; 15 unsigned long cr0, cr2, cr3, cr4;
16 u64 misc_enable; 16 u64 misc_enable;
17 bool misc_enable_saved; 17 bool misc_enable_saved;
18 struct desc_ptr gdt;
19 struct desc_ptr idt; 18 struct desc_ptr idt;
20 u16 ldt; 19 u16 ldt;
21 u16 tss; 20 u16 tss;
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index 13ab720573e3..91adb1be24bc 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -18,7 +18,6 @@ wakeup_pmode_return:
18 movw %ax, %gs 18 movw %ax, %gs
19 19
20 # reload the gdt, as we need the full 32 bit address 20 # reload the gdt, as we need the full 32 bit address
21 lgdt saved_gdt
22 lidt saved_idt 21 lidt saved_idt
23 lldt saved_ldt 22 lldt saved_ldt
24 ljmp $(__KERNEL_CS), $1f 23 ljmp $(__KERNEL_CS), $1f
@@ -44,7 +43,6 @@ bogus_magic:
44 43
45 44
46save_registers: 45save_registers:
47 sgdt saved_gdt
48 sidt saved_idt 46 sidt saved_idt
49 sldt saved_ldt 47 sldt saved_ldt
50 str saved_tss 48 str saved_tss
@@ -93,7 +91,6 @@ ENTRY(saved_magic) .long 0
93ENTRY(saved_eip) .long 0 91ENTRY(saved_eip) .long 0
94 92
95# saved registers 93# saved registers
96saved_gdt: .long 0,0
97saved_idt: .long 0,0 94saved_idt: .long 0,0
98saved_ldt: .long 0 95saved_ldt: .long 0
99saved_tss: .long 0 96saved_tss: .long 0
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)
61 * descriptor tables 61 * descriptor tables
62 */ 62 */
63#ifdef CONFIG_X86_32 63#ifdef CONFIG_X86_32
64 store_gdt(&ctxt->gdt);
65 store_idt(&ctxt->idt); 64 store_idt(&ctxt->idt);
66#else 65#else
67/* CONFIG_X86_64 */ 66/* CONFIG_X86_64 */
@@ -181,7 +180,6 @@ static void __restore_processor_state(struct saved_context *ctxt)
181 * ltr is done i fix_processor_context(). 180 * ltr is done i fix_processor_context().
182 */ 181 */
183#ifdef CONFIG_X86_32 182#ifdef CONFIG_X86_32
184 load_gdt(&ctxt->gdt);
185 load_idt(&ctxt->idt); 183 load_idt(&ctxt->idt);
186#else 184#else
187/* CONFIG_X86_64 */ 185/* CONFIG_X86_64 */