blob: 9e7e14797a72dda0b85d4c70afca61fdb2fdf92e [file] [log] [blame]
Pavel Macheke44b7b72008-04-10 23:28:10 +02001/*
2 * ACPI wakeup real mode startup stub
3 */
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +03004#include <linux/linkage.h>
Pavel Macheke44b7b72008-04-10 23:28:10 +02005#include <asm/segment.h>
6#include <asm/msr-index.h>
Jeremy Fitzhardinge0341c142009-02-13 11:14:01 -08007#include <asm/page_types.h>
8#include <asm/pgtable_types.h>
H. Peter Anvin4b4f7282008-06-24 23:03:48 +02009#include <asm/processor-flags.h>
Jarkko Sakkinenc4845472012-05-08 21:22:42 +030010#include "realmode.h"
H. Peter Anvind1ee4332011-02-14 15:42:46 -080011#include "wakeup.h"
Pavel Macheke44b7b72008-04-10 23:28:10 +020012
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030013 .code16
Pavel Macheke44b7b72008-04-10 23:28:10 +020014
15/* This should match the structure in wakeup.h */
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030016 .section ".data", "aw"
17
18 .balign 16
19GLOBAL(wakeup_header)
20 video_mode: .short 0 /* Video mode number */
21 pmode_entry: .long 0
22 pmode_cs: .short __KERNEL_CS
23 pmode_cr0: .long 0 /* Saved %cr0 */
24 pmode_cr3: .long 0 /* Saved %cr3 */
25 pmode_cr4: .long 0 /* Saved %cr4 */
26 pmode_efer: .quad 0 /* Saved EFER */
27 pmode_gdt: .quad 0
28 pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
29 pmode_behavior: .long 0 /* Wakeup behavior flags */
30 realmode_flags: .long 0
31 real_magic: .long 0
32 signature: .long WAKEUP_HEADER_SIGNATURE
33END(wakeup_header)
Pavel Macheke44b7b72008-04-10 23:28:10 +020034
35 .text
Pavel Macheke44b7b72008-04-10 23:28:10 +020036 .code16
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030037
38 .balign 16
39ENTRY(wakeup_start)
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +030040 cli
Pavel Macheke44b7b72008-04-10 23:28:10 +020041 cld
42
H. Peter Anvine5684ec2012-05-08 21:22:37 +030043 LJMPW_RM(3f)
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +0300443:
H. Peter Anvin4b4f7282008-06-24 23:03:48 +020045 /* Apparently some dimwit BIOS programmers don't know how to
46 program a PM to RM transition, and we might end up here with
47 junk in the data segment descriptor registers. The only way
48 to repair that is to go into PM and fix it ourselves... */
49 movw $16, %cx
50 lgdtl %cs:wakeup_gdt
51 movl %cr0, %eax
52 orb $X86_CR0_PE, %al
53 movl %eax, %cr0
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +030054 ljmpw $8, $2f
H. Peter Anvin4b4f7282008-06-24 23:03:48 +0200552:
56 movw %cx, %ds
57 movw %cx, %es
58 movw %cx, %ss
59 movw %cx, %fs
60 movw %cx, %gs
61
62 andb $~X86_CR0_PE, %al
63 movl %eax, %cr0
H. Peter Anvine5684ec2012-05-08 21:22:37 +030064 LJMPW_RM(3f)
H. Peter Anvin4b4f7282008-06-24 23:03:48 +0200653:
Pavel Macheke44b7b72008-04-10 23:28:10 +020066 /* Set up segments */
67 movw %cs, %ax
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030068 movw %ax, %ss
69 movl $rm_stack_end, %esp
Pavel Macheke44b7b72008-04-10 23:28:10 +020070 movw %ax, %ds
71 movw %ax, %es
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030072 movw %ax, %fs
73 movw %ax, %gs
Pavel Macheke44b7b72008-04-10 23:28:10 +020074
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +030075 lidtl wakeup_idt
Pavel Macheke44b7b72008-04-10 23:28:10 +020076
H. Peter Anvin1396adc2012-10-01 14:34:42 -070077 /* Clear the EFLAGS */
H. Peter Anvin73201db2012-09-26 15:02:34 -070078 pushl $0
79 popfl
Pavel Macheke44b7b72008-04-10 23:28:10 +020080
81 /* Check header signature... */
82 movl signature, %eax
H. Peter Anvind1ee4332011-02-14 15:42:46 -080083 cmpl $WAKEUP_HEADER_SIGNATURE, %eax
Pavel Macheke44b7b72008-04-10 23:28:10 +020084 jne bogus_real_magic
85
86 /* Check we really have everything... */
87 movl end_signature, %eax
H. Peter Anvin61f54462012-05-21 00:02:45 -070088 cmpl $REALMODE_END_SIGNATURE, %eax
Pavel Macheke44b7b72008-04-10 23:28:10 +020089 jne bogus_real_magic
90
91 /* Call the C code */
92 calll main
93
Kees Cook7a313662011-07-06 18:10:34 -070094 /* Restore MISC_ENABLE before entering protected mode, in case
95 BIOS decided to clear XD_DISABLE during S3. */
H. Peter Anvin73201db2012-09-26 15:02:34 -070096 movl pmode_behavior, %edi
97 btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %edi
Kees Cook7a313662011-07-06 18:10:34 -070098 jnc 1f
99
100 movl pmode_misc_en, %eax
101 movl pmode_misc_en + 4, %edx
102 movl $MSR_IA32_MISC_ENABLE, %ecx
103 wrmsr
1041:
105
Pavel Macheke44b7b72008-04-10 23:28:10 +0200106 /* Do any other stuff... */
107
108#ifndef CONFIG_64BIT
109 /* This could also be done in C code... */
110 movl pmode_cr3, %eax
111 movl %eax, %cr3
112
H. Peter Anvin73201db2012-09-26 15:02:34 -0700113 btl $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi
H. Peter Anvin1396adc2012-10-01 14:34:42 -0700114 jnc 1f
H. Peter Anvin73201db2012-09-26 15:02:34 -0700115 movl pmode_cr4, %eax
116 movl %eax, %cr4
Pavel Macheke44b7b72008-04-10 23:28:10 +02001171:
H. Peter Anvin73201db2012-09-26 15:02:34 -0700118 btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi
H. Peter Anvin1396adc2012-10-01 14:34:42 -0700119 jnc 1f
Pavel Macheke44b7b72008-04-10 23:28:10 +0200120 movl pmode_efer, %eax
121 movl pmode_efer + 4, %edx
Brian Gerstcfaa71e2010-07-17 09:03:27 -0400122 movl $MSR_EFER, %ecx
Pavel Macheke44b7b72008-04-10 23:28:10 +0200123 wrmsr
1241:
125
126 lgdtl pmode_gdt
127
128 /* This really couldn't... */
H. Peter Anvin968ff9e2012-05-08 21:22:36 +0300129 movl pmode_entry, %eax
130 movl pmode_cr0, %ecx
131 movl %ecx, %cr0
132 ljmpl $__KERNEL_CS, $pa_startup_32
133 /* -> jmp *%eax in trampoline_32.S */
Pavel Macheke44b7b72008-04-10 23:28:10 +0200134#else
Jarkko Sakkinenf37240f2012-05-08 21:22:43 +0300135 jmp trampoline_start
Pavel Macheke44b7b72008-04-10 23:28:10 +0200136#endif
137
138bogus_real_magic:
1391:
140 hlt
141 jmp 1b
142
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +0300143 .section ".rodata","a"
144
145 /*
146 * Set up the wakeup GDT. We set these up as Big Real Mode,
147 * that is, with limits set to 4 GB. At least the Lenovo
148 * Thinkpad X61 is known to need this for the video BIOS
149 * initialization quirk to work; this is likely to also
150 * be the case for other laptops or integrated video devices.
151 */
152
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +0300153 .balign 16
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +0300154GLOBAL(wakeup_gdt)
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +0300155 .word 3*8-1 /* Self-descriptor */
156 .long pa_wakeup_gdt
157 .word 0
158
159 .word 0xffff /* 16-bit code segment @ real_mode_base */
160 .long 0x9b000000 + pa_real_mode_base
161 .word 0x008f /* big real mode */
162
163 .word 0xffff /* 16-bit data segment @ real_mode_base */
164 .long 0x93000000 + pa_real_mode_base
165 .word 0x008f /* big real mode */
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +0300166END(wakeup_gdt)
Jarkko Sakkinenc9b77cc2012-05-08 21:22:29 +0300167
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +0300168 .section ".rodata","a"
H. Peter Anvin4b4f7282008-06-24 23:03:48 +0200169 .balign 8
170
171 /* This is the standard real-mode IDT */
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +0300172 .balign 16
173GLOBAL(wakeup_idt)
H. Peter Anvin4b4f7282008-06-24 23:03:48 +0200174 .word 0xffff /* limit */
175 .long 0 /* address */
176 .word 0
Jarkko Sakkinen8e029fc2012-05-08 21:22:40 +0300177END(wakeup_idt)