acpi_wakecode.S revision 1.1.2.3 1 /* $NetBSD: acpi_wakecode.S,v 1.1.2.3 2007/09/07 21:01:03 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Takuya SHIOZAKI, and by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39
40 /*
41 * This code is derived from FreeBSD. Original copyrights:
42 *
43 * Copyright (c) 2001 Takanori Watanabe <takawata (at) jp.freebsd.org>
44 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki (at) jp.freebsd.org>
45 * All rights reserved.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * FreeBSD: src/sys/i386/acpica/acpi_wakecode.S,v 1.1 2001/07/20 06:07:31 takawata Exp
69 */
70
71 #define _LOCORE
72
73 #define WAKECODE_VERBOSE
74
75 #include <machine/asm.h>
76 #include <machine/specialreg.h>
77 #include <machine/param.h>
78 #include <machine/segments.h>
79 #include <machine/psl.h>
80
81 .text
82 .code16
83 .org 0
84 .globl wakeup_16
85 wakeup_16:
86 nop
87 cli
88 cld
89
90 /* Set up segment registers for real mode */
91 movw %cs, %ax
92 movw %ax, %ds
93 movw %ax, %ss
94
95 /* Small call stack XXXAD Where is this? Is it in the ACPI spec? */
96 mov $0x1000, %sp
97
98 /* Clear flags */
99 pushl $0
100 popfl
101
102 /* Only beep on reset if machdep.acpi_beep_on_reset=1 */
103 cmpb $1, beep_on_reset
104 jne nobeepon
105 call beepon
106
107 nobeepon:
108
109 /* Only reset the VBIOS if machdep.acpi_vbios_reset=1 */
110 cmpb $1, vbios_reset
111 jne novbiosreset
112
113 /* Kick the VBIOS. */
114 lcall $0xc000, $3
115
116 /* Paranoid, restore segment registers. */
117 movw %cs, %ax
118 movw %ax, %ds
119 movw %ax, %ss
120
121 novbiosreset:
122
123 /* Only beep on reset if machdep.acpi_beep_on_reset=1 */
124 cmpb $1, beep_on_reset
125 jne nobeepoff
126 call beepoff
127
128 nobeepoff:
129
130 #ifdef WAKECODE_VERBOSE
131 movw $0xb800, %ax
132 movw %ax, %fs
133 movw $0x0200 + '0', %fs:(0x00)
134 #endif
135
136 /* Get physical address of the code */
137 mov %cs, %ax
138 movzx %ax, %esi
139 shll $4, %esi
140
141 /* Fill 16->32 address */
142 addl %esi, wakeup_sw32+2 /* 1b opcode, 1b prefix */
143 addl %esi, wakeup_sw64+1 /* 1b opcode */
144 addl %esi, tmp_gdt+2
145 addl %esi, tmp_gdt64+2
146 wbinvd /* flush uop/trace cache */
147 jmp 1f
148 1: jmp 1f
149 1:
150
151
152 #ifdef WAKECODE_VERBOSE
153 movw $0xb800, %ax
154 movw %ax, %fs
155 movw $0x0200 + '1', %fs:(0x02)
156 #endif
157
158 /* Load GDT, enable protected mode */
159 lgdt tmp_gdt
160
161 /* Enable protected mode */
162 movl %eax, %cr0
163 orb $(CR0_PE), %al
164 movl %eax, %cr0
165
166 wakeup_sw32:
167
168 /* Switch to protected mode by intersegmental jump */
169 ljmpl $GSEL(GCODE_SEL,SEL_KPL), $wakeup_32
170
171 .align 16
172 .code32
173 wakeup_32:
174
175 nop
176 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
177 movw %ax, %ds
178 movw %ax, %ss
179 movw %ax, %es
180 movw %ax, %fs
181 movw %ax, %gs
182
183 movl $0x1000, %esp /* XXXJDM is this needed? */
184
185 #ifdef WAKECODE_VERBOSE
186 movw $0x0200 + '2', (0xb8004)
187 #endif
188
189 pushl $PSL_MBO
190 popfl
191
192 movl %cr4, %eax
193 orl $(CR4_PAE|CR4_OSFXSR|CR4_OSXMMEXCPT), %eax
194 movl %eax, %cr4
195
196 /* Set long mode enable in EFER and enable syscall extensions */
197 movl $MSR_EFER, %ecx
198 rdmsr
199 xorl %eax, %eax
200 orl $(EFER_LME|EFER_SCE), %eax
201 wrmsr
202
203 #ifdef WAKECODE_VERBOSE
204 movw $0x0200 + '3', (0xb8006)
205 #endif
206
207 movl tmp_pml4(%esi), %ecx
208 movl %ecx, %cr3
209
210 #ifdef WAKECODE_VERBOSE
211 movw $0x0200 + '4', (0xb8008)
212 #endif
213
214 movl %cr0, %eax
215 orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP), %eax
216 movl %eax, %cr0
217 jmp compat
218 compat:
219
220 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
221 movl %eax, %ds
222 movl %eax, %es
223 movl %eax, %ss
224
225 movw $0x0200 + '5', (0xb800a)
226
227 /* Load 64-bit GDT. */
228 lgdt tmp_gdt64(%esi)
229
230 movw $0x0200 + '6', (0xb800c)
231
232 wakeup_sw64:
233
234 /* Jump to long mode segment. */
235 ljmpl $GSEL(GCODE_SEL,SEL_KPL), $wakeup_64
236
237 .align 16
238 .code64
239 wakeup_64:
240
241 nop
242 nop
243
244 /* Re-initialize segment regsisters to be on the safe side. */
245 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
246 movl %eax, %ds
247 movl %eax, %es
248 movl %eax, %gs
249 movl %eax, %ss
250 movl %eax, %fs
251
252 #ifdef WAKECODE_VERBOSE
253 movw $0x0200 + '7', (0xb800e)
254 #endif
255
256 movq previous_rsp(%rsi), %rsp
257
258 #ifdef WAKECODE_VERBOSE
259 movw $0x0200 + '8', (0xb8010)
260 #endif
261
262 #if 1 /* XXXAD ?? */
263 /* Fixup TSS type field; 386 busy TSS (11) -> 386 available TSS (9) */
264 #define TSS_TYPEFIX_MASK 0xf9
265 movq physical_gdt+2(%rsi), %rbx
266 movzxw previous_tr(%rsi), %rcx
267 leaq (%rbx,%rcx),%rax /* get TSS segment descriptor */
268 andb $TSS_TYPEFIX_MASK, 5(%rax)
269 #endif
270
271 #ifdef WAKECODE_VERBOSE
272 movw $0x0200 + '9', (0xb8012)
273 #endif
274
275 /* Restore registers */
276 lgdt previous_gdt(%rsi)
277 lidt previous_idt(%rsi)
278 lldt previous_ldt(%rsi)
279 #if 0
280 ltr previous_tr(%rsi)
281 #endif
282
283 #ifdef WAKECODE_VERBOSE
284 movw $0x0200 + 'a', (0xb8014)
285 #endif
286
287 movq previous_cr2(%rsi), %rax
288 movq %rax, %cr2
289 movq previous_cr3(%rsi), %rdx
290 movq previous_cr4(%rsi), %rax
291 movq %rax, %cr4
292
293 #ifdef WAKECODE_VERBOSE
294 movw $0x0200 + 'b', (0xb8016)
295 #endif
296
297 movw previous_es(%rsi), %ax
298 movw %ax, %es
299 movw previous_fs(%rsi), %ax
300 movw %ax, %fs
301 movw previous_gs(%rsi), %ax
302 movw %ax, %gs
303 movw previous_ss(%rsi), %ax
304 movw %ax, %ss
305 movq where_to_recover(%rsi), %rbx
306 movw previous_ds(%rsi), %ax
307
308 #ifdef WAKECODE_VERBOSE
309 movw $0x0200 + 'c', (0xb8018)
310 #endif
311
312 /* Re-enable paging, %rdx loaded above */
313 movq %rdx, %cr3
314 movq previous_cr0(%rsi), %rcx
315 movq %rcx, %cr0
316 jmp 1f
317 1: jmp 1f
318 1:
319
320 /* New address space active - reload %ds */
321 movw %ax, %ds
322 jmp *%rbx
323
324 beepon:
325 movb $0xc0, %al
326 outb %al, $0x42
327 movb $0x04, %al
328 outb %al, $0x42
329 inb $0x61, %al
330 orb $0x3, %al
331 outb %al, $0x61
332 ret
333
334 beepoff:
335 inb $0x61, %al
336 andb $0xfc, %al
337 outb %al, $0x61
338 ret
339
340 tmp_gdt:
341 .word 0xffff
342 .long tmp_gdtable
343
344 tmp_gdtable:
345 /* null */
346 .word 0, 0
347 .byte 0, 0, 0, 0
348 /* code */
349 .word 0xffff, 0
350 .byte 0, 0x9f, 0xcf, 0
351 /* data */
352 .word 0xffff, 0
353 .byte 0, 0x93, 0xcf, 0
354
355 tmp_gdt64:
356 .word 0xffff
357 .long tmp_gdtable64
358
359 tmp_gdtable64:
360 /* null */
361 .word 0, 0
362 .byte 0, 0, 0, 0
363 /* code */
364 .word 0xffff, 0
365 .byte 0, 0x9a, 0xaf, 0
366 /* data */
367 .word 0xffff, 0
368 .byte 0, 0x92, 0xcf, 0
369
370 .align 16, 0
371 .global WAKEUP_physical_gdt
372 WAKEUP_physical_gdt:
373 physical_gdt: .word 0
374 .quad 0
375 .global WAKEUP_previous_cr2
376 WAKEUP_previous_cr2:
377 previous_cr2: .quad 0
378 .global WAKEUP_previous_cr3
379 WAKEUP_previous_cr3:
380 previous_cr3: .quad 0
381 .global WAKEUP_previous_cr4
382 WAKEUP_previous_cr4:
383 previous_cr4: .quad 0
384 .global WAKEUP_previous_cr0
385 WAKEUP_previous_cr0:
386 previous_cr0: .quad 0
387 .global WAKEUP_previous_tr
388 WAKEUP_previous_tr:
389 previous_tr: .word 0
390 .global WAKEUP_previous_gdt
391 WAKEUP_previous_gdt:
392 previous_gdt: .word 0
393 .quad 0
394 .global WAKEUP_previous_ldt
395 WAKEUP_previous_ldt:
396 previous_ldt: .word 0
397 .global WAKEUP_previous_idt
398 WAKEUP_previous_idt:
399 previous_idt: .word 0
400 .quad 0
401 .global WAKEUP_previous_ds
402 WAKEUP_previous_ds:
403 previous_ds: .word 0
404 .global WAKEUP_previous_es
405 WAKEUP_previous_es:
406 previous_es: .word 0
407 .global WAKEUP_previous_fs
408 WAKEUP_previous_fs:
409 previous_fs: .word 0
410 .global WAKEUP_previous_gs
411 WAKEUP_previous_gs:
412 previous_gs: .word 0
413 .global WAKEUP_previous_ss
414 WAKEUP_previous_ss:
415 previous_ss: .word 0
416 .global WAKEUP_previous_rsp
417 WAKEUP_previous_rsp:
418 previous_rsp: .quad 0
419 .global WAKEUP_where_to_recover
420 WAKEUP_where_to_recover:
421 where_to_recover: .quad 0
422 .global WAKEUP_tmp_pml4
423 WAKEUP_tmp_pml4:
424 tmp_pml4: .quad 0
425 .global WAKEUP_vbios_reset
426 WAKEUP_vbios_reset:
427 vbios_reset: .byte 0
428 .global WAKEUP_beep_on_reset
429 WAKEUP_beep_on_reset:
430 beep_on_reset: .byte 0
431