2005-04-17 02:20:36 +04:00
/*
* Suspend support specific for i386 .
*
* Distribute under GPLv2
*
* Copyright ( c ) 2002 Pavel Machek < pavel @ suse . cz >
* Copyright ( c ) 2001 Patrick Mochel < mochel @ osdl . org >
*/
# include <linux/module.h>
# include <linux/suspend.h>
2006-06-23 13:04:18 +04:00
# include <asm/mtrr.h>
2006-06-23 13:04:20 +04:00
# include <asm/mce.h>
2005-04-17 02:20:36 +04:00
static struct saved_context saved_context ;
unsigned long saved_context_ebx ;
unsigned long saved_context_esp , saved_context_ebp ;
unsigned long saved_context_esi , saved_context_edi ;
unsigned long saved_context_eflags ;
2008-01-30 15:31:23 +03:00
static void __save_processor_state ( struct saved_context * ctxt )
2005-04-17 02:20:36 +04:00
{
2007-05-02 21:27:17 +04:00
mtrr_save_fixed_ranges ( NULL ) ;
2005-04-17 02:20:36 +04:00
kernel_fpu_begin ( ) ;
/*
* descriptor tables
*/
2008-02-24 13:57:22 +03:00
store_gdt ( & ctxt - > gdt ) ;
store_idt ( & ctxt - > idt ) ;
store_tr ( ctxt - > tr ) ;
2005-04-17 02:20:36 +04:00
/*
* segment registers
*/
2008-02-24 13:57:22 +03:00
savesegment ( es , ctxt - > es ) ;
savesegment ( fs , ctxt - > fs ) ;
savesegment ( gs , ctxt - > gs ) ;
savesegment ( ss , ctxt - > ss ) ;
2005-04-17 02:20:36 +04:00
/*
2008-02-10 01:24:09 +03:00
* control registers
2005-04-17 02:20:36 +04:00
*/
2005-09-04 02:56:36 +04:00
ctxt - > cr0 = read_cr0 ( ) ;
ctxt - > cr2 = read_cr2 ( ) ;
ctxt - > cr3 = read_cr3 ( ) ;
ctxt - > cr4 = read_cr4 ( ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-24 13:57:22 +03:00
/* Needed by apm.c */
2005-04-17 02:20:36 +04:00
void save_processor_state ( void )
{
__save_processor_state ( & saved_context ) ;
}
2008-02-24 13:57:22 +03:00
EXPORT_SYMBOL ( save_processor_state ) ;
2005-04-17 02:20:36 +04:00
2005-10-31 01:59:28 +03:00
static void do_fpu_end ( void )
2005-04-17 02:20:36 +04:00
{
2005-10-31 01:59:28 +03:00
/*
* Restore FPU regs if necessary .
*/
kernel_fpu_end ( ) ;
2005-04-17 02:20:36 +04:00
}
static void fix_processor_context ( void )
{
int cpu = smp_processor_id ( ) ;
2008-02-24 13:57:22 +03:00
struct tss_struct * t = & per_cpu ( init_tss , cpu ) ;
2005-04-17 02:20:36 +04:00
2008-02-24 13:57:22 +03:00
set_tss_desc ( cpu , t ) ; /*
* This just modifies memory ; should not be
* necessary . But . . . This is necessary , because
* 386 hardware has concept of busy TSS or some
* similar stupidity .
*/
2005-04-17 02:20:36 +04:00
load_TR_desc ( ) ; /* This does ltr */
load_LDT ( & current - > active_mm - > context ) ; /* This does lldt */
/*
* Now maybe reload the debug registers
*/
2008-01-30 15:30:59 +03:00
if ( current - > thread . debugreg7 ) {
set_debugreg ( current - > thread . debugreg0 , 0 ) ;
set_debugreg ( current - > thread . debugreg1 , 1 ) ;
set_debugreg ( current - > thread . debugreg2 , 2 ) ;
set_debugreg ( current - > thread . debugreg3 , 3 ) ;
2005-06-23 11:08:43 +04:00
/* no 4 and 5 */
2008-01-30 15:30:59 +03:00
set_debugreg ( current - > thread . debugreg6 , 6 ) ;
set_debugreg ( current - > thread . debugreg7 , 7 ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-30 15:31:23 +03:00
static void __restore_processor_state ( struct saved_context * ctxt )
2005-04-17 02:20:36 +04:00
{
/*
* control registers
*/
2005-09-04 02:56:36 +04:00
write_cr4 ( ctxt - > cr4 ) ;
write_cr3 ( ctxt - > cr3 ) ;
write_cr2 ( ctxt - > cr2 ) ;
2006-05-23 09:35:29 +04:00
write_cr0 ( ctxt - > cr0 ) ;
2005-04-17 02:20:36 +04:00
2005-06-26 01:55:14 +04:00
/*
* now restore the descriptor tables to their proper values
* ltr is done i fix_processor_context ( ) .
*/
2008-02-24 13:57:22 +03:00
load_gdt ( & ctxt - > gdt ) ;
load_idt ( & ctxt - > idt ) ;
2005-06-26 01:55:14 +04:00
2005-04-17 02:20:36 +04:00
/*
* segment registers
*/
2008-02-24 13:57:22 +03:00
loadsegment ( es , ctxt - > es ) ;
loadsegment ( fs , ctxt - > fs ) ;
loadsegment ( gs , ctxt - > gs ) ;
loadsegment ( ss , ctxt - > ss ) ;
2005-04-17 02:20:36 +04:00
/*
* sysenter MSRs
*/
if ( boot_cpu_has ( X86_FEATURE_SEP ) )
2005-06-26 01:54:53 +04:00
enable_sep_cpu ( ) ;
2005-04-17 02:20:36 +04:00
fix_processor_context ( ) ;
do_fpu_end ( ) ;
2005-07-08 04:56:38 +04:00
mtrr_ap_init ( ) ;
2005-11-07 11:58:42 +03:00
mcheck_init ( & boot_cpu_data ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-24 13:57:22 +03:00
/* Needed by apm.c */
2005-04-17 02:20:36 +04:00
void restore_processor_state ( void )
{
__restore_processor_state ( & saved_context ) ;
}
EXPORT_SYMBOL ( restore_processor_state ) ;