acpi_wakecode.S revision 1.1.2.1 1 /* $NetBSD: acpi_wakecode.S,v 1.1.2.1 2007/09/06 22:59:43 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 movw $0x0200 + '7', (0xb800e)
266
267 movq previous_rsp(%rsi), %rsp
268
269 movw $0x0200 + '8', (0xb8010)
270
271 #if 1 /* XXXAD ?? */
272 /* Fixup TSS type field; 386 busy TSS (11) -> 386 available TSS (9) */
273 #define TSS_TYPEFIX_MASK 0xf9
274 movq physical_gdt+2(%rsi), %rbx
275 movzxw previous_tr(%rsi), %rcx
276 leaq (%rbx,%rcx),%rax /* get TSS segment descriptor */
277 andb $TSS_TYPEFIX_MASK, 5(%rax)
278 #endif
279
280 movw $0x0200 + '9', (0xb8012)
281
282 /* Restore registers */
283 lgdt previous_gdt(%rsi)
284 lidt previous_idt(%rsi)
285 lldt previous_ldt(%rsi)
286 #if 0
287 ltr previous_tr(%rsi)
288 #endif
289
290 movw $0x0200 + 'a', (0xb8014)
291
292 movq previous_cr2(%rsi), %rax
293 movq %rax, %cr2
294 movq previous_cr3(%rsi), %rdx
295 movq previous_cr4(%rsi), %rax
296 movq %rax, %cr4
297
298 movw $0x0200 + 'b', (0xb8016)
299
300 movw previous_es(%rsi), %ax
301 movw %ax, %es
302 movw previous_fs(%rsi), %ax
303 movw %ax, %fs
304 movw previous_gs(%rsi), %ax
305 movw %ax, %gs
306 movw previous_ss(%rsi), %ax
307 movw %ax, %ss
308 movq where_to_recover(%rsi), %rbx
309 movw previous_ds(%rsi), %ax
310
311 movw $0x0200 + 'c', (0xb8018)
312
313 /* Re-enable paging, %rdx loaded above */
314 movq %rdx, %cr3
315 movq previous_cr0(%rsi), %rcx
316 movq %rcx, %cr0
317 jmp 1f
318 1: jmp 1f
319 1:
320
321 /* New address space active - reload %ds */
322 movw %ax, %ds
323 jmp *%rbx
324
325 beepon:
326 movb $0xc0, %al
327 outb %al, $0x42
328 movb $0x04, %al
329 outb %al, $0x42
330 inb $0x61, %al
331 orb $0x3, %al
332 outb %al, $0x61
333 ret
334
335 beepoff:
336 inb $0x61, %al
337 andb $0xfc, %al
338 outb %al, $0x61
339 ret
340
341 tmp_gdt:
342 .word 0xffff
343 .long RELOC(tmp_gdtable)
344
345 tmp_gdtable:
346 /* null */
347 .word 0, 0
348 .byte 0, 0, 0, 0
349 /* code */
350 .word 0xffff, 0
351 .byte 0, 0x9f, 0xcf, 0
352 /* data */
353 .word 0xffff, 0
354 .byte 0, 0x93, 0xcf, 0
355
356 tmp_gdt64:
357 .word 0xffff
358 .long RELOC(tmp_gdtable64)
359
360 tmp_gdtable64:
361 /* null */
362 .word 0, 0
363 .byte 0, 0, 0, 0
364 /* code */
365 .word 0xffff, 0
366 .byte 0, 0x9a, 0xaf, 0
367 /* data */
368 .word 0xffff, 0
369 .byte 0, 0x92, 0xcf, 0
370
371 .align 16, 0
372 physical_gdt: .word 0
373 .quad 0
374 previous_cr2: .quad 0
375 previous_cr3: .quad 0
376 previous_cr4: .quad 0
377 previous_cr0: .quad 0
378 previous_tr: .word 0
379 previous_gdt: .word 0
380 .quad 0
381 previous_ldt: .word 0
382 previous_idt: .word 0
383 .quad 0
384 previous_ds: .word 0
385 previous_es: .word 0
386 previous_fs: .word 0
387 previous_gs: .word 0
388 previous_ss: .word 0
389 previous_rsp: .quad 0
390 where_to_recover: .quad 0
391 tmp_pml4: .quad 0
392 vbios_reset: .byte 0
393 beep_on_reset: .byte 0
394