Deleted Added
full compact
acpi_wakecode.S (215200) acpi_wakecode.S (235622)
1/*-
2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
1/*-
2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
3 * Copyright (c) 2001 Mitsuru IWASAKI
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>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright

--- 7 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
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

--- 7 unchanged lines hidden (view full) ---

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 *
27 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 215200 2010-11-12 20:55:14Z jkim $
29 * $FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 235622 2012-05-18 18:55:58Z iwasaki $
28 */
29
30#include <machine/asmacros.h>
30 */
31
32#include <machine/asmacros.h>
33#include <machine/ppireg.h>
31#include <machine/specialreg.h>
34#include <machine/specialreg.h>
35#include <machine/timerreg.h>
32
33#include "assym.s"
34
35/*
36 * Resume entry point. The BIOS enters here in real mode after POST with
37 * CS set to the page where we stored this code. It should configure the
38 * segment registers with a flat 4 GB address space and EFLAGS.IF = 0.
39 * Depending on the previous sleep state, we may need to initialize more
40 * of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).
41 */
36
37#include "assym.s"
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 */
42 .align 4
43 .code16
44wakeup_16:
45 nop
46 cli
47 cld
48
46
47 .data /* So we can modify it */
48
49 ALIGN_TEXT
50 .code16
51wakeup_start:
49 /*
50 * Set up segment registers for real mode, a small stack for
51 * any calls we make, and clear any flags.
52 */
52 /*
53 * Set up segment registers for real mode, a small stack for
54 * any calls we make, and clear any flags.
55 */
53 movw %cs,%ax
54 movw %ax,%ds
55 movw %ax,%ss
56 movw $PAGE_SIZE,%sp
57 pushl $0
58 popfl
56 cli /* make sure no interrupts */
57 mov %cs, %ax /* copy %cs to %ds. Remember these */
58 mov %ax, %ds /* are offsets rather than selectors */
59 mov %ax, %ss
60 movw $PAGE_SIZE, %sp
61 xorw %ax, %ax
62 pushw %ax
63 popfw
59
60 /* To debug resume hangs, beep the speaker if the user requested. */
64
65 /* To debug resume hangs, beep the speaker if the user requested. */
61 cmpl $1,resume_beep
62 jne nobeep
63 movb $0xc0,%al
64 outb %al,$0x42
65 movb $0x04,%al
66 outb %al,$0x42
67 inb $0x61,%al
68 orb $0x3,%al
69 outb %al,$0x61
70nobeep:
66 testb $~0, resume_beep - wakeup_start
67 jz 1f
68 movb $0, resume_beep - wakeup_start
71
69
72 /* Re-initialize video BIOS if the reset_video tunable is set. */
73 cmpl $1,reset_video
74 jne nobiosreset
75 lcall $0xc000,$3
70 /* Set PIC timer2 to beep. */
71 movb $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al
72 outb %al, $TIMER_MODE
76
73
77 /*
78 * Set up segment registers for real mode again in case the
79 * previous BIOS call clobbers them.
80 */
81 movw %cs,%ax
82 movw %ax,%ds
83 movw %ax,%ss
84nobiosreset:
74 /* Turn on speaker. */
75 inb $IO_PPI, %al
76 orb $PIT_SPKR, %al
77 outb %al, $IO_PPI
85
78
86 /* Load GDT for real mode. Use 32 bit prefix for addresses >16 MB. */
87 lgdtl physical_gdt
79 /* Set frequency. */
80 movw $0x4c0, %ax
81 outb %al, $TIMER_CNTR2
82 shrw $8, %ax
83 outb %al, $TIMER_CNTR2
841:
88
85
89 /* Restore CR2, CR3 and CR4 */
90 movl previous_cr2,%eax
91 movl %eax,%cr2
92 movl previous_cr3,%eax
93 movl %eax,%cr3
94 movl previous_cr4,%eax
95 movl %eax,%cr4
86 /* Re-initialize video BIOS if the reset_video tunable is set. */
87 testb $~0, reset_video - wakeup_start
88 jz 1f
89 movb $0, reset_video - wakeup_start
90 lcall $0xc000, $3
96
91
97 /* Transfer some values to protected mode with an inline stack */
98#define NVALUES 9
99#define TRANSFER_STACK32(val, idx) \
100 movl val,%eax; \
101 movl %eax,wakeup_32stack+(idx+1)+(idx*4)
92 /* When we reach here, int 0x10 should be ready. Hide cursor. */
93 movb $0x01, %ah
94 movb $0x20, %ch
95 int $0x10
102
96
103 TRANSFER_STACK32(previous_ss, (NVALUES - 9))
104 TRANSFER_STACK32(previous_fs, (NVALUES - 8))
105 TRANSFER_STACK32(previous_ds, (NVALUES - 7))
106 TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6))
107 TRANSFER_STACK32(where_to_recover, (NVALUES - 5))
108 TRANSFER_STACK32(previous_idt+2, (NVALUES - 4))
109 TRANSFER_STACK32(previous_ldt, (NVALUES - 3))
110 TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2))
111 TRANSFER_STACK32(previous_tr, (NVALUES - 1))
112 TRANSFER_STACK32(previous_cr0, (NVALUES - 0))
97 /* Re-start in case the previous BIOS call clobbers them. */
98 jmp wakeup_start
991:
113
100
114 mov physical_esp,%esi /* to be used in 32bit code */
101 /*
102 * Find relocation base and patch the gdt descript and ljmp targets
103 */
104 xorl %ebx, %ebx
105 mov %cs, %bx
106 sall $4, %ebx /* %ebx is now our relocation base */
115
107
108 /*
109 * Load the descriptor table pointer. We'll need it when running
110 * in 16-bit protected mode.
111 */
112 lgdtl bootgdtdesc - wakeup_start
113
116 /* Enable protected mode */
114 /* Enable protected mode */
117 movl %cr0,%eax
118 orl $(CR0_PE),%eax
119 movl %eax,%cr0
115 movl $CR0_PE, %eax
116 mov %eax, %cr0
120
117
118 /*
119 * Now execute a far jump to turn on protected mode. This
120 * causes the segment registers to turn into selectors and causes
121 * %cs to be loaded from the gdt.
122 *
123 * The following instruction is:
124 * ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start
125 * but gas cannot assemble that. And besides, we patch the targets
126 * in early startup and its a little clearer what we are patching.
127 */
121wakeup_sw32:
128wakeup_sw32:
122 /* Switch to protected mode by intersegmental jump */
123 ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */
129 .byte 0x66 /* size override to 32 bits */
130 .byte 0xea /* opcode for far jump */
131 .long wakeup_32 - wakeup_start /* offset in segment */
132 .word bootcode32 - bootgdt /* index in gdt for 32 bit code */
124
125 /*
133
134 /*
126 * Now switched to protected mode without paging enabled.
127 * %esi: KERNEL stack pointer (physical address)
135 * At this point, we are running in 32 bit legacy protected mode.
128 */
136 */
137 ALIGN_TEXT
129 .code32
130wakeup_32:
138 .code32
139wakeup_32:
131 nop
132
140
133 /* Set up segment registers for protected mode */
134 movw $KDSEL,%ax /* KDSEL to segment registers */
135 movw %ax,%ds
136 movw %ax,%es
137 movw %ax,%gs
138 movw %ax,%ss
139 movw $KPSEL,%ax /* KPSEL to %fs */
140 movw %ax,%fs
141 movl %esi,%esp /* physical address stack pointer */
141 mov $bootdata32 - bootgdt, %eax
142 mov %ax, %ds
142
143
143wakeup_32stack:
144 /* Operands are overwritten in 16 bit code by TRANSFER_STACK32 macro */
145 pushl $0xabcdef09 /* ss + dummy */
146 pushl $0xabcdef08 /* fs + gs */
147 pushl $0xabcdef07 /* ds + es */
148 pushl $0xabcdef06 /* gdt:base (physical address) */
149 pushl $0xabcdef05 /* recover address */
150 pushl $0xabcdef04 /* idt:base */
151 pushl $0xabcdef03 /* ldt + idt:limit */
152 pushl $0xabcdef02 /* gdt:base */
153 pushl $0xabcdef01 /* TR + gdt:limit */
154 pushl $0xabcdef00 /* CR0 */
144 /* Get PCB and return address. */
145 movl wakeup_pcb - wakeup_start(%ebx), %esi
146 movl wakeup_ret - wakeup_start(%ebx), %edi
155
147
156 movl %esp,%ebp
157#define CR0_REGISTER 0(%ebp)
158#define TASK_REGISTER 4(%ebp)
159#define PREVIOUS_GDT 6(%ebp)
160#define PREVIOUS_LDT 12(%ebp)
161#define PREVIOUS_IDT 14(%ebp)
162#define RECOVER_ADDR 20(%ebp)
163#define PHYSICAL_GDT_BASE 24(%ebp)
164#define PREVIOUS_DS 28(%ebp)
165#define PREVIOUS_ES 30(%ebp)
166#define PREVIOUS_FS 32(%ebp)
167#define PREVIOUS_GS 34(%ebp)
168#define PREVIOUS_SS 36(%ebp)
148 /* Restore CR4 and CR3. */
149 movl wakeup_cr4 - wakeup_start(%ebx), %eax
150 mov %eax, %cr4
151 movl wakeup_cr3 - wakeup_start(%ebx), %eax
152 mov %eax, %cr3
169
153
170 /* Fixup TSS type field */
171#define TSS_TYPEFIX_MASK 0xf9
172 xorl %esi,%esi
173 movl PHYSICAL_GDT_BASE,%ebx
174 movw TASK_REGISTER,%si
175 leal (%ebx,%esi),%eax /* get TSS segment descriptor */
176 andb $TSS_TYPEFIX_MASK,5(%eax)
154 /*
155 * Finally, switch to long bit mode by enabling paging. We have
156 * to be very careful here because all the segmentation disappears
157 * out from underneath us. The spec says we can depend on the
158 * subsequent pipelined branch to execute, but *only if* everthing
159 * is still identity mapped. If any mappings change, the pipeline
160 * will flush.
161 */
162 mov %cr0, %eax
163 orl $CR0_PG, %eax
164 mov %eax, %cr0
177
165
178 /* Prepare to return to sleep/wakeup code point */
179 lgdtl PREVIOUS_GDT
180 lidtl PREVIOUS_IDT
181
182 /* Pack values from the GDT to be loaded into segment registers. */
183 movl PREVIOUS_DS,%ebx
184 movl PREVIOUS_FS,%ecx
185 movl PREVIOUS_SS,%edx
186 movw TASK_REGISTER,%si
187 shll $16,%esi
188 movw PREVIOUS_LDT,%si
189 movl RECOVER_ADDR,%edi
190
191 /* Enable paging and etc. */
192 movl CR0_REGISTER,%eax
193 movl %eax,%cr0
194
195 /* Flush the prefetch queue */
196 jmp 1f
166 jmp 1f
1971: jmp 1f
1981:
1671:
168 /* Jump to return address. */
169 jmp *%edi
199
170
200 /*
201 * Now we are in kernel virtual memory addressing with the following
202 * original register values:
203 * %ebx: ds + es
204 * %ecx: fs + gs
205 * %edx: ss + dummy
206 * %esi: LDTR + TR
207 * %edi: recover address
208 * We'll load these back into the segment registers now.
209 */
210 nop
171 .data
211
172
212 movl %esi,%eax /* LDTR + TR */
213 lldt %ax /* load LDT register */
214 shrl $16,%eax
215 ltr %ax /* load task register */
173resume_beep:
174 .byte 0
175reset_video:
176 .byte 0
216
177
217 /* Restore segment registers */
218 movl %ebx,%eax /* ds + es */
219 movw %ax,%ds
220 shrl $16,%eax
221 movw %ax,%es
222 movl %ecx,%eax /* fs + gs */
223 movw %ax,%fs
224 shrl $16,%eax
225 movw %ax,%gs
226 movl %edx,%eax /* ss */
227 movw %ax,%ss
178 ALIGN_DATA
179bootgdt:
180 .long 0x00000000
181 .long 0x00000000
228
182
229 /* Jump to acpi_restorecpu() */
230 jmp *%edi
183bootcode32:
184 .long 0x0000ffff
185 .long 0x00cf9b00
231
186
232/* used in real mode */
233physical_gdt: .word 0
234 .long 0
235physical_esp: .long 0
236previous_cr2: .long 0
237previous_cr3: .long 0
238previous_cr4: .long 0
239resume_beep: .long 0
240reset_video: .long 0
187bootdata32:
188 .long 0x0000ffff
189 .long 0x00cf9300
190bootgdtend:
241
191
242/*
243 * Transfer from real mode to protected mode. The order of these variables
244 * is very important, DO NOT INSERT OR CHANGE unless you know why.
245 */
246previous_cr0: .long 0
247previous_tr: .word 0
248previous_gdt: .word 0
249 .long 0
250previous_ldt: .word 0
251previous_idt: .word 0
252 .long 0
253where_to_recover: .long 0
254previous_ds: .word 0
255previous_es: .word 0
256previous_fs: .word 0
257previous_gs: .word 0
258previous_ss: .word 0
259dummy: .word 0
192bootgdtdesc:
193 .word bootgdtend - bootgdt /* Length */
194 .long bootgdt - wakeup_start /* Offset plus %ds << 4 */
195
196 ALIGN_DATA
197wakeup_cr4:
198 .long 0
199wakeup_cr3:
200 .long 0
201wakeup_pcb:
202 .long 0
203wakeup_ret:
204 .long 0
205dummy: