15db2f26eSSascha Wildner/*-
25db2f26eSSascha Wildner * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
35db2f26eSSascha Wildner * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
45db2f26eSSascha Wildner * All rights reserved.
55db2f26eSSascha Wildner *
65db2f26eSSascha Wildner * Redistribution and use in source and binary forms, with or without
75db2f26eSSascha Wildner * modification, are permitted provided that the following conditions
85db2f26eSSascha Wildner * are met:
95db2f26eSSascha Wildner * 1. Redistributions of source code must retain the above copyright
105db2f26eSSascha Wildner *    notice, this list of conditions and the following disclaimer.
115db2f26eSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
125db2f26eSSascha Wildner *    notice, this list of conditions and the following disclaimer in the
135db2f26eSSascha Wildner *    documentation and/or other materials provided with the distribution.
145db2f26eSSascha Wildner *
155db2f26eSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165db2f26eSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175db2f26eSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185db2f26eSSascha Wildner * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195db2f26eSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205db2f26eSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215db2f26eSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225db2f26eSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235db2f26eSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245db2f26eSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255db2f26eSSascha Wildner * SUCH DAMAGE.
265db2f26eSSascha Wildner *
275db2f26eSSascha Wildner * $FreeBSD: src/sys/i386/acpica/acpi_wakecode.S,v 1.9 2004/01/01 22:57:22 njl Exp $
285db2f26eSSascha Wildner */
295db2f26eSSascha Wildner
305db2f26eSSascha Wildner#define LOCORE
315db2f26eSSascha Wildner
325db2f26eSSascha Wildner#include <machine/asmacros.h>
335db2f26eSSascha Wildner#include <machine/param.h>
345db2f26eSSascha Wildner#include <machine/specialreg.h>
355db2f26eSSascha Wildner
365db2f26eSSascha Wildner	.align 4
375db2f26eSSascha Wildner	.code16
385db2f26eSSascha Wildnerwakeup_16:
395db2f26eSSascha Wildner	nop
405db2f26eSSascha Wildner	cli
415db2f26eSSascha Wildner
425db2f26eSSascha Wildner	/*
435db2f26eSSascha Wildner	 * Set up segment registers for real mode and a small stack for
445db2f26eSSascha Wildner	 * any calls we make.
455db2f26eSSascha Wildner	 */
465db2f26eSSascha Wildner	movw	%cs,%ax
475db2f26eSSascha Wildner	movw	%ax,%ds
485db2f26eSSascha Wildner	movw	%ax,%ss
495db2f26eSSascha Wildner	movw	$PAGE_SIZE,%sp
505db2f26eSSascha Wildner
515db2f26eSSascha Wildner	/* Re-initialize video BIOS if the reset_video tunable is set. */
52*0993d469SJohn Marino	cmpw	$0,reset_video
535db2f26eSSascha Wildner	je	wakeup_16_gdt
545db2f26eSSascha Wildner	lcall	$0xc000,$3
555db2f26eSSascha Wildner
565db2f26eSSascha Wildner	/*
575db2f26eSSascha Wildner	 * Set up segment registers for real mode again in case the
585db2f26eSSascha Wildner	 * previous BIOS call clobbers them.
595db2f26eSSascha Wildner	 */
605db2f26eSSascha Wildner	movw	%cs,%ax
615db2f26eSSascha Wildner	movw	%ax,%ds
625db2f26eSSascha Wildner	movw	%ax,%ss
635db2f26eSSascha Wildner
645db2f26eSSascha Wildnerwakeup_16_gdt:
655db2f26eSSascha Wildner	/* Load GDT for real mode */
665db2f26eSSascha Wildner	lgdt	physical_gdt
675db2f26eSSascha Wildner
685db2f26eSSascha Wildner	/* Restore CR2, CR3 and CR4 */
695db2f26eSSascha Wildner	mov	previous_cr2,%eax
705db2f26eSSascha Wildner	mov	%eax,%cr2
715db2f26eSSascha Wildner	mov	previous_cr3,%eax
725db2f26eSSascha Wildner	mov	%eax,%cr3
735db2f26eSSascha Wildner	mov	previous_cr4,%eax
745db2f26eSSascha Wildner	mov	%eax,%cr4
755db2f26eSSascha Wildner
765db2f26eSSascha Wildner	/* Transfer some values to protected mode */
775db2f26eSSascha Wildner#define NVALUES	9
785db2f26eSSascha Wildner#define TRANSFER_STACK32(val, idx)	\
795db2f26eSSascha Wildner	mov	val,%eax;		\
805db2f26eSSascha Wildner	mov	%eax,wakeup_32stack+(idx+1)+(idx*4);
815db2f26eSSascha Wildner
825db2f26eSSascha Wildner	TRANSFER_STACK32(previous_ss,		(NVALUES - 9))
835db2f26eSSascha Wildner	TRANSFER_STACK32(previous_fs,		(NVALUES - 8))
845db2f26eSSascha Wildner	TRANSFER_STACK32(previous_ds,		(NVALUES - 7))
855db2f26eSSascha Wildner	TRANSFER_STACK32(physical_gdt+2,	(NVALUES - 6))
865db2f26eSSascha Wildner	TRANSFER_STACK32(where_to_recover,	(NVALUES - 5))
875db2f26eSSascha Wildner	TRANSFER_STACK32(previous_idt+2,	(NVALUES - 4))
885db2f26eSSascha Wildner	TRANSFER_STACK32(previous_ldt,		(NVALUES - 3))
895db2f26eSSascha Wildner	TRANSFER_STACK32(previous_gdt+2,	(NVALUES - 2))
905db2f26eSSascha Wildner	TRANSFER_STACK32(previous_tr,		(NVALUES - 1))
915db2f26eSSascha Wildner	TRANSFER_STACK32(previous_cr0,		(NVALUES - 0))
925db2f26eSSascha Wildner
935db2f26eSSascha Wildner	mov	physical_esp,%esi	/* to be used in 32bit code */
945db2f26eSSascha Wildner
955db2f26eSSascha Wildner	/* Enable protected mode */
965db2f26eSSascha Wildner	mov	%cr0,%eax
975db2f26eSSascha Wildner	orl	$(CR0_PE),%eax
985db2f26eSSascha Wildner	mov	%eax,%cr0
995db2f26eSSascha Wildner
1005db2f26eSSascha Wildnerwakeup_sw32:
1015db2f26eSSascha Wildner	/* Switch to protected mode by intersegmental jump */
1025db2f26eSSascha Wildner	ljmpl	$0x8,$0x12345678	/* Code location, to be replaced */
1035db2f26eSSascha Wildner
1045db2f26eSSascha Wildner	.code32
1055db2f26eSSascha Wildnerwakeup_32:
1065db2f26eSSascha Wildner	/*
1075db2f26eSSascha Wildner	 * Switched to protected mode w/o paging
1085db2f26eSSascha Wildner	 *	%esi:	KERNEL stack pointer (physical address)
1095db2f26eSSascha Wildner	 */
1105db2f26eSSascha Wildner
1115db2f26eSSascha Wildner	nop
1125db2f26eSSascha Wildner
1135db2f26eSSascha Wildner	/* Set up segment registers for protected mode */
1145db2f26eSSascha Wildner	movw	$0x10,%ax		/* KDSEL to segment registers */
1155db2f26eSSascha Wildner	movw	%ax,%ds
1165db2f26eSSascha Wildner	movw	%ax,%es
1175db2f26eSSascha Wildner	movw	%ax,%gs
1185db2f26eSSascha Wildner	movw	%ax,%ss
1195db2f26eSSascha Wildner	movw	$0x18,%ax		/* KPSEL to %fs */
1205db2f26eSSascha Wildner	movw	%ax,%fs
1215db2f26eSSascha Wildner	movl	%esi,%esp		/* physical address stack pointer */
1225db2f26eSSascha Wildner
1235db2f26eSSascha Wildnerwakeup_32stack:
1245db2f26eSSascha Wildner	/* Operands are overwritten in 16bit code */
1255db2f26eSSascha Wildner	pushl	$0xabcdef09		/* ss + dummy */
1265db2f26eSSascha Wildner	pushl	$0xabcdef08		/* fs + gs */
1275db2f26eSSascha Wildner	pushl	$0xabcdef07		/* ds + es */
1285db2f26eSSascha Wildner	pushl	$0xabcdef06		/* gdt:base (physical address) */
1295db2f26eSSascha Wildner	pushl	$0xabcdef05		/* recover address */
1305db2f26eSSascha Wildner	pushl	$0xabcdef04		/* idt:base */
1315db2f26eSSascha Wildner	pushl	$0xabcdef03		/* ldt + idt:limit */
1325db2f26eSSascha Wildner	pushl	$0xabcdef02		/* gdt:base */
1335db2f26eSSascha Wildner	pushl	$0xabcdef01		/* TR + gdt:limit */
1345db2f26eSSascha Wildner	pushl	$0xabcdef00		/* CR0 */
1355db2f26eSSascha Wildner
1365db2f26eSSascha Wildner	movl	%esp,%ebp
1375db2f26eSSascha Wildner#define CR0_REGISTER		0(%ebp)
1385db2f26eSSascha Wildner#define TASK_REGISTER		4(%ebp)
1395db2f26eSSascha Wildner#define PREVIOUS_GDT		6(%ebp)
1405db2f26eSSascha Wildner#define PREVIOUS_LDT		12(%ebp)
1415db2f26eSSascha Wildner#define PREVIOUS_IDT		14(%ebp)
1425db2f26eSSascha Wildner#define RECOVER_ADDR		20(%ebp)
1435db2f26eSSascha Wildner#define PHYSICAL_GDT_BASE	24(%ebp)
1445db2f26eSSascha Wildner#define PREVIOUS_DS		28(%ebp)
1455db2f26eSSascha Wildner#define PREVIOUS_ES		30(%ebp)
1465db2f26eSSascha Wildner#define PREVIOUS_FS		32(%ebp)
1475db2f26eSSascha Wildner#define PREVIOUS_GS		34(%ebp)
1485db2f26eSSascha Wildner#define PREVIOUS_SS		36(%ebp)
1495db2f26eSSascha Wildner
1505db2f26eSSascha Wildner	/* Fixup TSS type field */
1515db2f26eSSascha Wildner#define TSS_TYPEFIX_MASK	0xf9
1525db2f26eSSascha Wildner	xorl	%esi,%esi
1535db2f26eSSascha Wildner	movl	PHYSICAL_GDT_BASE,%ebx
1545db2f26eSSascha Wildner	movw	TASK_REGISTER,%si
1555db2f26eSSascha Wildner	leal	(%ebx,%esi),%eax	/* get TSS segment descriptor */
1565db2f26eSSascha Wildner	andb	$TSS_TYPEFIX_MASK,5(%eax)
1575db2f26eSSascha Wildner
1585db2f26eSSascha Wildner	/* Prepare to return to sleep/wakeup code point */
1595db2f26eSSascha Wildner	lgdt	PREVIOUS_GDT
1605db2f26eSSascha Wildner	lidt	PREVIOUS_IDT
1615db2f26eSSascha Wildner
1625db2f26eSSascha Wildner	xorl	%eax,%eax
1635db2f26eSSascha Wildner	movl	%eax,%ebx
1645db2f26eSSascha Wildner	movl	%eax,%ecx
1655db2f26eSSascha Wildner	movl	%eax,%edx
1665db2f26eSSascha Wildner	movl	%eax,%esi
1675db2f26eSSascha Wildner	movl	%eax,%edi
1685db2f26eSSascha Wildner	movl	PREVIOUS_DS,%ebx
1695db2f26eSSascha Wildner	movl	PREVIOUS_FS,%ecx
1705db2f26eSSascha Wildner	movl	PREVIOUS_SS,%edx
1715db2f26eSSascha Wildner	movw	TASK_REGISTER,%si
1725db2f26eSSascha Wildner	shll	$16,%esi
1735db2f26eSSascha Wildner	movw	PREVIOUS_LDT,%si
1745db2f26eSSascha Wildner	movl	RECOVER_ADDR,%edi
1755db2f26eSSascha Wildner
1765db2f26eSSascha Wildner	/* Enable paging and etc. */
1775db2f26eSSascha Wildner	movl	CR0_REGISTER,%eax
1785db2f26eSSascha Wildner	movl	%eax,%cr0
1795db2f26eSSascha Wildner
1805db2f26eSSascha Wildner	/* Flush the prefetch queue */
1815db2f26eSSascha Wildner	jmp	1f
1825db2f26eSSascha Wildner1:	jmp	1f
1835db2f26eSSascha Wildner1:
1845db2f26eSSascha Wildner	/*
1855db2f26eSSascha Wildner	 * Now that we are in kernel virtual memory addressing
1865db2f26eSSascha Wildner	 *	%ebx:	ds + es
1875db2f26eSSascha Wildner	 *	%ecx:	fs + gs
1885db2f26eSSascha Wildner	 *	%edx:	ss + dummy
1895db2f26eSSascha Wildner	 *	%esi:	LDTR + TR
1905db2f26eSSascha Wildner	 *	%edi:	recover address
1915db2f26eSSascha Wildner	 */
1925db2f26eSSascha Wildner
1935db2f26eSSascha Wildner	nop
1945db2f26eSSascha Wildner
1955db2f26eSSascha Wildner	movl	%esi,%eax		/* LDTR + TR */
1965db2f26eSSascha Wildner	lldt	%ax			/* load LDT register */
1975db2f26eSSascha Wildner	shrl	$16,%eax
1985db2f26eSSascha Wildner	ltr	%ax			/* load task register */
1995db2f26eSSascha Wildner
2005db2f26eSSascha Wildner	/* Restore segment registers */
2015db2f26eSSascha Wildner	movl	%ebx,%eax		/* ds + es */
2025db2f26eSSascha Wildner	movw	%ax,%ds
2035db2f26eSSascha Wildner	shrl	$16,%eax
2045db2f26eSSascha Wildner	movw	%ax,%es
2055db2f26eSSascha Wildner	movl	%ecx,%eax		/* fs + gs */
2065db2f26eSSascha Wildner	movw	%ax,%fs
2075db2f26eSSascha Wildner	shrl	$16,%eax
2085db2f26eSSascha Wildner	movw	%ax,%gs
2095db2f26eSSascha Wildner	movl	%edx,%eax		/* ss */
2105db2f26eSSascha Wildner	movw	%ax,%ss
2115db2f26eSSascha Wildner
2125db2f26eSSascha Wildner	/* Jump to acpi_restorecpu() */
2135db2f26eSSascha Wildner	jmp	*%edi
2145db2f26eSSascha Wildner
2155db2f26eSSascha Wildner/* used in real mode */
2165db2f26eSSascha Wildnerphysical_gdt:		.word 0
2175db2f26eSSascha Wildner			.long 0
2185db2f26eSSascha Wildnerphysical_esp:		.long 0
2195db2f26eSSascha Wildnerprevious_cr2:		.long 0
2205db2f26eSSascha Wildnerprevious_cr3:		.long 0
2215db2f26eSSascha Wildnerprevious_cr4:		.long 0
2225db2f26eSSascha Wildnerreset_video:		.long 0
2235db2f26eSSascha Wildner
2245db2f26eSSascha Wildner/* transfer from real mode to protected mode */
2255db2f26eSSascha Wildnerprevious_cr0:		.long 0
2265db2f26eSSascha Wildnerprevious_tr:		.word 0
2275db2f26eSSascha Wildnerprevious_gdt:		.word 0
2285db2f26eSSascha Wildner			.long 0
2295db2f26eSSascha Wildnerprevious_ldt:		.word 0
2305db2f26eSSascha Wildnerprevious_idt:		.word 0
2315db2f26eSSascha Wildner			.long 0
2325db2f26eSSascha Wildnerwhere_to_recover:	.long 0
2335db2f26eSSascha Wildnerprevious_ds:		.word 0
2345db2f26eSSascha Wildnerprevious_es:		.word 0
2355db2f26eSSascha Wildnerprevious_fs:		.word 0
2365db2f26eSSascha Wildnerprevious_gs:		.word 0
2375db2f26eSSascha Wildnerprevious_ss:		.word 0
2385db2f26eSSascha Wildnerdummy:			.word 0
239