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