The patch:
    73201dbe x86, suspend: On wakeup always initialize cr4 and EFER
... was incorrectly committed in an intermediate (unfinished) form.
- We need to test CF, not ZF, for a bit test with btl.
- We don't actually need to compute the existence of EFLAGS.ID,
  since we set a flag at suspend time if CR4 should be restored.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Link: http://lkml.kernel.org/r/1348529239-17943-1-git-send-email-hpa@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
		
	
			
		
			
				
	
	
		
			177 lines
		
	
	
	
		
			3.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
	
		
			3.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * ACPI wakeup real mode startup stub
 | 
						|
 */
 | 
						|
#include <linux/linkage.h>
 | 
						|
#include <asm/segment.h>
 | 
						|
#include <asm/msr-index.h>
 | 
						|
#include <asm/page_types.h>
 | 
						|
#include <asm/pgtable_types.h>
 | 
						|
#include <asm/processor-flags.h>
 | 
						|
#include "realmode.h"
 | 
						|
#include "wakeup.h"
 | 
						|
 | 
						|
	.code16
 | 
						|
 | 
						|
/* This should match the structure in wakeup.h */
 | 
						|
	.section ".data", "aw"
 | 
						|
 | 
						|
	.balign	16
 | 
						|
GLOBAL(wakeup_header)
 | 
						|
	video_mode:	.short	0	/* Video mode number */
 | 
						|
	pmode_entry:	.long	0
 | 
						|
	pmode_cs:	.short	__KERNEL_CS
 | 
						|
	pmode_cr0:	.long	0	/* Saved %cr0 */
 | 
						|
	pmode_cr3:	.long	0	/* Saved %cr3 */
 | 
						|
	pmode_cr4:	.long	0	/* Saved %cr4 */
 | 
						|
	pmode_efer:	.quad	0	/* Saved EFER */
 | 
						|
	pmode_gdt:	.quad	0
 | 
						|
	pmode_misc_en:	.quad	0	/* Saved MISC_ENABLE MSR */
 | 
						|
	pmode_behavior:	.long	0	/* Wakeup behavior flags */
 | 
						|
	realmode_flags:	.long	0
 | 
						|
	real_magic:	.long	0
 | 
						|
	signature:	.long	WAKEUP_HEADER_SIGNATURE
 | 
						|
END(wakeup_header)
 | 
						|
 | 
						|
	.text
 | 
						|
	.code16
 | 
						|
 | 
						|
	.balign	16
 | 
						|
ENTRY(wakeup_start)
 | 
						|
	cli
 | 
						|
	cld
 | 
						|
 | 
						|
	LJMPW_RM(3f)
 | 
						|
3:
 | 
						|
	/* 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
 | 
						|
	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
 | 
						|
	LJMPW_RM(3f)
 | 
						|
3:
 | 
						|
	/* Set up segments */
 | 
						|
	movw	%cs, %ax
 | 
						|
	movw	%ax, %ss
 | 
						|
	movl	$rm_stack_end, %esp
 | 
						|
	movw	%ax, %ds
 | 
						|
	movw	%ax, %es
 | 
						|
	movw	%ax, %fs
 | 
						|
	movw	%ax, %gs
 | 
						|
 | 
						|
	lidtl	wakeup_idt
 | 
						|
 | 
						|
	/* Clear the EFLAGS */
 | 
						|
	pushl $0
 | 
						|
	popfl
 | 
						|
 | 
						|
	/* Check header signature... */
 | 
						|
	movl	signature, %eax
 | 
						|
	cmpl	$WAKEUP_HEADER_SIGNATURE, %eax
 | 
						|
	jne	bogus_real_magic
 | 
						|
 | 
						|
	/* Check we really have everything... */
 | 
						|
	movl	end_signature, %eax
 | 
						|
	cmpl	$REALMODE_END_SIGNATURE, %eax
 | 
						|
	jne	bogus_real_magic
 | 
						|
 | 
						|
	/* Call the C code */
 | 
						|
	calll	main
 | 
						|
 | 
						|
	/* Restore MISC_ENABLE before entering protected mode, in case
 | 
						|
	   BIOS decided to clear XD_DISABLE during S3. */
 | 
						|
	movl	pmode_behavior, %edi
 | 
						|
	btl	$WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
 | 
						|
	jnc	1f
 | 
						|
 | 
						|
	movl	pmode_misc_en, %eax
 | 
						|
	movl	pmode_misc_en + 4, %edx
 | 
						|
	movl	$MSR_IA32_MISC_ENABLE, %ecx
 | 
						|
	wrmsr
 | 
						|
1:
 | 
						|
 | 
						|
	/* Do any other stuff... */
 | 
						|
 | 
						|
#ifndef CONFIG_64BIT
 | 
						|
	/* This could also be done in C code... */
 | 
						|
	movl	pmode_cr3, %eax
 | 
						|
	movl	%eax, %cr3
 | 
						|
 | 
						|
	btl	$WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
 | 
						|
	jnc	1f
 | 
						|
	movl	pmode_cr4, %eax
 | 
						|
	movl	%eax, %cr4
 | 
						|
1:
 | 
						|
	btl	$WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
 | 
						|
	jnc	1f
 | 
						|
	movl	pmode_efer, %eax
 | 
						|
	movl	pmode_efer + 4, %edx
 | 
						|
	movl	$MSR_EFER, %ecx
 | 
						|
	wrmsr
 | 
						|
1:
 | 
						|
 | 
						|
	lgdtl	pmode_gdt
 | 
						|
 | 
						|
	/* This really couldn't... */
 | 
						|
	movl	pmode_entry, %eax
 | 
						|
	movl	pmode_cr0, %ecx
 | 
						|
	movl	%ecx, %cr0
 | 
						|
	ljmpl	$__KERNEL_CS, $pa_startup_32
 | 
						|
	/* -> jmp *%eax in trampoline_32.S */
 | 
						|
#else
 | 
						|
	jmp	trampoline_start
 | 
						|
#endif
 | 
						|
 | 
						|
bogus_real_magic:
 | 
						|
1:
 | 
						|
	hlt
 | 
						|
	jmp	1b
 | 
						|
 | 
						|
	.section ".rodata","a"
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Set up the wakeup GDT.  We set these up as Big Real Mode,
 | 
						|
	 * that is, with limits set to 4 GB.  At least the Lenovo
 | 
						|
	 * Thinkpad X61 is known to need this for the video BIOS
 | 
						|
	 * initialization quirk to work; this is likely to also
 | 
						|
	 * be the case for other laptops or integrated video devices.
 | 
						|
	 */
 | 
						|
 | 
						|
	.balign	16
 | 
						|
GLOBAL(wakeup_gdt)
 | 
						|
	.word	3*8-1		/* Self-descriptor */
 | 
						|
	.long	pa_wakeup_gdt
 | 
						|
	.word	0
 | 
						|
 | 
						|
	.word	0xffff		/* 16-bit code segment @ real_mode_base */
 | 
						|
	.long	0x9b000000 + pa_real_mode_base
 | 
						|
	.word	0x008f		/* big real mode */
 | 
						|
 | 
						|
	.word	0xffff		/* 16-bit data segment @ real_mode_base */
 | 
						|
	.long	0x93000000 + pa_real_mode_base
 | 
						|
	.word	0x008f		/* big real mode */
 | 
						|
END(wakeup_gdt)
 | 
						|
 | 
						|
	.section ".rodata","a"
 | 
						|
	.balign	8
 | 
						|
 | 
						|
	/* This is the standard real-mode IDT */
 | 
						|
	.balign	16
 | 
						|
GLOBAL(wakeup_idt)
 | 
						|
	.word	0xffff		/* limit */
 | 
						|
	.long	0		/* address */
 | 
						|
	.word	0
 | 
						|
END(wakeup_idt)
 |