@@ -36,6 +36,7 @@ struct saved_context {
unsigned long tr;
unsigned long safety;
unsigned long return_address;
+ u8 skip;
} __attribute__((packed));
#define loaddebug(thread,register) \
@@ -24,6 +24,9 @@ unsigned long acpi_realmode_flags;
#if defined(CONFIG_SMP) && defined(CONFIG_64BIT)
static char temp_stack[4096];
#endif
+#include <asm/suspend_64.h>
+bool skip_cr3;
+extern struct saved_context saved_context;
/**
* acpi_suspend_lowlevel - save kernel state
@@ -82,10 +85,16 @@ int acpi_suspend_lowlevel(void)
saved_magic = 0x123456789abcdef0L;
#endif /* CONFIG_64BIT */
+ if (skip_cr3) {
+ printk(KERN_INFO "Skipping cr3\n");
+ saved_context.skip = 1;
+ }
do_suspend_lowlevel();
return 0;
}
-
+bool ignore_idt;
+bool ignore_gdt;
+bool alternative_tss;
static int __init acpi_sleep_setup(char *str)
{
while ((str != NULL) && (*str != '\0')) {
@@ -105,6 +114,14 @@ static int __init acpi_sleep_setup(char *str)
acpi_nvs_nosave_s3();
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
+ if (strncmp(str, "ignore_idt", 10) == 0)
+ ignore_idt = true;
+ if (strncmp(str, "ignore_gdt", 10) == 0)
+ ignore_idt = true;
+ if (strncmp(str, "tss", 3) == 0)
+ alternative_tss = true;
+ if (strncmp(str, "cr3", 3) == 0)
+ skip_cr3 = true;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
@@ -83,12 +83,16 @@ resume_point:
movq $saved_context, %rax
movq saved_context_cr4(%rax), %rbx
movq %rbx, %cr4
+
+ cmp $0x0, saved_context_skip(%rax)
+ jne skip
movq saved_context_cr3(%rax), %rbx
movq %rbx, %cr3
movq saved_context_cr2(%rax), %rbx
movq %rbx, %cr2
movq saved_context_cr0(%rax), %rbx
movq %rbx, %cr0
+skip:
pushq pt_regs_flags(%rax)
popfq
movq pt_regs_sp(%rax), %rsp
@@ -73,6 +73,7 @@ int main(void)
ENTRY(cr3);
ENTRY(cr4);
ENTRY(cr8);
+ ENTRY(skip);
BLANK();
#undef ENTRY
@@ -35,6 +35,10 @@ unsigned long saved_context_eflags;
struct saved_context saved_context;
#endif
+extern bool ignore_idt;
+extern bool ignore_gdt;
+extern bool alternative_tss;
+
/**
* __save_processor_state - save CPU registers before creating a
* hibernation image and before restoring the memory state from it
@@ -61,12 +65,16 @@ static void __save_processor_state(struct saved_context *ctxt)
* descriptor tables
*/
#ifdef CONFIG_X86_32
- store_gdt(&ctxt->gdt);
- store_idt(&ctxt->idt);
+ if (!ignore_gdt)
+ store_gdt(&ctxt->gdt);
+ if (!ignore_idt)
+ store_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
- store_idt((struct desc_ptr *)&ctxt->idt_limit);
+ if (!ignore_gdt)
+ store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
+ if (!ignore_idt)
+ store_idt((struct desc_ptr *)&ctxt->idt_limit);
#endif
store_tr(ctxt->tr);
@@ -136,6 +144,7 @@ static void fix_processor_context(void)
struct tss_struct *t = &per_cpu(init_tss, cpu);
#ifdef CONFIG_X86_64
struct desc_struct *desc = get_cpu_gdt_table(cpu);
+ tss_desc tss;
#endif
set_tss_desc(cpu, t); /*
* This just modifies memory; should not be
@@ -145,13 +154,23 @@ static void fix_processor_context(void)
*/
#ifdef CONFIG_X86_64
- if (!desc_empty(&desc[GDT_ENTRY_TSS]))
- desc[GDT_ENTRY_TSS].type = DESC_TSS;
+ if (alternative_tss) {
+ memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
+ tss.type = DESC_TSS;
+ write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
+ } else {
+ if (!desc_empty(&desc[GDT_ENTRY_TSS])) {
+ desc[GDT_ENTRY_TSS].type = DESC_TSS;
+ }
+ }
syscall_init(); /* This sets MSR_*STAR and related */
#endif
+ outb('G', 0xe9);
load_TR_desc(); /* This does ltr */
+ outb('H', 0xe9);
load_LDT(¤t->active_mm->context); /* This does lldt */
+ outb('I', 0xe9);
}
/**
@@ -185,12 +204,16 @@ 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);
+ if (!ignore_gdt)
+ load_gdt(&ctxt->gdt);
+ if (!ignore_idt)
+ load_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
- load_idt((const struct desc_ptr *)&ctxt->idt_limit);
+ if (!ignore_gdt)
+ load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
+ if (!ignore_idt)
+ load_idt((const struct desc_ptr *)&ctxt->idt_limit);
#endif
/*
@@ -228,9 +251,13 @@ static void __restore_processor_state(struct saved_context *ctxt)
fix_processor_context();
+ outb('P', 0xe9);
do_fpu_end();
+ outb('Q', 0xe9);
x86_platform.restore_sched_clock_state();
+ outb('R', 0xe9);
mtrr_bp_restore();
+ outb('S', 0xe9);
}
/* Needed by apm.c */
@@ -1035,6 +1035,7 @@ static void xen_write_cr4(unsigned long cr4)
native_write_cr4(cr4);
}
#ifdef CONFIG_X86_64
+extern bool skip_cr3;
static inline unsigned long xen_read_cr8(void)
{
return 0;
@@ -1094,7 +1095,8 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
* xen_read_cr3 will try to find the cr3 for the user-space
* case - and feed it to the hypercall (which would fail).
*/
- xen_acpi_reload_cr3_value();
+ if (!skip_cr3)
+ xen_acpi_reload_cr3_value();
#endif
default:
ret = native_write_msr_safe(msr, low, high);
@@ -56,6 +56,8 @@ void xen_acpi_reload_cr3_value(void)
saved_context.cr3 = read_cr3();
}
#endif
+extern bool skip_cr3;
+
int xen_acpi_notify_hypervisor_state(u8 sleep_state,
u32 pm1a_cnt, u32 pm1b_cnt)
{
@@ -98,7 +100,9 @@ int xen_acpi_notify_hypervisor_state(u8 sleep_state,
mfn = pfn_to_mfn(PFN_DOWN(saved_context.cr3));
/* and back to a physical address */
mfn = PFN_PHYS(mfn);
- saved_context.cr3 = mfn;
+
+ if (!skip_cr3)
+ saved_context.cr3 = mfn;
/* Sadly, this has the end result that if we the resume code
* does the movq X, %cr3 and then later uses the X value to do