acpi_wakecode.S revision 159409
1/*-
2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 159409 2006-06-08 17:54:10Z njl $
28 */
29
30#define LOCORE
31
32#include <machine/asmacros.h>
33#include <machine/specialreg.h>
34
35#include "assym.s"
36
37	.align 4096
38	.code16
39wakeup_16:
40	nop
41	cli
42
43	/*
44	 * Set up segment registers for real mode and a small stack for
45	 * any calls we make.
46	 */
47	movw	%cs,%ax
48	movw	%ax,%ds
49	movw	%ax,%ss
50	movw	$PAGE_SIZE,%sp
51
52	/* To debug resume hangs, beep the speaker if the user requested. */
53	cmpl	$1,resume_beep
54	jne	nobeep
55	movb	$0xc0,%al
56	outb	%al,$0x42
57	movb	$0x04,%al
58	outb	%al,$0x42
59	inb	$0x61,%al
60	orb	$0x3,%al
61	outb	%al,$0x61
62nobeep:
63
64	/* Re-initialize video BIOS if the reset_video tunable is set. */
65	cmpl	$1,reset_video
66	jne	nobiosreset
67	lcall	$0xc000,$3
68
69	/*
70	 * Set up segment registers for real mode again in case the
71	 * previous BIOS call clobbers them.
72	 */
73	movw	%cs,%ax
74	movw	%ax,%ds
75	movw	%ax,%ss
76nobiosreset:
77
78	/* Load GDT for real mode */
79	lgdt	physical_gdt
80
81	/* Restore CR2, CR3 and CR4 */
82	mov	previous_cr2,%eax
83	mov	%eax,%cr2
84	mov	previous_cr3,%eax
85	mov	%eax,%cr3
86	mov	previous_cr4,%eax
87	mov	%eax,%cr4
88
89	/* Transfer some values to protected mode */
90#define NVALUES	9
91#define TRANSFER_STACK32(val, idx)	\
92	mov	val,%eax;		\
93	mov	%eax,wakeup_32stack+(idx+1)+(idx*4);
94
95	TRANSFER_STACK32(previous_ss,		(NVALUES - 9))
96	TRANSFER_STACK32(previous_fs,		(NVALUES - 8))
97	TRANSFER_STACK32(previous_ds,		(NVALUES - 7))
98	TRANSFER_STACK32(physical_gdt+2,	(NVALUES - 6))
99	TRANSFER_STACK32(where_to_recover,	(NVALUES - 5))
100	TRANSFER_STACK32(previous_idt+2,	(NVALUES - 4))
101	TRANSFER_STACK32(previous_ldt,		(NVALUES - 3))
102	TRANSFER_STACK32(previous_gdt+2,	(NVALUES - 2))
103	TRANSFER_STACK32(previous_tr,		(NVALUES - 1))
104	TRANSFER_STACK32(previous_cr0,		(NVALUES - 0))
105
106	mov	physical_esp,%esi	/* to be used in 32bit code */
107
108	/* Enable protected mode */
109	mov	%cr0,%eax
110	orl	$(CR0_PE),%eax
111	mov	%eax,%cr0
112
113wakeup_sw32:
114	/* Switch to protected mode by intersegmental jump */
115	ljmpl	$KCSEL,$0x12345678	/* Code location, to be replaced */
116
117	.code32
118wakeup_32:
119	/*
120	 * Switched to protected mode w/o paging
121	 *	%esi:	KERNEL stack pointer (physical address)
122	 */
123
124	nop
125
126	/* Set up segment registers for protected mode */
127	movw	$KDSEL,%ax		/* KDSEL to segment registers */
128	movw	%ax,%ds
129	movw	%ax,%es
130	movw	%ax,%gs
131	movw	%ax,%ss
132	movw	$KPSEL,%ax		/* KPSEL to %fs */
133	movw	%ax,%fs
134	movl	%esi,%esp		/* physical address stack pointer */
135
136wakeup_32stack:
137	/* Operands are overwritten in 16bit code */
138	pushl	$0xabcdef09		/* ss + dummy */
139	pushl	$0xabcdef08		/* fs + gs */
140	pushl	$0xabcdef07		/* ds + es */
141	pushl	$0xabcdef06		/* gdt:base (physical address) */
142	pushl	$0xabcdef05		/* recover address */
143	pushl	$0xabcdef04		/* idt:base */
144	pushl	$0xabcdef03		/* ldt + idt:limit */
145	pushl	$0xabcdef02		/* gdt:base */
146	pushl	$0xabcdef01		/* TR + gdt:limit */
147	pushl	$0xabcdef00		/* CR0 */
148
149	movl	%esp,%ebp
150#define CR0_REGISTER		0(%ebp)
151#define TASK_REGISTER		4(%ebp)
152#define PREVIOUS_GDT		6(%ebp)
153#define PREVIOUS_LDT		12(%ebp)
154#define PREVIOUS_IDT		14(%ebp)
155#define RECOVER_ADDR		20(%ebp)
156#define PHYSICAL_GDT_BASE	24(%ebp)
157#define PREVIOUS_DS		28(%ebp)
158#define PREVIOUS_ES		30(%ebp)
159#define PREVIOUS_FS		32(%ebp)
160#define PREVIOUS_GS		34(%ebp)
161#define PREVIOUS_SS		36(%ebp)
162
163	/* Fixup TSS type field */
164#define TSS_TYPEFIX_MASK	0xf9
165	xorl	%esi,%esi
166	movl	PHYSICAL_GDT_BASE,%ebx
167	movw	TASK_REGISTER,%si
168	leal	(%ebx,%esi),%eax	/* get TSS segment descriptor */
169	andb	$TSS_TYPEFIX_MASK,5(%eax)
170
171	/* Prepare to return to sleep/wakeup code point */
172	lgdt	PREVIOUS_GDT
173	lidt	PREVIOUS_IDT
174
175	xorl	%eax,%eax
176	movl	%eax,%ebx
177	movl	%eax,%ecx
178	movl	%eax,%edx
179	movl	%eax,%esi
180	movl	%eax,%edi
181	movl	PREVIOUS_DS,%ebx
182	movl	PREVIOUS_FS,%ecx
183	movl	PREVIOUS_SS,%edx
184	movw	TASK_REGISTER,%si
185	shll	$16,%esi
186	movw	PREVIOUS_LDT,%si
187	movl	RECOVER_ADDR,%edi
188
189	/* Enable paging and etc. */
190	movl	CR0_REGISTER,%eax
191	movl	%eax,%cr0
192
193	/* Flush the prefetch queue */
194	jmp	1f
1951:	jmp	1f
1961:
197	/*
198	 * Now that we are in kernel virtual memory addressing
199	 *	%ebx:	ds + es
200	 *	%ecx:	fs + gs
201	 *	%edx:	ss + dummy
202	 *	%esi:	LDTR + TR
203	 *	%edi:	recover address
204	 */
205
206	nop
207
208	movl	%esi,%eax		/* LDTR + TR */
209	lldt	%ax			/* load LDT register */
210	shrl	$16,%eax
211	ltr	%ax			/* load task register */
212
213	/* Restore segment registers */
214	movl	%ebx,%eax		/* ds + es */
215	movw	%ax,%ds
216	shrl	$16,%eax
217	movw	%ax,%es
218	movl	%ecx,%eax		/* fs + gs */
219	movw	%ax,%fs
220	shrl	$16,%eax
221	movw	%ax,%gs
222	movl	%edx,%eax		/* ss */
223	movw	%ax,%ss
224
225	/* Jump to acpi_restorecpu() */
226	jmp	*%edi
227
228/* used in real mode */
229physical_gdt:		.word 0
230			.long 0
231physical_esp:		.long 0
232previous_cr2:		.long 0
233previous_cr3:		.long 0
234previous_cr4:		.long 0
235resume_beep:		.long 0
236reset_video:		.long 0
237
238/* transfer from real mode to protected mode */
239previous_cr0:		.long 0
240previous_tr:		.word 0
241previous_gdt:		.word 0
242			.long 0
243previous_ldt:		.word 0
244previous_idt:		.word 0
245			.long 0
246where_to_recover:	.long 0
247previous_ds:		.word 0
248previous_es:		.word 0
249previous_fs:		.word 0
250previous_gs:		.word 0
251previous_ss:		.word 0
252dummy:			.word 0
253