]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/acpica/acpi_wakecode.S
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / i386 / acpica / acpi_wakecode.S
1 /*-
2  * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3  * Copyright (c) 2001-2012 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.  The BIOS enters here in real mode after POST with
41  * CS set to the page where we stored this code.  It should configure the
42  * segment registers with a flat 4 GB address space and EFLAGS.IF = 0.
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
47         .data                           /* So we can modify it */
48
49         ALIGN_TEXT
50         .code16
51 wakeup_start:
52         /*
53          * Set up segment registers for real mode and a small stack for
54          * any calls we make.  Set up full 32-bit bootstrap kernel flags
55          * since resumectx() doesn't restore flags.  PSL_KERNEL gives
56          * bootstrap kernel flags (with interrupts disabled), not normal
57          * kernel flags.
58          */
59         cli                             /* make sure no interrupts */
60         mov     %cs, %ax                /* copy %cs to %ds.  Remember these */
61         mov     %ax, %ds                /* are offsets rather than selectors */
62         mov     %ax, %ss
63         movw    $PAGE_SIZE, %sp
64         pushl   $PSL_KERNEL
65         popfl
66
67         /* To debug resume hangs, beep the speaker if the user requested. */
68         testb   $~0, resume_beep - wakeup_start
69         jz      1f
70         movb    $0, resume_beep - wakeup_start
71
72         /* Set PIC timer2 to beep. */
73         movb    $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al
74         outb    %al, $TIMER_MODE
75
76         /* Turn on speaker. */
77         inb     $IO_PPI, %al
78         orb     $PIT_SPKR, %al
79         outb    %al, $IO_PPI
80
81         /* Set frequency. */
82         movw    $0x4c0, %ax
83         outb    %al, $TIMER_CNTR2
84         shrw    $8, %ax
85         outb    %al, $TIMER_CNTR2
86 1:
87
88         /* Re-initialize video BIOS if the reset_video tunable is set. */
89         testb   $~0, reset_video - wakeup_start
90         jz      1f
91         movb    $0, reset_video - wakeup_start
92         lcall   $0xc000, $3
93
94         /* When we reach here, int 0x10 should be ready.  Hide cursor. */
95         movb    $0x01, %ah
96         movb    $0x20, %ch
97         int     $0x10
98
99         /* Re-start in case the previous BIOS call clobbers them. */
100         jmp     wakeup_start
101 1:
102
103         /*
104          * Find relocation base and patch the gdt descript and ljmp targets
105          */
106         xorl    %ebx, %ebx
107         mov     %cs, %bx
108         sall    $4, %ebx                /* %ebx is now our relocation base */
109
110         /*
111          * Load the descriptor table pointer.  We'll need it when running
112          * in 16-bit protected mode.
113          */
114         lgdtl   bootgdtdesc - wakeup_start
115
116         /* Enable protected mode */
117         movl    $CR0_PE, %eax
118         mov     %eax, %cr0
119
120         /*
121          * Now execute a far jump to turn on protected mode.  This
122          * causes the segment registers to turn into selectors and causes
123          * %cs to be loaded from the gdt.
124          *
125          * The following instruction is:
126          * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start
127          * but gas cannot assemble that.  And besides, we patch the targets
128          * in early startup and its a little clearer what we are patching.
129          */
130 wakeup_sw32:
131         .byte   0x66                    /* size override to 32 bits */
132         .byte   0xea                    /* opcode for far jump */
133         .long   wakeup_32 - wakeup_start /* offset in segment */
134         .word   bootcode32 - bootgdt    /* index in gdt for 32 bit code */
135
136         /*
137          * At this point, we are running in 32 bit legacy protected mode.
138          */
139         ALIGN_TEXT
140         .code32
141 wakeup_32:
142
143         mov     $bootdata32 - bootgdt, %eax
144         mov     %ax, %ds
145
146         /* Restore EFER, CR4 and CR3. */
147         movl    wakeup_efer - wakeup_start(%ebx), %eax
148         movl    wakeup_efer - wakeup_start + 4(%ebx), %edx
149         cmpl    $0, %eax
150         jne     1f
151         cmpl    $0, %edx
152         je      2f
153 1:      movl    $MSR_EFER, %ecx
154         wrmsr
155 2:      movl    wakeup_cr4 - wakeup_start(%ebx), %eax
156         cmpl    $0, %eax
157         je      3f
158         mov     %eax, %cr4
159 3:      movl    wakeup_cr3 - wakeup_start(%ebx), %eax
160         mov     %eax, %cr3
161
162         /* Get PCB and return address. */
163         movl    wakeup_ret - wakeup_start(%ebx), %edx
164         movl    wakeup_pcb - wakeup_start(%ebx), %ecx
165
166         /* Enable paging. */
167         mov     %cr0, %eax
168         orl     $CR0_PG, %eax
169         mov     %eax, %cr0
170
171         /* Jump to return address. */
172         jmp     *%edx
173
174         .data
175
176 resume_beep:
177         .byte   0
178 reset_video:
179         .byte   0
180
181         ALIGN_DATA
182 bootgdt:
183         .long   0x00000000
184         .long   0x00000000
185
186 bootcode32:
187         .long   0x0000ffff
188         .long   0x00cf9b00
189
190 bootdata32:
191         .long   0x0000ffff
192         .long   0x00cf9300
193 bootgdtend:
194
195 bootgdtdesc:
196         .word   bootgdtend - bootgdt    /* Length */
197         .long   bootgdt - wakeup_start  /* Offset plus %ds << 4 */
198
199         ALIGN_DATA
200 wakeup_efer:
201         .long   0
202         .long   0
203 wakeup_cr4:
204         .long   0
205 wakeup_cr3:
206         .long   0
207 wakeup_pcb:
208         .long   0
209 wakeup_ret:
210         .long   0
211 wakeup_gdt:             /* not used */
212         .word   0
213         .long   0
214 dummy: