]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - arch/i386/kernel/acpi/wakeup.S
[PATCH] don't use flush_tlb_all in suspend time
[mirror_ubuntu-zesty-kernel.git] / arch / i386 / kernel / acpi / wakeup.S
1 .text
2 #include <linux/linkage.h>
3 #include <asm/segment.h>
4 #include <asm/page.h>
5
6 #
7 # wakeup_code runs in real mode, and at unknown address (determined at run-time).
8 # Therefore it must only use relative jumps/calls.
9 #
10 # Do we need to deal with A20? It is okay: ACPI specs says A20 must be enabled
11 #
12 # If physical address of wakeup_code is 0x12345, BIOS should call us with
13 # cs = 0x1234, eip = 0x05
14 #
15
16 ALIGN
17 .align 4096
18 ENTRY(wakeup_start)
19 wakeup_code:
20 wakeup_code_start = .
21 .code16
22
23 movw $0xb800, %ax
24 movw %ax,%fs
25 movw $0x0e00 + 'L', %fs:(0x10)
26
27 cli
28 cld
29
30 # setup data segment
31 movw %cs, %ax
32 movw %ax, %ds # Make ds:0 point to wakeup_start
33 movw %ax, %ss
34 mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
35 movw $0x0e00 + 'S', %fs:(0x12)
36
37 pushl $0 # Kill any dangerous flags
38 popfl
39
40 movl real_magic - wakeup_code, %eax
41 cmpl $0x12345678, %eax
42 jne bogus_real_magic
43
44 testl $1, video_flags - wakeup_code
45 jz 1f
46 lcall $0xc000,$3
47 movw %cs, %ax
48 movw %ax, %ds # Bios might have played with that
49 movw %ax, %ss
50 1:
51
52 testl $2, video_flags - wakeup_code
53 jz 1f
54 mov video_mode - wakeup_code, %ax
55 call mode_set
56 1:
57
58 # set up page table
59 movl $swsusp_pg_dir-__PAGE_OFFSET, %eax
60 movl %eax, %cr3
61
62 testl $1, real_efer_save_restore - wakeup_code
63 jz 4f
64 # restore efer setting
65 movl real_save_efer_edx - wakeup_code, %edx
66 movl real_save_efer_eax - wakeup_code, %eax
67 mov $0xc0000080, %ecx
68 wrmsr
69 4:
70 # make sure %cr4 is set correctly (features, etc)
71 movl real_save_cr4 - wakeup_code, %eax
72 movl %eax, %cr4
73 movw $0xb800, %ax
74 movw %ax,%fs
75 movw $0x0e00 + 'i', %fs:(0x12)
76
77 # need a gdt -- use lgdtl to force 32-bit operands, in case
78 # the GDT is located past 16 megabytes.
79 lgdtl real_save_gdt - wakeup_code
80
81 movl real_save_cr0 - wakeup_code, %eax
82 movl %eax, %cr0
83 jmp 1f
84 1:
85 movw $0x0e00 + 'n', %fs:(0x14)
86
87 movl real_magic - wakeup_code, %eax
88 cmpl $0x12345678, %eax
89 jne bogus_real_magic
90
91 ljmpl $__KERNEL_CS,$wakeup_pmode_return
92
93 real_save_gdt: .word 0
94 .long 0
95 real_save_cr0: .long 0
96 real_save_cr3: .long 0
97 real_save_cr4: .long 0
98 real_magic: .long 0
99 video_mode: .long 0
100 video_flags: .long 0
101 real_efer_save_restore: .long 0
102 real_save_efer_edx: .long 0
103 real_save_efer_eax: .long 0
104
105 bogus_real_magic:
106 movw $0x0e00 + 'B', %fs:(0x12)
107 jmp bogus_real_magic
108
109 /* This code uses an extended set of video mode numbers. These include:
110 * Aliases for standard modes
111 * NORMAL_VGA (-1)
112 * EXTENDED_VGA (-2)
113 * ASK_VGA (-3)
114 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
115 * of compatibility when extending the table. These are between 0x00 and 0xff.
116 */
117 #define VIDEO_FIRST_MENU 0x0000
118
119 /* Standard BIOS video modes (BIOS number + 0x0100) */
120 #define VIDEO_FIRST_BIOS 0x0100
121
122 /* VESA BIOS video modes (VESA number + 0x0200) */
123 #define VIDEO_FIRST_VESA 0x0200
124
125 /* Video7 special modes (BIOS number + 0x0900) */
126 #define VIDEO_FIRST_V7 0x0900
127
128 # Setting of user mode (AX=mode ID) => CF=success
129 mode_set:
130 movw %ax, %bx
131 #if 0
132 cmpb $0xff, %ah
133 jz setalias
134
135 testb $VIDEO_RECALC>>8, %ah
136 jnz _setrec
137
138 cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
139 jnc setres
140
141 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
142 jz setspc
143
144 cmpb $VIDEO_FIRST_V7>>8, %ah
145 jz setv7
146 #endif
147
148 cmpb $VIDEO_FIRST_VESA>>8, %ah
149 jnc check_vesa
150 #if 0
151 orb %ah, %ah
152 jz setmenu
153 #endif
154
155 decb %ah
156 # jz setbios Add bios modes later
157
158 setbad: clc
159 ret
160
161 check_vesa:
162 subb $VIDEO_FIRST_VESA>>8, %bh
163 orw $0x4000, %bx # Use linear frame buffer
164 movw $0x4f02, %ax # VESA BIOS mode set call
165 int $0x10
166 cmpw $0x004f, %ax # AL=4f if implemented
167 jnz _setbad # AH=0 if OK
168
169 stc
170 ret
171
172 _setbad: jmp setbad
173
174 .code32
175 ALIGN
176
177 .org 0x800
178 wakeup_stack_begin: # Stack grows down
179
180 .org 0xff0 # Just below end of page
181 wakeup_stack:
182 ENTRY(wakeup_end)
183
184 .org 0x1000
185
186 wakeup_pmode_return:
187 movw $__KERNEL_DS, %ax
188 movw %ax, %ss
189 movw %ax, %ds
190 movw %ax, %es
191 movw %ax, %fs
192 movw %ax, %gs
193 movw $0x0e00 + 'u', 0xb8016
194
195 # reload the gdt, as we need the full 32 bit address
196 lgdt saved_gdt
197 lidt saved_idt
198 lldt saved_ldt
199 ljmp $(__KERNEL_CS),$1f
200 1:
201 movl %cr3, %eax
202 movl %eax, %cr3
203 wbinvd
204
205 # and restore the stack ... but you need gdt for this to work
206 movl saved_context_esp, %esp
207
208 movl %cs:saved_magic, %eax
209 cmpl $0x12345678, %eax
210 jne bogus_magic
211
212 # jump to place where we left off
213 movl saved_eip,%eax
214 jmp *%eax
215
216 bogus_magic:
217 movw $0x0e00 + 'B', 0xb8018
218 jmp bogus_magic
219
220
221 ##
222 # acpi_copy_wakeup_routine
223 #
224 # Copy the above routine to low memory.
225 #
226 # Parameters:
227 # %eax: place to copy wakeup routine to
228 #
229 # Returned address is location of code in low memory (past data and stack)
230 #
231 ENTRY(acpi_copy_wakeup_routine)
232
233 sgdt saved_gdt
234 sidt saved_idt
235 sldt saved_ldt
236 str saved_tss
237
238 movl nx_enabled, %edx
239 movl %edx, real_efer_save_restore - wakeup_start (%eax)
240 testl $1, real_efer_save_restore - wakeup_start (%eax)
241 jz 2f
242 # save efer setting
243 pushl %eax
244 movl %eax, %ebx
245 mov $0xc0000080, %ecx
246 rdmsr
247 movl %edx, real_save_efer_edx - wakeup_start (%ebx)
248 movl %eax, real_save_efer_eax - wakeup_start (%ebx)
249 popl %eax
250 2:
251
252 movl %cr3, %edx
253 movl %edx, real_save_cr3 - wakeup_start (%eax)
254 movl %cr4, %edx
255 movl %edx, real_save_cr4 - wakeup_start (%eax)
256 movl %cr0, %edx
257 movl %edx, real_save_cr0 - wakeup_start (%eax)
258 sgdt real_save_gdt - wakeup_start (%eax)
259
260 movl saved_videomode, %edx
261 movl %edx, video_mode - wakeup_start (%eax)
262 movl acpi_video_flags, %edx
263 movl %edx, video_flags - wakeup_start (%eax)
264 movl $0x12345678, real_magic - wakeup_start (%eax)
265 movl $0x12345678, saved_magic
266 ret
267
268 .data
269 ALIGN
270 ENTRY(saved_magic) .long 0
271 ENTRY(saved_eip) .long 0
272
273 save_registers:
274 leal 4(%esp), %eax
275 movl %eax, saved_context_esp
276 movl %ebx, saved_context_ebx
277 movl %ebp, saved_context_ebp
278 movl %esi, saved_context_esi
279 movl %edi, saved_context_edi
280 pushfl ; popl saved_context_eflags
281
282 movl $ret_point, saved_eip
283 ret
284
285
286 restore_registers:
287 movl saved_context_ebp, %ebp
288 movl saved_context_ebx, %ebx
289 movl saved_context_esi, %esi
290 movl saved_context_edi, %edi
291 pushl saved_context_eflags ; popfl
292 ret
293
294 ENTRY(do_suspend_lowlevel)
295 call save_processor_state
296 call save_registers
297 pushl $3
298 call acpi_enter_sleep_state
299 addl $4, %esp
300 ret
301 .p2align 4,,7
302 ret_point:
303 call restore_registers
304 call restore_processor_state
305 ret
306
307 ALIGN
308 # saved registers
309 saved_gdt: .long 0,0
310 saved_idt: .long 0,0
311 saved_ldt: .long 0
312 saved_tss: .long 0
313