From: Len Brown <lenb@kernel.org>
To: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Andrew Morton <akpm@linux-foundation.org>,
ACPI Devel Maling List <linux-acpi@vger.kernel.org>,
Ingo Molnar <mingo@elte.hu>, LKML <linux-kernel@vger.kernel.org>,
Pavel Machek <pavel@ucw.cz>,
pm list <linux-pm@lists.linux-foundation.org>
Subject: Re: [PATCH] x86 ACPI: normalize segment descriptor register on resume
Date: Tue, 24 Jun 2008 17:47:20 -0400 (EDT) [thread overview]
Message-ID: <alpine.LFD.1.10.0806241747071.3014@localhost.localdomain> (raw)
In-Reply-To: <200806242303.49498.rjw@sisk.pl>
Applied.
thanks,
-Len
On Tue, 24 Jun 2008, Rafael J. Wysocki wrote:
> Hi,
>
> The patch below fixes the regression described at
> http://bugzilla.kernel.org/show_bug.cgi?id=10927
> which is caused by the fact that some BIOSes call the kernel's resume code with
> post-protected mode garbage in segment registers.
>
> Apart from Dell laptops referred to in the chagelog it has a potential to fix
> some other systems on which resume from suspend to RAM fails in a mysterious
> way and the probability of it breaking things is rather small, so IMO it would
> be nice to have in 2.6.26.
>
> Thanks,
> Rafael
>
>
> ---
> From: H. Peter Anvin <hpa@zytor.com>
>
> 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 <hpa@zytor.com>
> Tested-by: Kirill A. Shutemov <kirill@shutemov.name>
> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
> ---
> arch/x86/kernel/acpi/realmode/wakeup.S | 38 ++++++++++++++++++++++++++++++++-
> arch/x86/kernel/acpi/realmode/wakeup.h | 5 ++++
> arch/x86/kernel/acpi/sleep.c | 16 +++++++++++++
> drivers/acpi/sleep/main.c | 5 +---
> 4 files changed, 59 insertions(+), 5 deletions(-)
>
> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> ===================================================================
> --- linux-2.6.orig/arch/x86/kernel/acpi/realmode/wakeup.S
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.S
> @@ -5,6 +5,7 @@
> #include <asm/msr-index.h>
> #include <asm/page.h>
> #include <asm/pgtable.h>
> +#include <asm/processor-flags.h>
>
> .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
> Index: linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
> ===================================================================
> --- linux-2.6.orig/arch/x86/kernel/acpi/realmode/wakeup.h
> +++ linux-2.6/arch/x86/kernel/acpi/realmode/wakeup.h
> @@ -24,6 +24,11 @@ struct wakeup_header {
> u32 realmode_flags;
> u32 real_magic;
> u16 trampoline_segment; /* segment with trampoline code, 64-bit only */
> + u8 _pad1;
> + u8 wakeup_jmp;
> + u16 wakeup_jmp_off;
> + u16 wakeup_jmp_seg;
> + u64 wakeup_gdt[3];
> u32 signature; /* To check we have correct structure */
> } __attribute__((__packed__));
>
> Index: linux-2.6/arch/x86/kernel/acpi/sleep.c
> ===================================================================
> --- linux-2.6.orig/arch/x86/kernel/acpi/sleep.c
> +++ linux-2.6/arch/x86/kernel/acpi/sleep.c
> @@ -50,6 +50,20 @@ int acpi_save_state_mem(void)
>
> header->video_mode = saved_video_mode;
>
> + header->wakeup_jmp_seg = acpi_wakeup_address >> 4;
> + /* GDT[0]: GDT self-pointer */
> + header->wakeup_gdt[0] =
> + (u64)(sizeof(header->wakeup_gdt) - 1) +
> + ((u64)(acpi_wakeup_address +
> + ((char *)&header->wakeup_gdt - (char *)acpi_realmode))
> + << 16);
> + /* GDT[1]: real-mode-like code segment */
> + header->wakeup_gdt[1] = (0x009bULL << 40) +
> + ((u64)acpi_wakeup_address << 16) + 0xffff;
> + /* GDT[2]: real-mode-like data segment */
> + header->wakeup_gdt[2] = (0x0093ULL << 40) +
> + ((u64)acpi_wakeup_address << 16) + 0xffff;
> +
> #ifndef CONFIG_64BIT
> store_gdt((struct desc_ptr *)&header->pmode_gdt);
>
> @@ -111,7 +125,7 @@ void __init acpi_reserve_bootmem(void)
> return;
> }
>
> - acpi_wakeup_address = acpi_realmode;
> + acpi_wakeup_address = virt_to_phys((void *)acpi_realmode);
> }
>
>
> Index: linux-2.6/drivers/acpi/sleep/main.c
> ===================================================================
> --- linux-2.6.orig/drivers/acpi/sleep/main.c
> +++ linux-2.6/drivers/acpi/sleep/main.c
> @@ -32,9 +32,8 @@ static int acpi_sleep_prepare(u32 acpi_s
> if (!acpi_wakeup_address) {
> return -EFAULT;
> }
> - acpi_set_firmware_waking_vector((acpi_physical_address)
> - virt_to_phys((void *)
> - acpi_wakeup_address));
> + acpi_set_firmware_waking_vector(
> + (acpi_physical_address)acpi_wakeup_address);
>
> }
> ACPI_FLUSH_CPU_CACHE();
>
prev parent reply other threads:[~2008-06-24 21:47 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-24 21:03 [PATCH] x86 ACPI: normalize segment descriptor register on resume Rafael J. Wysocki
2008-06-24 21:46 ` Pavel Machek
2008-06-25 17:01 ` Ingo Molnar
2008-06-25 20:17 ` Rafael J. Wysocki
2008-06-26 8:17 ` Andrew Morton
2008-06-26 8:29 ` Ingo Molnar
2008-06-26 8:39 ` Rafael J. Wysocki
2008-06-26 8:51 ` Ingo Molnar
2008-06-26 8:56 ` Rafael J. Wysocki
2008-06-26 8:35 ` Rafael J. Wysocki
2008-06-24 21:47 ` Len Brown [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.LFD.1.10.0806241747071.3014@localhost.localdomain \
--to=lenb@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.linux-foundation.org \
--cc=mingo@elte.hu \
--cc=pavel@ucw.cz \
--cc=rjw@sisk.pl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox