acpi_wakecode.S revision 1.1.2.2 1 /* $NetBSD: acpi_wakecode.S,v 1.1.2.2 2007/09/06 23:09:08 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 /*
82 * Should not be needed, but... Note that we rely on the below code
83 * being copied to a 16-byte aligned address.
84 */
85 #define RELOC(x) x - wakeup_16
86
87 .text
88 .org 0
89
90 .align 16
91 .code16
92 wakeup_16:
93
94 nop
95 cli
96 cld
97
98 /* Set up segment registers for real mode */
99 movw %cs, %ax
100 movw %ax, %ds
101 movw %ax, %ss
102
103 /* Small call stack XXXAD Where is this? Is it in the ACPI spec? */
104 mov $0x1000, %sp
105
106 /* Clear flags */
107 pushl $0
108 popfl
109
110 /* Only beep on reset if machdep.acpi_beep_on_reset=1 */
111 cmpb $1, RELOC(beep_on_reset)
112 jne nobeepon
113 call beepon
114
115 nobeepon:
116
117 /* Only reset the VBIOS if machdep.acpi_vbios_reset=1 */
118 cmpb $1, RELOC(vbios_reset)
119 jne novbiosreset
120
121 /* Kick the VBIOS. */
122 lcall $0xc000, $3
123
124 /* Paranoid, restore segment registers. */
125 movw %cs, %ax
126 movw %ax, %ds
127 movw %ax, %ss
128
129 novbiosreset:
130
131 /* Only beep on reset if machdep.acpi_beep_on_reset=1 */
132 cmpb $1, RELOC(beep_on_reset)
133 jne nobeepoff
134 call beepoff
135
136 nobeepoff:
137
138 #ifdef WAKECODE_VERBOSE
139 movw $0xb800, %ax
140 movw %ax, %fs
141 movw $0x0200 + '0', %fs:(0x00)
142 #endif
143
144 /* Get physical address of the code */
145 mov %cs, %ax
146 movzx %ax, %esi
147 shll $4, %esi
148
149 /* Fill 16->32 address */
150 addl %esi, RELOC(wakeup_sw32)+2 /* 1b opcode, 1b prefix */
151 addl %esi, RELOC(wakeup_sw64)+1 /* 1b opcode */
152 addl %esi, RELOC(tmp_gdt)+2
153 addl %esi, RELOC(tmp_gdt64)+2
154 wbinvd /* flush uop/trace cache */
155 jmp 1f
156 1: jmp 1f
157 1:
158
159
160 #ifdef WAKECODE_VERBOSE
161 movw $0xb800, %ax
162 movw %ax, %fs
163 movw $0x0200 + '1', %fs:(0x02)
164 #endif
165
166 /* Load GDT, enable protected mode */
167 lgdtl RELOC(tmp_gdt)
168 movl %eax, %cr0
169 orb $CR0_PE, %al
170 movl %eax, %cr0
171
172 wakeup_sw32:
173
174 /* Switch to protected mode by intersegmental jump */
175 ljmpl $GSEL(GCODE_SEL,SEL_KPL), $(RELOC(wakeup_32))
176
177 .align 16
178 .code32
179 wakeup_32:
180
181 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
182 movw %ax, %ds
183 movw %ax, %ss
184 movw %ax, %es
185 movw %ax, %fs
186 movw %ax, %gs
187
188 movl $0x1000, %esp /* XXXJDM is this needed? */
189
190 #ifdef WAKECODE_VERBOSE
191 movw $0x0200 + '2', (0xb8004)
192 #endif
193
194 pushl $PSL_MBO
195 popfl
196
197 movl %cr4, %eax
198 orl $(CR4_PAE|CR4_OSFXSR|CR4_OSXMMEXCPT), %eax
199 movl %eax, %cr4
200
201 /* Set long mode enable in EFER and enable syscall extensions */
202 movl $MSR_EFER, %ecx
203 rdmsr
204 xorl %eax, %eax
205 orl $(EFER_LME|EFER_SCE), %eax
206 wrmsr
207
208 #ifdef WAKECODE_VERBOSE
209 movw $0x0200 + '3', (0xb8006)
210 #endif
211
212 movl (RELOC(tmp_pml4))(%esi), %ecx
213 movl %ecx, %cr3
214
215 #ifdef WAKECODE_VERBOSE
216 movw $0x0200 + '4', (0xb8008)
217 #endif
218
219 movl %cr0, %eax
220 orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP), %eax
221 movl %eax, %cr0
222 jmp compat
223 compat:
224
225 movb $0xc0, %al
226 outb %al, $0x42
227 movb $0x04, %al
228 outb %al, $0x42
229 inb $0x61, %al
230 orb $0x3, %al
231 outb %al, $0x61
232
233 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
234 movl %eax, %ds
235 movl %eax, %es
236 movl %eax, %ss
237
238 movw $0x0200 + '5', (0xb800a)
239
240 /* Load 64-bit GDT. */
241 lgdt (RELOC(tmp_gdt64))(%esi)
242
243 movw $0x0200 + '6', (0xb800c)
244
245 wakeup_sw64:
246
247 /* Jump to long mode segment. */
248 ljmpl $GSEL(GCODE_SEL,SEL_KPL), $(RELOC(wakeup_64))
249
250 .align 16
251 .code64
252 wakeup_64:
253
254 nop
255 nop
256
257 /* Re-initialize segment regsisters to be on the safe side. */
258 movl $GSEL(GDATA_SEL,SEL_KPL), %eax
259 movl %eax, %ds
260 movl %eax, %es
261 movl %eax, %gs
262 movl %eax, %ss
263 movl %eax, %fs
264
265 #ifdef WAKECODE_VERBOSE
266 movw $0x0200 + '7', (0xb800e)
267 #endif
268
269 movq previous_rsp(%rsi), %rsp
270
271 #ifdef WAKECODE_VERBOSE
272 movw $0x0200 + '8', (0xb8010)
273 #endif
274
275 #if 1 /* XXXAD ?? */
276 /* Fixup TSS type field; 386 busy TSS (11) -> 386 available TSS (9) */
277 #define TSS_TYPEFIX_MASK 0xf9
278 movq physical_gdt+2(%rsi), %rbx
279 movzxw previous_tr(%rsi), %rcx
280 leaq (%rbx,%rcx),%rax /* get TSS segment descriptor */
281 andb $TSS_TYPEFIX_MASK, 5(%rax)
282 #endif
283
284 #ifdef WAKECODE_VERBOSE
285 movw $0x0200 + '9', (0xb8012)
286 #endif
287
288 /* Restore registers */
289 lgdt previous_gdt(%rsi)
290 lidt previous_idt(%rsi)
291 lldt previous_ldt(%rsi)
292 #if 0
293 ltr previous_tr(%rsi)
294 #endif
295
296 #ifdef WAKECODE_VERBOSE
297 movw $0x0200 + 'a', (0xb8014)
298 #endif
299
300 movq previous_cr2(%rsi), %rax
301 movq %rax, %cr2
302 movq previous_cr3(%rsi), %rdx
303 movq previous_cr4(%rsi), %rax
304 movq %rax, %cr4
305
306 #ifdef WAKECODE_VERBOSE
307 movw $0x0200 + 'b', (0xb8016)
308 #endif
309
310 movw previous_es(%rsi), %ax
311 movw %ax, %es
312 movw previous_fs(%rsi), %ax
313 movw %ax, %fs
314 movw previous_gs(%rsi), %ax
315 movw %ax, %gs
316 movw previous_ss(%rsi), %ax
317 movw %ax, %ss
318 movq where_to_recover(%rsi), %rbx
319 movw previous_ds(%rsi), %ax
320
321 #ifdef WAKECODE_VERBOSE
322 movw $0x0200 + 'c', (0xb8018)
323 #endif
324
325 /* Re-enable paging, %rdx loaded above */
326 movq %rdx, %cr3
327 movq previous_cr0(%rsi), %rcx
328 movq %rcx, %cr0
329 jmp 1f
330 1: jmp 1f
331 1:
332
333 /* New address space active - reload %ds */
334 movw %ax, %ds
335 jmp *%rbx
336
337 beepon:
338 movb $0xc0, %al
339 outb %al, $0x42
340 movb $0x04, %al
341 outb %al, $0x42
342 inb $0x61, %al
343 orb $0x3, %al
344 outb %al, $0x61
345 ret
346
347 beepoff:
348 inb $0x61, %al
349 andb $0xfc, %al
350 outb %al, $0x61
351 ret
352
353 tmp_gdt:
354 .word 0xffff
355 .long RELOC(tmp_gdtable)
356
357 tmp_gdtable:
358 /* null */
359 .word 0, 0
360 .byte 0, 0, 0, 0
361 /* code */
362 .word 0xffff, 0
363 .byte 0, 0x9f, 0xcf, 0
364 /* data */
365 .word 0xffff, 0
366 .byte 0, 0x93, 0xcf, 0
367
368 tmp_gdt64:
369 .word 0xffff
370 .long RELOC(tmp_gdtable64)
371
372 tmp_gdtable64:
373 /* null */
374 .word 0, 0
375 .byte 0, 0, 0, 0
376 /* code */
377 .word 0xffff, 0
378 .byte 0, 0x9a, 0xaf, 0
379 /* data */
380 .word 0xffff, 0
381 .byte 0, 0x92, 0xcf, 0
382
383 .align 16, 0
384 physical_gdt: .word 0
385 .quad 0
386 previous_cr2: .quad 0
387 previous_cr3: .quad 0
388 previous_cr4: .quad 0
389 previous_cr0: .quad 0
390 previous_tr: .word 0
391 previous_gdt: .word 0
392 .quad 0
393 previous_ldt: .word 0
394 previous_idt: .word 0
395 .quad 0
396 previous_ds: .word 0
397 previous_es: .word 0
398 previous_fs: .word 0
399 previous_gs: .word 0
400 previous_ss: .word 0
401 previous_rsp: .quad 0
402 where_to_recover: .quad 0
403 tmp_pml4: .quad 0
404 vbios_reset: .byte 0
405 beep_on_reset: .byte 0
406