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