x86-32, gdt: Store/load GDT for ACPI S3 or hibernation/resume path is not needed
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Fri, 5 Apr 2013 20:42:22 +0000 (16:42 -0400)
committerH. Peter Anvin <hpa@linux.intel.com>
Thu, 11 Apr 2013 22:40:17 +0000 (15:40 -0700)
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>
arch/x86/include/asm/suspend_32.h
arch/x86/kernel/acpi/wakeup_32.S
arch/x86/power/cpu.c

index 487055c8c1aaf2d63bbf2b0d8bcfcdd5d616c721..f6064b7385b0619d9fe09dab76e482a0d95e89c1 100644 (file)
@@ -15,7 +15,6 @@ struct saved_context {
        unsigned long cr0, cr2, cr3, cr4;
        u64 misc_enable;
        bool misc_enable_saved;
-       struct desc_ptr gdt;
        struct desc_ptr idt;
        u16 ldt;
        u16 tss;
index 13ab720573e3e31e317ac52f977e168401552f17..91adb1be24bcdaa8a62235fa45611f09eeb46393 100644 (file)
@@ -18,7 +18,6 @@ wakeup_pmode_return:
        movw    %ax, %gs
 
        # reload the gdt, as we need the full 32 bit address
-       lgdt    saved_gdt
        lidt    saved_idt
        lldt    saved_ldt
        ljmp    $(__KERNEL_CS), $1f
@@ -44,7 +43,6 @@ bogus_magic:
 
 
 save_registers:
-       sgdt    saved_gdt
        sidt    saved_idt
        sldt    saved_ldt
        str     saved_tss
@@ -93,7 +91,6 @@ ENTRY(saved_magic)    .long   0
 ENTRY(saved_eip)       .long   0
 
 # saved registers
-saved_gdt:     .long   0,0
 saved_idt:     .long   0,0
 saved_ldt:     .long   0
 saved_tss:     .long   0
index 6bd94233669c3b56991d942a6dd46495707bbb10..82c39c5323491339950c8fa91b7f10624b6a2e07 100644 (file)
@@ -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 */