From 4b4f7280d7fd1feeff134c2cf2db32fd583b6c29 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 24 Jun 2008 23:03:48 +0200 Subject: x86 ACPI: normalize segment descriptor register on resume Some Dell laptops enter resume with apparent garbage in the segment descriptor registers (almost certainly the result of a botched transition from protected to real mode.) The only way to clean that up is to enter protected mode ourselves and clean out the descriptor registers. This fixes resume on Dell XPS M1210 and Dell D620. Reference: http://bugzilla.kernel.org/show_bug.cgi?id=10927 Signed-off-by: H. Peter Anvin Cc: Andrew Morton Cc: Pavel Machek Cc: pm list Cc: Len Brown Signed-off-by: Ingo Molnar Tested-by: Kirill A. Shutemov Signed-off-by: Rafael J. Wysocki Signed-off-by: Ingo Molnar --- arch/x86/kernel/acpi/realmode/wakeup.S | 38 +++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'arch/x86/kernel/acpi/realmode/wakeup.S') diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S index f9b77fb37e5..3355973b12a 100644 --- a/arch/x86/kernel/acpi/realmode/wakeup.S +++ b/arch/x86/kernel/acpi/realmode/wakeup.S @@ -5,6 +5,7 @@ #include #include #include +#include .code16 .section ".header", "a" @@ -24,6 +25,11 @@ pmode_gdt: .quad 0 realmode_flags: .long 0 real_magic: .long 0 trampoline_segment: .word 0 +_pad1: .byte 0 +wakeup_jmp: .byte 0xea /* ljmpw */ +wakeup_jmp_off: .word 3f +wakeup_jmp_seg: .word 0 +wakeup_gdt: .quad 0, 0, 0 signature: .long 0x51ee1111 .text @@ -34,11 +40,34 @@ _start: cli cld + /* Apparently some dimwit BIOS programmers don't know how to + program a PM to RM transition, and we might end up here with + junk in the data segment descriptor registers. The only way + to repair that is to go into PM and fix it ourselves... */ + movw $16, %cx + lgdtl %cs:wakeup_gdt + movl %cr0, %eax + orb $X86_CR0_PE, %al + movl %eax, %cr0 + jmp 1f +1: ljmpw $8, $2f +2: + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs + + andb $~X86_CR0_PE, %al + movl %eax, %cr0 + jmp wakeup_jmp +3: /* Set up segments */ movw %cs, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss + lidtl wakeup_idt movl $wakeup_stack_end, %esp @@ -98,7 +127,14 @@ bogus_real_magic: jmp 1b .data - .balign 4 + .balign 8 + + /* This is the standard real-mode IDT */ +wakeup_idt: + .word 0xffff /* limit */ + .long 0 /* address */ + .word 0 + .globl HEAP, heap_end HEAP: .long wakeup_heap -- cgit v1.2.3