Skip to content
  • Konrad Rzeszutek Wilk's avatar
    x86-32, gdt: Store/load GDT for ACPI S3 or hibernation/resume path is not needed · 84e70971
    Konrad Rzeszutek Wilk authored
    
    
    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: default avatarKonrad 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: default avatarH. Peter Anvin <hpa@linux.intel.com>
    84e70971