acpi_wakecode.S revision 121603
1117397Skan/*-
2117397Skan * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3117397Skan * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4117397Skan * All rights reserved.
5117397Skan *
6117397Skan * Redistribution and use in source and binary forms, with or without
7117397Skan * modification, are permitted provided that the following conditions
8117397Skan * are met:
9117397Skan * 1. Redistributions of source code must retain the above copyright
10117397Skan *    notice, this list of conditions and the following disclaimer.
11117397Skan * 2. Redistributions in binary form must reproduce the above copyright
12117397Skan *    notice, this list of conditions and the following disclaimer in the
13117397Skan *    documentation and/or other materials provided with the distribution.
14117397Skan *
15117397Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117397Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117397Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18169691Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19117397Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20117397Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21117397Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117397Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23117397Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24117397Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25117397Skan * SUCH DAMAGE.
26117397Skan */
27117397Skan
28117397Skan#include <machine/asm.h>
29117397Skan__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 121603 2003-10-27 06:26:51Z njl $");
30169691Skan
31169691Skan#define LOCORE
32169691Skan
33169691Skan#include <machine/specialreg.h>
34169691Skan
35117397Skan	.align 4
36117397Skan	.code16
37117397Skanwakeup_16:
38117397Skan	nop
39117397Skan	cli
40117397Skan
41117397Skan	/* Set up segment registers for real mode */
42169691Skan	movw	%cs,%ax
43169691Skan	movw	%ax,%ds
44117397Skan	movw	%ax,%ss
45117397Skan
46117397Skan	/*
47117397Skan	 * Re-initialize video BIOS.  Restore DS and SS from CS in
48117397Skan	 * case the BIOS modified them.
49117397Skan	 */
50117397Skan	lcall	$0xc000, $3
51117397Skan	movw	%cs, %ax
52117397Skan	movw	%ax, %ds
53117397Skan	movw	%ax, %ss
54117397Skan
55117397Skan	/* Load GDT for real mode */
56117397Skan	lgdt	physical_gdt
57117397Skan
58117397Skan	/* Restore CR2, CR3 and CR4 */
59117397Skan	mov	previous_cr2,%eax
60117397Skan	mov	%eax,%cr2
61117397Skan	mov	previous_cr3,%eax
62117397Skan	mov	%eax,%cr3
63117397Skan	mov	previous_cr4,%eax
64117397Skan	mov	%eax,%cr4
65117397Skan
66117397Skan	/* Transfer some values to protected mode */
67117397Skan#define NVALUES	9
68117397Skan#define TRANSFER_STACK32(val, idx)	\
69117397Skan	mov	val,%eax;		\
70117397Skan	mov	%eax,wakeup_32stack+(idx+1)+(idx*4);
71117397Skan
72117397Skan	TRANSFER_STACK32(previous_ss,		(NVALUES - 9))
73117397Skan	TRANSFER_STACK32(previous_fs,		(NVALUES - 8))
74117397Skan	TRANSFER_STACK32(previous_ds,		(NVALUES - 7))
75169691Skan	TRANSFER_STACK32(physical_gdt+2,	(NVALUES - 6))
76169691Skan	TRANSFER_STACK32(where_to_recover,	(NVALUES - 5))
77	TRANSFER_STACK32(previous_idt+2,	(NVALUES - 4))
78	TRANSFER_STACK32(previous_ldt,		(NVALUES - 3))
79	TRANSFER_STACK32(previous_gdt+2,	(NVALUES - 2))
80	TRANSFER_STACK32(previous_tr,		(NVALUES - 1))
81	TRANSFER_STACK32(previous_cr0,		(NVALUES - 0))
82
83	mov	physical_esp,%esi	/* to be used in 32bit code */
84
85	/* Enable protected mode */
86	mov	%cr0,%eax
87	orl	$(CR0_PE),%eax
88	mov	%eax,%cr0
89
90wakeup_sw32:
91	/* Switch to protected mode by intersegmental jump */
92	ljmpl	$0x8,$0x12345678	/* Code location, to be replaced */
93
94	.code32
95wakeup_32:
96	/*
97	 * Switched to protected mode w/o paging
98	 *	%esi:	KERNEL stack pointer (physical address)
99	 */
100
101	nop
102
103	/* Set up segment registers for protected mode */
104	movw	$0x10,%ax		/* KDSEL to segment registers */
105	movw	%ax,%ds
106	movw	%ax,%es
107	movw	%ax,%gs
108	movw	%ax,%ss
109	movw	$0x18,%ax		/* KPSEL to %fs */
110	movw	%ax,%fs
111	movl	%esi,%esp		/* physical address stack pointer */
112
113wakeup_32stack:
114	/* Operands are overwritten in 16bit code */
115	pushl	$0xabcdef09		/* ss + dummy */
116	pushl	$0xabcdef08		/* fs + gs */
117	pushl	$0xabcdef07		/* ds + es */
118	pushl	$0xabcdef06		/* gdt:base (physical address) */
119	pushl	$0xabcdef05		/* recover address */
120	pushl	$0xabcdef04		/* idt:base */
121	pushl	$0xabcdef03		/* ldt + idt:limit */
122	pushl	$0xabcdef02		/* gdt:base */
123	pushl	$0xabcdef01		/* TR + gdt:limit */
124	pushl	$0xabcdef00		/* CR0 */
125
126	movl	%esp,%ebp
127#define CR0_REGISTER		0(%ebp)
128#define TASK_REGISTER		4(%ebp)
129#define PREVIOUS_GDT		6(%ebp)
130#define PREVIOUS_LDT		12(%ebp)
131#define PREVIOUS_IDT		14(%ebp)
132#define RECOVER_ADDR		20(%ebp)
133#define PHYSICAL_GDT_BASE	24(%ebp)
134#define PREVIOUS_DS		28(%ebp)
135#define PREVIOUS_ES		30(%ebp)
136#define PREVIOUS_FS		32(%ebp)
137#define PREVIOUS_GS		34(%ebp)
138#define PREVIOUS_SS		36(%ebp)
139
140	/* Fixup TSS type field */
141#define TSS_TYPEFIX_MASK	0xf9
142	xorl	%esi,%esi
143	movl	PHYSICAL_GDT_BASE,%ebx
144	movw	TASK_REGISTER,%si
145	leal	(%ebx,%esi),%eax	/* get TSS segment descriptor */
146	andb	$TSS_TYPEFIX_MASK,5(%eax)
147
148	/* Prepare to return to sleep/wakeup code point */
149	lgdt	PREVIOUS_GDT
150	lidt	PREVIOUS_IDT
151
152	xorl	%eax,%eax
153	movl	%eax,%ebx
154	movl	%eax,%ecx
155	movl	%eax,%edx
156	movl	%eax,%esi
157	movl	%eax,%edi
158	movl	PREVIOUS_DS,%ebx
159	movl	PREVIOUS_FS,%ecx
160	movl	PREVIOUS_SS,%edx
161	movw	TASK_REGISTER,%si
162	shll	$16,%esi
163	movw	PREVIOUS_LDT,%si
164	movl	RECOVER_ADDR,%edi
165
166	/* Enable paging and etc. */
167	movl	CR0_REGISTER,%eax
168	movl	%eax,%cr0
169
170	/* Flush the prefetch queue */
171	jmp	1f
1721:	jmp	1f
1731:
174	/*
175	 * Now that we are in kernel virtual memory addressing
176	 *	%ebx:	ds + es
177	 *	%ecx:	fs + gs
178	 *	%edx:	ss + dummy
179	 *	%esi:	LDTR + TR
180	 *	%edi:	recover address
181	 */
182
183	nop
184
185	movl	%esi,%eax		/* LDTR + TR */
186	lldt	%ax			/* load LDT register */
187	shrl	$16,%eax
188	ltr	%ax			/* load task register */
189
190	/* Restore segment registers */
191	movl	%ebx,%eax		/* ds + es */
192	movw	%ax,%ds
193	shrl	$16,%eax
194	movw	%ax,%es
195	movl	%ecx,%eax		/* fs + gs */
196	movw	%ax,%fs
197	shrl	$16,%eax
198	movw	%ax,%gs
199	movl	%edx,%eax		/* ss */
200	movw	%ax,%ss
201
202	/* Jump to acpi_restorecpu() */
203	jmp	*%edi
204
205/* used in real mode */
206physical_gdt:		.word 0
207			.long 0
208physical_esp:		.long 0
209previous_cr2:		.long 0
210previous_cr3:		.long 0
211previous_cr4:		.long 0
212
213/* transfer from real mode to protected mode */
214previous_cr0:		.long 0
215previous_tr:		.word 0
216previous_gdt:		.word 0
217			.long 0
218previous_ldt:		.word 0
219previous_idt:		.word 0
220			.long 0
221where_to_recover:	.long 0
222previous_ds:		.word 0
223previous_es:		.word 0
224previous_fs:		.word 0
225previous_gs:		.word 0
226previous_ss:		.word 0
227dummy:			.word 0
228