]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/acpica/acpi_wakecode.S
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.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-2012 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/ppireg.h>
34 #include <machine/specialreg.h>
35 #include <machine/timerreg.h>
36
37 #include "assym.inc"
38
39 /*
40  * Resume entry point for real mode.
41  *
42  * If XFirmwareWakingVector is zero and FirmwareWakingVector is non-zero
43  * in FACS, the BIOS enters here in real mode after POST with CS set to
44  * (FirmwareWakingVector >> 4) and IP set to (FirmwareWakingVector & 0xf).
45  * Depending on the previous sleep state, we may need to initialize more
46  * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).
47  *
48  * Note: If XFirmwareWakingVector is non-zero, it should disable address
49  * translation/paging and interrupts, load all segment registers with
50  * a flat 4 GB address space, and set EFLAGS.IF to zero.  Currently
51  * this mode is not supported by this code.
52  */
53
54         .data                           /* So we can modify it */
55
56         ALIGN_TEXT
57         .code16
58 wakeup_start:
59         /*
60          * Set up segment registers for real mode, a small stack for
61          * any calls we make, and clear any flags.
62          */
63         cli                             /* make sure no interrupts */
64         mov     %cs, %ax                /* copy %cs to %ds.  Remember these */
65         mov     %ax, %ds                /* are offsets rather than selectors */
66         mov     %ax, %ss
67         movw    $PAGE_SIZE, %sp
68         xorw    %ax, %ax
69         pushw   %ax
70         popfw
71
72         /* To debug resume hangs, beep the speaker if the user requested. */
73         testb   $~0, resume_beep - wakeup_start
74         jz      1f
75         movb    $0, resume_beep - wakeup_start
76
77         /* Set PIC timer2 to beep. */
78         movb    $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al
79         outb    %al, $TIMER_MODE
80
81         /* Turn on speaker. */
82         inb     $IO_PPI, %al
83         orb     $PIT_SPKR, %al
84         outb    %al, $IO_PPI
85
86         /* Set frequency. */
87         movw    $0x4c0, %ax
88         outb    %al, $TIMER_CNTR2
89         shrw    $8, %ax
90         outb    %al, $TIMER_CNTR2
91 1:
92
93         /* Re-initialize video BIOS if the reset_video tunable is set. */
94         testb   $~0, reset_video - wakeup_start
95         jz      1f
96         movb    $0, reset_video - wakeup_start
97         lcall   $0xc000, $3
98
99         /* When we reach here, int 0x10 should be ready.  Hide cursor. */
100         movb    $0x01, %ah
101         movb    $0x20, %ch
102         int     $0x10
103
104         /* Re-start in case the previous BIOS call clobbers them. */
105         jmp     wakeup_start
106 1:
107
108         /*
109          * Find relocation base and patch the gdt descript and ljmp targets
110          */
111         xorl    %ebx, %ebx
112         mov     %cs, %bx
113         sall    $4, %ebx                /* %ebx is now our relocation base */
114
115         /*
116          * Load the descriptor table pointer.  We'll need it when running
117          * in 16-bit protected mode.
118          */
119         lgdtl   bootgdtdesc - wakeup_start
120
121         /* Enable protected mode */
122         movl    $CR0_PE, %eax
123         mov     %eax, %cr0
124
125         /*
126          * Now execute a far jump to turn on protected mode.  This
127          * causes the segment registers to turn into selectors and causes
128          * %cs to be loaded from the gdt.
129          *
130          * The following instruction is:
131          * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start
132          * but gas cannot assemble that.  And besides, we patch the targets
133          * in early startup and its a little clearer what we are patching.
134          */
135 wakeup_sw32:
136         .byte   0x66                    /* size override to 32 bits */
137         .byte   0xea                    /* opcode for far jump */
138         .long   wakeup_32 - wakeup_start /* offset in segment */
139         .word   bootcode32 - bootgdt    /* index in gdt for 32 bit code */
140
141         /*
142          * At this point, we are running in 32 bit legacy protected mode.
143          */
144         ALIGN_TEXT
145         .code32
146 wakeup_32:
147
148         mov     $bootdata32 - bootgdt, %eax
149         mov     %ax, %ds
150
151         /* Turn on the PAE bit for when paging is enabled */
152         mov     %cr4, %eax
153         orl     $CR4_PAE, %eax
154         mov     %eax, %cr4
155
156         /*
157          * Enable EFER.LME so that we get long mode when all the prereqs are
158          * in place.  In this case, it turns on when CR0_PG is finally enabled.
159          * Also it picks up a few other EFER bits that we'll use need we're
160          * here, like SYSCALL and NX enable.
161          */
162         movl    $MSR_EFER, %ecx
163         movl    wakeup_efer - wakeup_start(%ebx), %eax
164         movl    wakeup_efer + 4 - wakeup_start(%ebx), %edx
165         wrmsr
166
167         /*
168          * Point to the embedded page tables for startup.  Note that this
169          * only gets accessed after we're actually in 64 bit mode, however
170          * we can only set the bottom 32 bits of %cr3 in this state.  This
171          * means we are required to use a temporary page table that is below
172          * the 4GB limit.  %ebx is still our relocation base.  We could just
173          * subtract 3 * PAGE_SIZE, but that would be too easy.
174          */
175         leal    wakeup_pagetables - wakeup_start(%ebx), %eax
176         movl    (%eax), %eax
177         mov     %eax, %cr3
178
179         /*
180          * Finally, switch to long bit mode by enabling paging.  We have
181          * to be very careful here because all the segmentation disappears
182          * out from underneath us.  The spec says we can depend on the
183          * subsequent pipelined branch to execute, but *only if* everything
184          * is still identity mapped.  If any mappings change, the pipeline
185          * will flush.
186          */
187         mov     %cr0, %eax
188         orl     $CR0_PG, %eax
189         mov     %eax, %cr0
190
191         /*
192          * At this point paging is enabled, and we are in "compatibility" mode.
193          * We do another far jump to reload %cs with the 64 bit selector.
194          * %cr3 points to a 4-level page table page.
195          * We cannot yet jump all the way to the kernel because we can only
196          * specify a 32 bit linear address.  So, yet another trampoline.
197          *
198          * The following instruction is:
199          * ljmp $bootcode64 - bootgdt, $wakeup_64 - wakeup_start
200          * but gas cannot assemble that.  And besides, we patch the targets
201          * in early startup and its a little clearer what we are patching.
202          */
203 wakeup_sw64:
204         .byte   0xea                    /* opcode for far jump */
205         .long   wakeup_64 - wakeup_start /* offset in segment */
206         .word   bootcode64 - bootgdt    /* index in gdt for 64 bit code */
207
208         /*
209          * Yeehar!  We're running in 64-bit mode!  We can mostly ignore our
210          * segment registers, and get on with it.
211          * Note that we are running at the correct virtual address, but with
212          * a 1:1 1GB mirrored mapping over entire address space.  We had better
213          * switch to a real %cr3 promptly so that we can get to the direct map
214          * space. Remember that jmp is relative and that we've been relocated,
215          * so use an indirect jump.
216          */
217         ALIGN_TEXT
218         .code64
219 wakeup_64:
220         mov     $bootdata64 - bootgdt, %eax
221         mov     %ax, %ds
222
223         /* Restore arguments. */
224         movq    wakeup_pcb - wakeup_start(%rbx), %rdi
225         movq    wakeup_ret - wakeup_start(%rbx), %rax
226
227         /* Restore GDT. */
228         lgdt    wakeup_gdt - wakeup_start(%rbx)
229
230         /* Jump to return address. */
231         jmp     *%rax
232
233         .data
234
235 resume_beep:
236         .byte   0
237 reset_video:
238         .byte   0
239
240         ALIGN_DATA
241 bootgdt:
242         .long   0x00000000
243         .long   0x00000000
244         .long   0x00000000
245         .long   0x00000000
246         .long   0x00000000
247         .long   0x00000000
248         .long   0x00000000
249         .long   0x00000000
250
251 bootcode64:
252         .long   0x0000ffff
253         .long   0x00af9b00
254
255 bootdata64:
256         .long   0x0000ffff
257         .long   0x00af9300
258
259 bootcode32:
260         .long   0x0000ffff
261         .long   0x00cf9b00
262
263 bootdata32:
264         .long   0x0000ffff
265         .long   0x00cf9300
266 bootgdtend:
267
268 wakeup_pagetables:
269         .long   0
270
271 bootgdtdesc:
272         .word   bootgdtend - bootgdt    /* Length */
273         .long   bootgdt - wakeup_start  /* Offset plus %ds << 4 */
274
275         ALIGN_DATA
276 wakeup_pcb:
277         .quad   0
278 wakeup_ret:
279         .quad   0
280 wakeup_efer:
281         .quad   0
282 wakeup_gdt:
283         .word   0
284         .quad   0
285 dummy: