acpi_wakecode.S revision 121830
180028Stakawata/*-
280028Stakawata * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
380028Stakawata * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
480028Stakawata * All rights reserved.
580028Stakawata *
680028Stakawata * Redistribution and use in source and binary forms, with or without
780028Stakawata * modification, are permitted provided that the following conditions
880028Stakawata * are met:
980028Stakawata * 1. Redistributions of source code must retain the above copyright
1080028Stakawata *    notice, this list of conditions and the following disclaimer.
1180028Stakawata * 2. Redistributions in binary form must reproduce the above copyright
1280028Stakawata *    notice, this list of conditions and the following disclaimer in the
1380028Stakawata *    documentation and/or other materials provided with the distribution.
1480028Stakawata *
1580028Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1680028Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1780028Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1880028Stakawata * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1980028Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2080028Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2180028Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2280028Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2380028Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2480028Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2580028Stakawata * SUCH DAMAGE.
2680028Stakawata */
2780028Stakawata
28115681Sobrien#include <machine/asm.h>
29115681Sobrien__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 121830 2003-11-01 00:18:29Z njl $");
30115681Sobrien
3180028Stakawata#define LOCORE
3280028Stakawata
33121830Snjl#include <machine/param.h>
3480028Stakawata#include <machine/specialreg.h>
3580028Stakawata
3680028Stakawata	.align 4
3780028Stakawata	.code16
3880028Stakawatawakeup_16:
3980028Stakawata	nop
4080028Stakawata	cli
4180028Stakawata
42121830Snjl	/*
43121830Snjl	 * Set up segment registers for real mode and a small stack for
44121830Snjl	 * any calls we make.
45121830Snjl	 */
4680028Stakawata	movw	%cs,%ax
4780028Stakawata	movw	%ax,%ds
4880028Stakawata	movw	%ax,%ss
49121830Snjl	movw	$PAGE_SIZE,%sp
50121830Snjl
51121830Snjl	/* Re-initialize video BIOS if the reset_video tunable is set. */
52121830Snjl	cmp	$1,reset_video
53121830Snjl	je	wakeup_16_gdt
54121830Snjl	lcall	$0xc000,$3
55121830Snjl
56121603Snjl	/*
57121830Snjl	 * Set up segment registers for real mode again in case the
58121830Snjl	 * previous BIOS call clobbers them.
59121603Snjl	 */
60121830Snjl	movw	%cs,%ax
61121830Snjl	movw	%ax,%ds
62121830Snjl	movw	%ax,%ss
6380028Stakawata
64121743Siwasakiwakeup_16_gdt:
6580028Stakawata	/* Load GDT for real mode */
6680028Stakawata	lgdt	physical_gdt
6780028Stakawata
6880028Stakawata	/* Restore CR2, CR3 and CR4 */
6980028Stakawata	mov	previous_cr2,%eax
7080028Stakawata	mov	%eax,%cr2
7180028Stakawata	mov	previous_cr3,%eax
7280028Stakawata	mov	%eax,%cr3
7380028Stakawata	mov	previous_cr4,%eax
7480028Stakawata	mov	%eax,%cr4
7580028Stakawata
7680028Stakawata	/* Transfer some values to protected mode */
7780028Stakawata#define NVALUES	9
7880028Stakawata#define TRANSFER_STACK32(val, idx)	\
7980028Stakawata	mov	val,%eax;		\
8080028Stakawata	mov	%eax,wakeup_32stack+(idx+1)+(idx*4);
8180028Stakawata
8280028Stakawata	TRANSFER_STACK32(previous_ss,		(NVALUES - 9))
8380028Stakawata	TRANSFER_STACK32(previous_fs,		(NVALUES - 8))
8480028Stakawata	TRANSFER_STACK32(previous_ds,		(NVALUES - 7))
8580028Stakawata	TRANSFER_STACK32(physical_gdt+2,	(NVALUES - 6))
8680028Stakawata	TRANSFER_STACK32(where_to_recover,	(NVALUES - 5))
8780028Stakawata	TRANSFER_STACK32(previous_idt+2,	(NVALUES - 4))
8880028Stakawata	TRANSFER_STACK32(previous_ldt,		(NVALUES - 3))
8980028Stakawata	TRANSFER_STACK32(previous_gdt+2,	(NVALUES - 2))
9080028Stakawata	TRANSFER_STACK32(previous_tr,		(NVALUES - 1))
9180028Stakawata	TRANSFER_STACK32(previous_cr0,		(NVALUES - 0))
9280028Stakawata
9380028Stakawata	mov	physical_esp,%esi	/* to be used in 32bit code */
9480028Stakawata
9580028Stakawata	/* Enable protected mode */
9680028Stakawata	mov	%cr0,%eax
9780028Stakawata	orl	$(CR0_PE),%eax
9880028Stakawata	mov	%eax,%cr0
9980028Stakawata
10080028Stakawatawakeup_sw32:
10180028Stakawata	/* Switch to protected mode by intersegmental jump */
10280028Stakawata	ljmpl	$0x8,$0x12345678	/* Code location, to be replaced */
10380028Stakawata
10480028Stakawata	.code32
10580028Stakawatawakeup_32:
10680028Stakawata	/*
10780028Stakawata	 * Switched to protected mode w/o paging
10880028Stakawata	 *	%esi:	KERNEL stack pointer (physical address)
10980028Stakawata	 */
11080028Stakawata
11180028Stakawata	nop
11280028Stakawata
11380028Stakawata	/* Set up segment registers for protected mode */
11480028Stakawata	movw	$0x10,%ax		/* KDSEL to segment registers */
11580028Stakawata	movw	%ax,%ds
11680028Stakawata	movw	%ax,%es
11780028Stakawata	movw	%ax,%gs
11880028Stakawata	movw	%ax,%ss
11980028Stakawata	movw	$0x18,%ax		/* KPSEL to %fs */
12080028Stakawata	movw	%ax,%fs
12180028Stakawata	movl	%esi,%esp		/* physical address stack pointer */
12280028Stakawata
12380028Stakawatawakeup_32stack:
12480028Stakawata	/* Operands are overwritten in 16bit code */
12580028Stakawata	pushl	$0xabcdef09		/* ss + dummy */
12680028Stakawata	pushl	$0xabcdef08		/* fs + gs */
12780028Stakawata	pushl	$0xabcdef07		/* ds + es */
12880028Stakawata	pushl	$0xabcdef06		/* gdt:base (physical address) */
12980028Stakawata	pushl	$0xabcdef05		/* recover address */
13080028Stakawata	pushl	$0xabcdef04		/* idt:base */
13180028Stakawata	pushl	$0xabcdef03		/* ldt + idt:limit */
13280028Stakawata	pushl	$0xabcdef02		/* gdt:base */
13380028Stakawata	pushl	$0xabcdef01		/* TR + gdt:limit */
13480028Stakawata	pushl	$0xabcdef00		/* CR0 */
13580028Stakawata
13680028Stakawata	movl	%esp,%ebp
13780028Stakawata#define CR0_REGISTER		0(%ebp)
13880028Stakawata#define TASK_REGISTER		4(%ebp)
13980028Stakawata#define PREVIOUS_GDT		6(%ebp)
14080028Stakawata#define PREVIOUS_LDT		12(%ebp)
14180028Stakawata#define PREVIOUS_IDT		14(%ebp)
14280028Stakawata#define RECOVER_ADDR		20(%ebp)
14380028Stakawata#define PHYSICAL_GDT_BASE	24(%ebp)
14480028Stakawata#define PREVIOUS_DS		28(%ebp)
14580028Stakawata#define PREVIOUS_ES		30(%ebp)
14680028Stakawata#define PREVIOUS_FS		32(%ebp)
14780028Stakawata#define PREVIOUS_GS		34(%ebp)
14880028Stakawata#define PREVIOUS_SS		36(%ebp)
14980028Stakawata
15080028Stakawata	/* Fixup TSS type field */
15180028Stakawata#define TSS_TYPEFIX_MASK	0xf9
15280028Stakawata	xorl	%esi,%esi
15380028Stakawata	movl	PHYSICAL_GDT_BASE,%ebx
15480028Stakawata	movw	TASK_REGISTER,%si
15580028Stakawata	leal	(%ebx,%esi),%eax	/* get TSS segment descriptor */
15680028Stakawata	andb	$TSS_TYPEFIX_MASK,5(%eax)
15780028Stakawata
15880028Stakawata	/* Prepare to return to sleep/wakeup code point */
15980028Stakawata	lgdt	PREVIOUS_GDT
16080028Stakawata	lidt	PREVIOUS_IDT
16180028Stakawata
16280028Stakawata	xorl	%eax,%eax
16380028Stakawata	movl	%eax,%ebx
16480028Stakawata	movl	%eax,%ecx
16580028Stakawata	movl	%eax,%edx
16680028Stakawata	movl	%eax,%esi
16780028Stakawata	movl	%eax,%edi
16880028Stakawata	movl	PREVIOUS_DS,%ebx
16980028Stakawata	movl	PREVIOUS_FS,%ecx
17080028Stakawata	movl	PREVIOUS_SS,%edx
17180028Stakawata	movw	TASK_REGISTER,%si
17280028Stakawata	shll	$16,%esi
17380028Stakawata	movw	PREVIOUS_LDT,%si
17480028Stakawata	movl	RECOVER_ADDR,%edi
17580028Stakawata
17680028Stakawata	/* Enable paging and etc. */
17780028Stakawata	movl	CR0_REGISTER,%eax
17880028Stakawata	movl	%eax,%cr0
17980028Stakawata
18080028Stakawata	/* Flush the prefetch queue */
18180028Stakawata	jmp	1f
18280028Stakawata1:	jmp	1f
18380028Stakawata1:
18480028Stakawata	/*
18580028Stakawata	 * Now that we are in kernel virtual memory addressing
18680028Stakawata	 *	%ebx:	ds + es
18780028Stakawata	 *	%ecx:	fs + gs
18880028Stakawata	 *	%edx:	ss + dummy
18980028Stakawata	 *	%esi:	LDTR + TR
19080028Stakawata	 *	%edi:	recover address
19180028Stakawata	 */
19280028Stakawata
19380028Stakawata	nop
19480028Stakawata
19580028Stakawata	movl	%esi,%eax		/* LDTR + TR */
19680028Stakawata	lldt	%ax			/* load LDT register */
19780028Stakawata	shrl	$16,%eax
19880028Stakawata	ltr	%ax			/* load task register */
19980028Stakawata
20080028Stakawata	/* Restore segment registers */
20180028Stakawata	movl	%ebx,%eax		/* ds + es */
20280028Stakawata	movw	%ax,%ds
20380028Stakawata	shrl	$16,%eax
20480028Stakawata	movw	%ax,%es
20580028Stakawata	movl	%ecx,%eax		/* fs + gs */
20680028Stakawata	movw	%ax,%fs
20780028Stakawata	shrl	$16,%eax
20880028Stakawata	movw	%ax,%gs
20980028Stakawata	movl	%edx,%eax		/* ss */
21080028Stakawata	movw	%ax,%ss
21180028Stakawata
21280028Stakawata	/* Jump to acpi_restorecpu() */
21380028Stakawata	jmp	*%edi
21480028Stakawata
21580028Stakawata/* used in real mode */
21680028Stakawataphysical_gdt:		.word 0
21780028Stakawata			.long 0
21880028Stakawataphysical_esp:		.long 0
21980028Stakawataprevious_cr2:		.long 0
22080028Stakawataprevious_cr3:		.long 0
22180028Stakawataprevious_cr4:		.long 0
222121830Snjlreset_video:		.long 0
22380028Stakawata
22480028Stakawata/* transfer from real mode to protected mode */
22580028Stakawataprevious_cr0:		.long 0
22680028Stakawataprevious_tr:		.word 0
22780028Stakawataprevious_gdt:		.word 0
22880028Stakawata			.long 0
22980028Stakawataprevious_ldt:		.word 0
23080028Stakawataprevious_idt:		.word 0
23180028Stakawata			.long 0
23280028Stakawatawhere_to_recover:	.long 0
23380028Stakawataprevious_ds:		.word 0
23480028Stakawataprevious_es:		.word 0
23580028Stakawataprevious_fs:		.word 0
23680028Stakawataprevious_gs:		.word 0
23780028Stakawataprevious_ss:		.word 0
23880028Stakawatadummy:			.word 0
239