acpi_wakecode.S revision 121743
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
28#include <machine/asm.h>
29__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 121743 2003-10-30 16:14:55Z iwasaki $");
30
31#define LOCORE
32
33#include <machine/specialreg.h>
34
35	.align 4
36	.code16
37wakeup_16:
38	nop
39	cli
40
41	/* Set up segment registers for real mode */
42	movw	%cs,%ax
43	movw	%ax,%ds
44	movw	%ax,%ss
45
46#ifndef ACPI_NO_RESET_VIDEO
47	/*
48	 * Re-initialize video BIOS.  Restore DS and SS from CS in
49	 * case the BIOS modified them.
50	 */
51	cmp	$1, no_reset_video
52	je	wakeup_16_gdt
53	lcall	$0xc000, $3
54	movw	%cs, %ax
55	movw	%ax, %ds
56	movw	%ax, %ss
57#endif
58
59wakeup_16_gdt:
60	/* Load GDT for real mode */
61	lgdt	physical_gdt
62
63	/* Restore CR2, CR3 and CR4 */
64	mov	previous_cr2,%eax
65	mov	%eax,%cr2
66	mov	previous_cr3,%eax
67	mov	%eax,%cr3
68	mov	previous_cr4,%eax
69	mov	%eax,%cr4
70
71	/* Transfer some values to protected mode */
72#define NVALUES	9
73#define TRANSFER_STACK32(val, idx)	\
74	mov	val,%eax;		\
75	mov	%eax,wakeup_32stack+(idx+1)+(idx*4);
76
77	TRANSFER_STACK32(previous_ss,		(NVALUES - 9))
78	TRANSFER_STACK32(previous_fs,		(NVALUES - 8))
79	TRANSFER_STACK32(previous_ds,		(NVALUES - 7))
80	TRANSFER_STACK32(physical_gdt+2,	(NVALUES - 6))
81	TRANSFER_STACK32(where_to_recover,	(NVALUES - 5))
82	TRANSFER_STACK32(previous_idt+2,	(NVALUES - 4))
83	TRANSFER_STACK32(previous_ldt,		(NVALUES - 3))
84	TRANSFER_STACK32(previous_gdt+2,	(NVALUES - 2))
85	TRANSFER_STACK32(previous_tr,		(NVALUES - 1))
86	TRANSFER_STACK32(previous_cr0,		(NVALUES - 0))
87
88	mov	physical_esp,%esi	/* to be used in 32bit code */
89
90	/* Enable protected mode */
91	mov	%cr0,%eax
92	orl	$(CR0_PE),%eax
93	mov	%eax,%cr0
94
95wakeup_sw32:
96	/* Switch to protected mode by intersegmental jump */
97	ljmpl	$0x8,$0x12345678	/* Code location, to be replaced */
98
99	.code32
100wakeup_32:
101	/*
102	 * Switched to protected mode w/o paging
103	 *	%esi:	KERNEL stack pointer (physical address)
104	 */
105
106	nop
107
108	/* Set up segment registers for protected mode */
109	movw	$0x10,%ax		/* KDSEL to segment registers */
110	movw	%ax,%ds
111	movw	%ax,%es
112	movw	%ax,%gs
113	movw	%ax,%ss
114	movw	$0x18,%ax		/* KPSEL to %fs */
115	movw	%ax,%fs
116	movl	%esi,%esp		/* physical address stack pointer */
117
118wakeup_32stack:
119	/* Operands are overwritten in 16bit code */
120	pushl	$0xabcdef09		/* ss + dummy */
121	pushl	$0xabcdef08		/* fs + gs */
122	pushl	$0xabcdef07		/* ds + es */
123	pushl	$0xabcdef06		/* gdt:base (physical address) */
124	pushl	$0xabcdef05		/* recover address */
125	pushl	$0xabcdef04		/* idt:base */
126	pushl	$0xabcdef03		/* ldt + idt:limit */
127	pushl	$0xabcdef02		/* gdt:base */
128	pushl	$0xabcdef01		/* TR + gdt:limit */
129	pushl	$0xabcdef00		/* CR0 */
130
131	movl	%esp,%ebp
132#define CR0_REGISTER		0(%ebp)
133#define TASK_REGISTER		4(%ebp)
134#define PREVIOUS_GDT		6(%ebp)
135#define PREVIOUS_LDT		12(%ebp)
136#define PREVIOUS_IDT		14(%ebp)
137#define RECOVER_ADDR		20(%ebp)
138#define PHYSICAL_GDT_BASE	24(%ebp)
139#define PREVIOUS_DS		28(%ebp)
140#define PREVIOUS_ES		30(%ebp)
141#define PREVIOUS_FS		32(%ebp)
142#define PREVIOUS_GS		34(%ebp)
143#define PREVIOUS_SS		36(%ebp)
144
145	/* Fixup TSS type field */
146#define TSS_TYPEFIX_MASK	0xf9
147	xorl	%esi,%esi
148	movl	PHYSICAL_GDT_BASE,%ebx
149	movw	TASK_REGISTER,%si
150	leal	(%ebx,%esi),%eax	/* get TSS segment descriptor */
151	andb	$TSS_TYPEFIX_MASK,5(%eax)
152
153	/* Prepare to return to sleep/wakeup code point */
154	lgdt	PREVIOUS_GDT
155	lidt	PREVIOUS_IDT
156
157	xorl	%eax,%eax
158	movl	%eax,%ebx
159	movl	%eax,%ecx
160	movl	%eax,%edx
161	movl	%eax,%esi
162	movl	%eax,%edi
163	movl	PREVIOUS_DS,%ebx
164	movl	PREVIOUS_FS,%ecx
165	movl	PREVIOUS_SS,%edx
166	movw	TASK_REGISTER,%si
167	shll	$16,%esi
168	movw	PREVIOUS_LDT,%si
169	movl	RECOVER_ADDR,%edi
170
171	/* Enable paging and etc. */
172	movl	CR0_REGISTER,%eax
173	movl	%eax,%cr0
174
175	/* Flush the prefetch queue */
176	jmp	1f
1771:	jmp	1f
1781:
179	/*
180	 * Now that we are in kernel virtual memory addressing
181	 *	%ebx:	ds + es
182	 *	%ecx:	fs + gs
183	 *	%edx:	ss + dummy
184	 *	%esi:	LDTR + TR
185	 *	%edi:	recover address
186	 */
187
188	nop
189
190	movl	%esi,%eax		/* LDTR + TR */
191	lldt	%ax			/* load LDT register */
192	shrl	$16,%eax
193	ltr	%ax			/* load task register */
194
195	/* Restore segment registers */
196	movl	%ebx,%eax		/* ds + es */
197	movw	%ax,%ds
198	shrl	$16,%eax
199	movw	%ax,%es
200	movl	%ecx,%eax		/* fs + gs */
201	movw	%ax,%fs
202	shrl	$16,%eax
203	movw	%ax,%gs
204	movl	%edx,%eax		/* ss */
205	movw	%ax,%ss
206
207	/* Jump to acpi_restorecpu() */
208	jmp	*%edi
209
210/* used in real mode */
211physical_gdt:		.word 0
212			.long 0
213physical_esp:		.long 0
214previous_cr2:		.long 0
215previous_cr3:		.long 0
216previous_cr4:		.long 0
217no_reset_video:		.long 0
218
219/* transfer from real mode to protected mode */
220previous_cr0:		.long 0
221previous_tr:		.word 0
222previous_gdt:		.word 0
223			.long 0
224previous_ldt:		.word 0
225previous_idt:		.word 0
226			.long 0
227where_to_recover:	.long 0
228previous_ds:		.word 0
229previous_es:		.word 0
230previous_fs:		.word 0
231previous_gs:		.word 0
232previous_ss:		.word 0
233dummy:			.word 0
234