linux/arch/x86/kernel/acpi/wakeup_32.S
Ingo Molnar ffa64eff95 x86: Load __USER_DS into DS/ES after resume
Srinivas Pandruvada reported a problem with system resume from
suspend-to-RAM on 32-bit x86 systems where the DS register of
the CPU is set to __KERNEL_DS instead of __USER_DS on return
to user space which cases a General Protection Fault to occur.

The issue is that DS is set to __KERNEL_DS by the ACPI resume code
path while the SYSEXIT path never reloads DS/ES.  It assumes they
are still __USER_DS set at the SYSENTER time (Brian Gerst), so if
the return to user space happens to be through SYSEXIT, it will lead
to the reported GPF.

Fix the problem by setting the DS and ES registers to __USER_DS
as expected by the SYSEXIT path.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=61781
Link: http://marc.info/?l=linux-pm&m=143406648920385&w=2
Acked-by: Pavel Machek <pavel@ucw.cz>
Tested-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Ingo Molnar <mingo@kernel.org>

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2015-06-22 14:40:03 +02:00

100 lines
1.7 KiB
ArmAsm

.text
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page_types.h>
# Copyright 2003, 2008 Pavel Machek <pavel@suse.cz>, distribute under GPLv2
.code32
ALIGN
ENTRY(wakeup_pmode_return)
wakeup_pmode_return:
movw $__KERNEL_DS, %ax
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
movw $__USER_DS, %ax
movw %ax, %ds
movw %ax, %es
# reload the gdt, as we need the full 32 bit address
lidt saved_idt
lldt saved_ldt
ljmp $(__KERNEL_CS), $1f
1:
movl %cr3, %eax
movl %eax, %cr3
wbinvd
# and restore the stack ... but you need gdt for this to work
movl saved_context_esp, %esp
movl %cs:saved_magic, %eax
cmpl $0x12345678, %eax
jne bogus_magic
# jump to place where we left off
movl saved_eip, %eax
jmp *%eax
bogus_magic:
jmp bogus_magic
save_registers:
sidt saved_idt
sldt saved_ldt
str saved_tss
leal 4(%esp), %eax
movl %eax, saved_context_esp
movl %ebx, saved_context_ebx
movl %ebp, saved_context_ebp
movl %esi, saved_context_esi
movl %edi, saved_context_edi
pushfl
popl saved_context_eflags
movl $ret_point, saved_eip
ret
restore_registers:
movl saved_context_ebp, %ebp
movl saved_context_ebx, %ebx
movl saved_context_esi, %esi
movl saved_context_edi, %edi
pushl saved_context_eflags
popfl
ret
ENTRY(do_suspend_lowlevel)
call save_processor_state
call save_registers
pushl $3
call x86_acpi_enter_sleep_state
addl $4, %esp
# In case of S3 failure, we'll emerge here. Jump
# to ret_point to recover
jmp ret_point
.p2align 4,,7
ret_point:
call restore_registers
call restore_processor_state
ret
.data
ALIGN
ENTRY(saved_magic) .long 0
ENTRY(saved_eip) .long 0
# saved registers
saved_idt: .long 0,0
saved_ldt: .long 0
saved_tss: .long 0