xref: /freebsd/sys/amd64/acpica/acpi_wakecode.S (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1c66d2b38SJung-uk Kim/*-
2c66d2b38SJung-uk Kim * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3c66d2b38SJung-uk Kim * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4c66d2b38SJung-uk Kim * Copyright (c) 2003 Peter Wemm
5db25e24cSJung-uk Kim * Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
6c66d2b38SJung-uk Kim * All rights reserved.
7c66d2b38SJung-uk Kim *
8c66d2b38SJung-uk Kim * Redistribution and use in source and binary forms, with or without
9c66d2b38SJung-uk Kim * modification, are permitted provided that the following conditions
10c66d2b38SJung-uk Kim * are met:
11c66d2b38SJung-uk Kim * 1. Redistributions of source code must retain the above copyright
12c66d2b38SJung-uk Kim *    notice, this list of conditions and the following disclaimer.
13c66d2b38SJung-uk Kim * 2. Redistributions in binary form must reproduce the above copyright
14c66d2b38SJung-uk Kim *    notice, this list of conditions and the following disclaimer in the
15c66d2b38SJung-uk Kim *    documentation and/or other materials provided with the distribution.
16c66d2b38SJung-uk Kim *
17c66d2b38SJung-uk Kim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18c66d2b38SJung-uk Kim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19c66d2b38SJung-uk Kim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20c66d2b38SJung-uk Kim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21c66d2b38SJung-uk Kim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22c66d2b38SJung-uk Kim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23c66d2b38SJung-uk Kim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24c66d2b38SJung-uk Kim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25c66d2b38SJung-uk Kim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26c66d2b38SJung-uk Kim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27c66d2b38SJung-uk Kim * SUCH DAMAGE.
28c66d2b38SJung-uk Kim */
29c66d2b38SJung-uk Kim
30c66d2b38SJung-uk Kim#include <machine/asmacros.h>
31c66d2b38SJung-uk Kim#include <machine/specialreg.h>
32d1f4c44aSDmitry Chagin#include <x86/ppireg.h>
33*de4da6cdSDmitry Chagin#include <x86/timerreg.h>
34c66d2b38SJung-uk Kim
35fc2a8776SEd Maste#include "assym.inc"
36c66d2b38SJung-uk Kim
37c66d2b38SJung-uk Kim/*
38c66d2b38SJung-uk Kim * Resume entry point for real mode.
39c66d2b38SJung-uk Kim *
40c66d2b38SJung-uk Kim * If XFirmwareWakingVector is zero and FirmwareWakingVector is non-zero
41c66d2b38SJung-uk Kim * in FACS, the BIOS enters here in real mode after POST with CS set to
42c66d2b38SJung-uk Kim * (FirmwareWakingVector >> 4) and IP set to (FirmwareWakingVector & 0xf).
43c66d2b38SJung-uk Kim * Depending on the previous sleep state, we may need to initialize more
44c66d2b38SJung-uk Kim * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).
45c66d2b38SJung-uk Kim *
46c66d2b38SJung-uk Kim * Note: If XFirmwareWakingVector is non-zero, it should disable address
47c66d2b38SJung-uk Kim * translation/paging and interrupts, load all segment registers with
48c66d2b38SJung-uk Kim * a flat 4 GB address space, and set EFLAGS.IF to zero.  Currently
49c66d2b38SJung-uk Kim * this mode is not supported by this code.
50c66d2b38SJung-uk Kim */
51c66d2b38SJung-uk Kim
52c66d2b38SJung-uk Kim	.data				/* So we can modify it */
53c66d2b38SJung-uk Kim
54c66d2b38SJung-uk Kim	ALIGN_TEXT
55c66d2b38SJung-uk Kim	.code16
56a7e2341eSJung-uk Kimwakeup_start:
57c66d2b38SJung-uk Kim	/*
58c66d2b38SJung-uk Kim	 * Set up segment registers for real mode, a small stack for
59c66d2b38SJung-uk Kim	 * any calls we make, and clear any flags.
60c66d2b38SJung-uk Kim	 */
61c66d2b38SJung-uk Kim	cli				/* make sure no interrupts */
62c66d2b38SJung-uk Kim	mov	%cs, %ax		/* copy %cs to %ds.  Remember these */
63c66d2b38SJung-uk Kim	mov	%ax, %ds		/* are offsets rather than selectors */
64c66d2b38SJung-uk Kim	mov	%ax, %ss
65a7e2341eSJung-uk Kim	movw	$PAGE_SIZE, %sp
66d2b227cdSJung-uk Kim	xorw	%ax, %ax
67d2b227cdSJung-uk Kim	pushw	%ax
68c66d2b38SJung-uk Kim	popfw
69c66d2b38SJung-uk Kim
70c66d2b38SJung-uk Kim	/* To debug resume hangs, beep the speaker if the user requested. */
71d2b227cdSJung-uk Kim	testb	$~0, resume_beep - wakeup_start
72d2b227cdSJung-uk Kim	jz	1f
73d2b227cdSJung-uk Kim	movb	$0, resume_beep - wakeup_start
74b1dd9055SJung-uk Kim
75b1dd9055SJung-uk Kim	/* Set PIC timer2 to beep. */
76b1dd9055SJung-uk Kim	movb	$(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al
77b1dd9055SJung-uk Kim	outb	%al, $TIMER_MODE
78b1dd9055SJung-uk Kim
79b1dd9055SJung-uk Kim	/* Turn on speaker. */
80b1dd9055SJung-uk Kim	inb	$IO_PPI, %al
81b1dd9055SJung-uk Kim	orb	$PIT_SPKR, %al
82b1dd9055SJung-uk Kim	outb	%al, $IO_PPI
83b1dd9055SJung-uk Kim
84b1dd9055SJung-uk Kim	/* Set frequency. */
85b1dd9055SJung-uk Kim	movw	$0x4c0, %ax
86b1dd9055SJung-uk Kim	outb	%al, $TIMER_CNTR2
87b1dd9055SJung-uk Kim	shrw	$8, %ax
88b1dd9055SJung-uk Kim	outb	%al, $TIMER_CNTR2
89c66d2b38SJung-uk Kim1:
90c66d2b38SJung-uk Kim
91c66d2b38SJung-uk Kim	/* Re-initialize video BIOS if the reset_video tunable is set. */
92d2b227cdSJung-uk Kim	testb	$~0, reset_video - wakeup_start
93d2b227cdSJung-uk Kim	jz	1f
94d2b227cdSJung-uk Kim	movb	$0, reset_video - wakeup_start
95c66d2b38SJung-uk Kim	lcall	$0xc000, $3
96c66d2b38SJung-uk Kim
971d9fd147SJung-uk Kim	/* When we reach here, int 0x10 should be ready.  Hide cursor. */
981d9fd147SJung-uk Kim	movb	$0x01, %ah
991d9fd147SJung-uk Kim	movb	$0x20, %ch
1001d9fd147SJung-uk Kim	int	$0x10
1011d9fd147SJung-uk Kim
102d2b227cdSJung-uk Kim	/* Re-start in case the previous BIOS call clobbers them. */
103d2b227cdSJung-uk Kim	jmp	wakeup_start
104c66d2b38SJung-uk Kim1:
105c66d2b38SJung-uk Kim
106c66d2b38SJung-uk Kim	/*
107c66d2b38SJung-uk Kim	 * Find relocation base and patch the gdt descript and ljmp targets
108c66d2b38SJung-uk Kim	 */
109c66d2b38SJung-uk Kim	xorl	%ebx, %ebx
110c66d2b38SJung-uk Kim	mov	%cs, %bx
111c66d2b38SJung-uk Kim	sall	$4, %ebx		/* %ebx is now our relocation base */
112c66d2b38SJung-uk Kim
113c66d2b38SJung-uk Kim	/*
114c66d2b38SJung-uk Kim	 * Load the descriptor table pointer.  We'll need it when running
115c66d2b38SJung-uk Kim	 * in 16-bit protected mode.
116c66d2b38SJung-uk Kim	 */
117c66d2b38SJung-uk Kim	lgdtl	bootgdtdesc - wakeup_start
118c66d2b38SJung-uk Kim
119c66d2b38SJung-uk Kim	/* Enable protected mode */
120c66d2b38SJung-uk Kim	movl	$CR0_PE, %eax
121c66d2b38SJung-uk Kim	mov	%eax, %cr0
122c66d2b38SJung-uk Kim
123c66d2b38SJung-uk Kim	/*
124c66d2b38SJung-uk Kim	 * Now execute a far jump to turn on protected mode.  This
125c66d2b38SJung-uk Kim	 * causes the segment registers to turn into selectors and causes
126c66d2b38SJung-uk Kim	 * %cs to be loaded from the gdt.
127c66d2b38SJung-uk Kim	 *
128c66d2b38SJung-uk Kim	 * The following instruction is:
129c66d2b38SJung-uk Kim	 * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start
130c66d2b38SJung-uk Kim	 * but gas cannot assemble that.  And besides, we patch the targets
131c66d2b38SJung-uk Kim	 * in early startup and its a little clearer what we are patching.
132c66d2b38SJung-uk Kim	 */
133c66d2b38SJung-uk Kimwakeup_sw32:
134c66d2b38SJung-uk Kim	.byte	0x66			/* size override to 32 bits */
135c66d2b38SJung-uk Kim	.byte	0xea			/* opcode for far jump */
136c66d2b38SJung-uk Kim	.long	wakeup_32 - wakeup_start /* offset in segment */
137c66d2b38SJung-uk Kim	.word	bootcode32 - bootgdt	/* index in gdt for 32 bit code */
138c66d2b38SJung-uk Kim
139c66d2b38SJung-uk Kim	/*
140c66d2b38SJung-uk Kim	 * At this point, we are running in 32 bit legacy protected mode.
141c66d2b38SJung-uk Kim	 */
142a7e2341eSJung-uk Kim	ALIGN_TEXT
143c66d2b38SJung-uk Kim	.code32
144c66d2b38SJung-uk Kimwakeup_32:
145c66d2b38SJung-uk Kim
146c66d2b38SJung-uk Kim	mov	$bootdata32 - bootgdt, %eax
147c66d2b38SJung-uk Kim	mov	%ax, %ds
148c66d2b38SJung-uk Kim
149f446480bSKonstantin Belousov	/*
150f446480bSKonstantin Belousov	 * Turn on the PAE bit and optionally the LA57 bit for when paging
151f446480bSKonstantin Belousov	 * is later enabled.
152f446480bSKonstantin Belousov	 */
153c66d2b38SJung-uk Kim	mov	%cr4, %eax
154f5417a03SRoger Pau Monné	orl	$CR4_PAE, %eax
155f446480bSKonstantin Belousov	leal	wakeup_pagetables - wakeup_start(%ebx), %ecx
156f446480bSKonstantin Belousov	movl	(%ecx), %ecx
157f446480bSKonstantin Belousov	testl	$0x1, %ecx
158f446480bSKonstantin Belousov	je	1f
159f446480bSKonstantin Belousov	orl	$CR4_LA57, %eax
160f446480bSKonstantin Belousov1:	mov	%eax, %cr4
161c66d2b38SJung-uk Kim
162c66d2b38SJung-uk Kim	/*
163c66d2b38SJung-uk Kim	 * Enable EFER.LME so that we get long mode when all the prereqs are
164c66d2b38SJung-uk Kim	 * in place.  In this case, it turns on when CR0_PG is finally enabled.
165bd101a66SKonstantin Belousov	 * Also it picks up a few other EFER bits that we'll use need we're
166bd101a66SKonstantin Belousov	 * here, like SYSCALL and NX enable.
167c66d2b38SJung-uk Kim	 */
168c66d2b38SJung-uk Kim	movl	$MSR_EFER, %ecx
169bd101a66SKonstantin Belousov	movl	wakeup_efer - wakeup_start(%ebx), %eax
170bd101a66SKonstantin Belousov	movl	wakeup_efer + 4 - wakeup_start(%ebx), %edx
171c66d2b38SJung-uk Kim	wrmsr
172c66d2b38SJung-uk Kim
173c66d2b38SJung-uk Kim	/*
174c66d2b38SJung-uk Kim	 * Point to the embedded page tables for startup.  Note that this
175c66d2b38SJung-uk Kim	 * only gets accessed after we're actually in 64 bit mode, however
176c66d2b38SJung-uk Kim	 * we can only set the bottom 32 bits of %cr3 in this state.  This
177c66d2b38SJung-uk Kim	 * means we are required to use a temporary page table that is below
178c66d2b38SJung-uk Kim	 * the 4GB limit.  %ebx is still our relocation base.  We could just
179c66d2b38SJung-uk Kim	 * subtract 3 * PAGE_SIZE, but that would be too easy.
180c66d2b38SJung-uk Kim	 */
181c66d2b38SJung-uk Kim	leal	wakeup_pagetables - wakeup_start(%ebx), %eax
182c66d2b38SJung-uk Kim	movl	(%eax), %eax
183f446480bSKonstantin Belousov	andl	$~0x1, %eax
184c66d2b38SJung-uk Kim	mov	%eax, %cr3
185c66d2b38SJung-uk Kim
186c66d2b38SJung-uk Kim	/*
187c66d2b38SJung-uk Kim	 * Finally, switch to long bit mode by enabling paging.  We have
188c66d2b38SJung-uk Kim	 * to be very careful here because all the segmentation disappears
189c66d2b38SJung-uk Kim	 * out from underneath us.  The spec says we can depend on the
190edafb5a3SPedro F. Giffuni	 * subsequent pipelined branch to execute, but *only if* everything
191c66d2b38SJung-uk Kim	 * is still identity mapped.  If any mappings change, the pipeline
192c66d2b38SJung-uk Kim	 * will flush.
193c66d2b38SJung-uk Kim	 */
194c66d2b38SJung-uk Kim	mov	%cr0, %eax
195c66d2b38SJung-uk Kim	orl	$CR0_PG, %eax
196c66d2b38SJung-uk Kim	mov	%eax, %cr0
197c66d2b38SJung-uk Kim
198c66d2b38SJung-uk Kim	/*
199edafb5a3SPedro F. Giffuni	 * At this point paging is enabled, and we are in "compatibility" mode.
200c66d2b38SJung-uk Kim	 * We do another far jump to reload %cs with the 64 bit selector.
201c66d2b38SJung-uk Kim	 * %cr3 points to a 4-level page table page.
202c66d2b38SJung-uk Kim	 * We cannot yet jump all the way to the kernel because we can only
203c66d2b38SJung-uk Kim	 * specify a 32 bit linear address.  So, yet another trampoline.
204c66d2b38SJung-uk Kim	 *
205c66d2b38SJung-uk Kim	 * The following instruction is:
206c66d2b38SJung-uk Kim	 * ljmp $bootcode64 - bootgdt, $wakeup_64 - wakeup_start
207c66d2b38SJung-uk Kim	 * but gas cannot assemble that.  And besides, we patch the targets
208c66d2b38SJung-uk Kim	 * in early startup and its a little clearer what we are patching.
209c66d2b38SJung-uk Kim	 */
210c66d2b38SJung-uk Kimwakeup_sw64:
211c66d2b38SJung-uk Kim	.byte	0xea			/* opcode for far jump */
212c66d2b38SJung-uk Kim	.long	wakeup_64 - wakeup_start /* offset in segment */
213c66d2b38SJung-uk Kim	.word	bootcode64 - bootgdt	/* index in gdt for 64 bit code */
214c66d2b38SJung-uk Kim
215c66d2b38SJung-uk Kim	/*
216c66d2b38SJung-uk Kim	 * Yeehar!  We're running in 64-bit mode!  We can mostly ignore our
217c66d2b38SJung-uk Kim	 * segment registers, and get on with it.
218c66d2b38SJung-uk Kim	 * Note that we are running at the correct virtual address, but with
219c66d2b38SJung-uk Kim	 * a 1:1 1GB mirrored mapping over entire address space.  We had better
220c66d2b38SJung-uk Kim	 * switch to a real %cr3 promptly so that we can get to the direct map
221c66d2b38SJung-uk Kim	 * space. Remember that jmp is relative and that we've been relocated,
222c66d2b38SJung-uk Kim	 * so use an indirect jump.
223c66d2b38SJung-uk Kim	 */
224d2b227cdSJung-uk Kim	ALIGN_TEXT
225c66d2b38SJung-uk Kim	.code64
226c66d2b38SJung-uk Kimwakeup_64:
227c66d2b38SJung-uk Kim	mov	$bootdata64 - bootgdt, %eax
228c66d2b38SJung-uk Kim	mov	%ax, %ds
229c66d2b38SJung-uk Kim
230fb864578SMitsuru IWASAKI	/* Restore arguments. */
231fb864578SMitsuru IWASAKI	movq	wakeup_pcb - wakeup_start(%rbx), %rdi
232fb864578SMitsuru IWASAKI	movq	wakeup_ret - wakeup_start(%rbx), %rax
233fb864578SMitsuru IWASAKI
234fb864578SMitsuru IWASAKI	/* Restore GDT. */
235fb864578SMitsuru IWASAKI	lgdt	wakeup_gdt - wakeup_start(%rbx)
236fb864578SMitsuru IWASAKI
237fb864578SMitsuru IWASAKI	/* Jump to return address. */
238c66d2b38SJung-uk Kim	jmp	*%rax
239c66d2b38SJung-uk Kim
240d2b227cdSJung-uk Kim	.data
241d2b227cdSJung-uk Kim
242d2b227cdSJung-uk Kimresume_beep:
243d2b227cdSJung-uk Kim	.byte	0
244d2b227cdSJung-uk Kimreset_video:
245d2b227cdSJung-uk Kim	.byte	0
246d2b227cdSJung-uk Kim
247c66d2b38SJung-uk Kim	ALIGN_DATA
248c66d2b38SJung-uk Kimbootgdt:
249c66d2b38SJung-uk Kim	.long	0x00000000
250c66d2b38SJung-uk Kim	.long	0x00000000
251c8b7d7f4SJung-uk Kim	.long	0x00000000
252c8b7d7f4SJung-uk Kim	.long	0x00000000
253c8b7d7f4SJung-uk Kim	.long	0x00000000
254c8b7d7f4SJung-uk Kim	.long	0x00000000
255c8b7d7f4SJung-uk Kim	.long	0x00000000
256c8b7d7f4SJung-uk Kim	.long	0x00000000
257c66d2b38SJung-uk Kim
258c66d2b38SJung-uk Kimbootcode64:
259c66d2b38SJung-uk Kim	.long	0x0000ffff
260c66d2b38SJung-uk Kim	.long	0x00af9b00
261c66d2b38SJung-uk Kim
262c66d2b38SJung-uk Kimbootdata64:
263c66d2b38SJung-uk Kim	.long	0x0000ffff
264c66d2b38SJung-uk Kim	.long	0x00af9300
265c66d2b38SJung-uk Kim
266c66d2b38SJung-uk Kimbootcode32:
267c66d2b38SJung-uk Kim	.long	0x0000ffff
268c66d2b38SJung-uk Kim	.long	0x00cf9b00
269c66d2b38SJung-uk Kim
270c66d2b38SJung-uk Kimbootdata32:
271c66d2b38SJung-uk Kim	.long	0x0000ffff
272c66d2b38SJung-uk Kim	.long	0x00cf9300
273c66d2b38SJung-uk Kimbootgdtend:
274c66d2b38SJung-uk Kim
275c66d2b38SJung-uk Kimwakeup_pagetables:
276c66d2b38SJung-uk Kim	.long	0
277c66d2b38SJung-uk Kim
278c66d2b38SJung-uk Kimbootgdtdesc:
279c66d2b38SJung-uk Kim	.word	bootgdtend - bootgdt	/* Length */
280c66d2b38SJung-uk Kim	.long	bootgdt - wakeup_start	/* Offset plus %ds << 4 */
281c66d2b38SJung-uk Kim
282c66d2b38SJung-uk Kim	ALIGN_DATA
283a2d2c836SJung-uk Kimwakeup_pcb:
284c66d2b38SJung-uk Kim	.quad	0
285fb864578SMitsuru IWASAKIwakeup_ret:
286bc536d5aSJung-uk Kim	.quad	0
287bd101a66SKonstantin Belousovwakeup_efer:
288bd101a66SKonstantin Belousov	.quad	0
289c66d2b38SJung-uk Kimwakeup_gdt:
290c66d2b38SJung-uk Kim	.word	0
291c66d2b38SJung-uk Kim	.quad	0
292c66d2b38SJung-uk Kimdummy:
293