]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/acpi_wakeup.s
xnu-792.10.96.tar.gz
[apple/xnu.git] / osfmk / i386 / acpi_wakeup.s
CommitLineData
91447636
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
91447636 11 *
37839358
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
91447636
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
91447636
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <i386/asm.h>
24#include <i386/proc_reg.h>
25#include <i386/postcode.h>
26#include <i386/acpi.h>
27#include <assym.s>
28
29 .file "acpi_wakeup.s"
30
31 .text
32 .align 12 /* Page align for single bcopy_phys() */
33
34#define LJMP(segment, address) \
35 .byte 0xea ;\
36 .long address - EXT(acpi_wake_start) ;\
37 .word segment
38
c0fea474 39#define PA(addr) (addr)
91447636
A
40
41/*
42 * acpi_wake_start
43 *
44 * The code from acpi_wake_start to acpi_wake_end is copied to
45 * memory below 1MB. The firmware waking vector is updated to
46 * point at acpi_wake_start in low memory before sleeping.
47 */
48
49ENTRY(acpi_wake_start)
50 /*
51 * CPU woke up from sleep, and is back in real mode.
52 * Initialize it just enough to get back to protected mode.
53 */
54 cli
55
56 POSTCODE(ACPI_WAKE_START_ENTRY)
57
58 /* set up DS to match CS */
59 movw %cs, %ax
60 movw %ax, %ds
61
62 /*
63 * Must initialize GDTR before entering protected mode.
64 * Use a temporary GDT that is 0 based, 4GB limit, code and data.
65 * Restoring the actual GDT will come later.
66 */
67 addr16
68 data16
69 lgdt EXT(acpi_gdtr) - EXT(acpi_wake_start)
70
71 /* set CR0.PE to enter protected mode */
72 mov %cr0, %eax
73 data16
74 or $(CR0_PE), %eax
75 mov %eax, %cr0
76
77 /*
78 * Make intra-segment jump to flush pipeline and reload CS register.
79 * If GDT is bogus, it will blow up here.
80 */
81 data16
82 LJMP(0x8, acpi_wake_prot + ACPI_WAKE_ADDR)
83
84acpi_wake_prot:
85
86 /* protected mode, paging disabled */
87
88 /* setup the protected mode segment registers */
89 mov $0x10, %eax
90 movw %ax, %ds
91 movw %ax, %es
92 movw %ax, %ss
93 movw %ax, %fs
94 movw %ax, %gs
95
96 /* jump back to the sleep function in the kernel */
97 movl PA(saved_eip), %eax
98 jmp *%eax
99
100/* Segment Descriptor
101 *
102 * 31 24 19 16 7 0
103 * ------------------------------------------------------------
104 * | | |B| |A| | | |1|0|E|W|A| |
105 * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
106 * | | |D| |L| 19..16| | |1|1|C|R|A| |
107 * ------------------------------------------------------------
108 * | | |
109 * | BASE 15..0 | LIMIT 15..0 |
110 * | | |
111 * ------------------------------------------------------------
112 */
113ENTRY(acpi_gdt)
114 .word 0, 0 /* 0x0 : null */
115 .byte 0, 0, 0, 0
116
117 .word 0xffff, 0x0000 /* 0x8 : code */
118 .byte 0, 0x9e, 0xcf, 0
119
120 .word 0xffff, 0x0000 /* 0x10 : data */
121 .byte 0, 0x92, 0xcf, 0
122
123ENTRY(acpi_gdtr)
124 .word 24 /* limit (8*3 segs) */
125 .long EXT(acpi_gdt) - EXT(acpi_wake_start) + ACPI_WAKE_ADDR
126
127ENTRY(acpi_wake_end)
128
129
130/*
131 * acpi_sleep_cpu(acpi_sleep_callback func, void * refcon)
132 *
133 * Save CPU state before platform sleep. Restore CPU state
134 * following wake up.
135 */
136
137ENTRY(acpi_sleep_cpu)
138 pushl %ebp
139 movl %esp, %ebp
140
141 /* save flags */
142 pushfl
143
144 /* save general purpose registers */
145 pushal
146 movl %esp, saved_esp
147
c0fea474
A
148 /* make sure tlb is flushed */
149 movl %cr3,%eax
150 movl %eax,%cr3
151
91447636
A
152 /* save control registers */
153 movl %cr0, %eax
154 movl %eax, saved_cr0
155 movl %cr2, %eax
156 movl %eax, saved_cr2
157 movl %cr3, %eax
158 movl %eax, saved_cr3
159 movl %cr4, %eax
160 movl %eax, saved_cr4
161
162 /* save segment registers */
163 movw %es, saved_es
164 movw %fs, saved_fs
165 movw %gs, saved_gs
166 movw %ss, saved_ss
167
168 /* save descriptor table registers */
169 sgdt saved_gdt
170 sldt saved_ldt
171 sidt saved_idt
172 str saved_tr
173
174 /*
175 * When system wakes up, the real mode wake handler will revert to
176 * protected mode, then jump to the address stored at saved_eip.
177 */
178 movl $(PA(wake_prot)), saved_eip
179
180 /*
181 * Call ACPI function provided by the caller to sleep the platform.
182 * This call will not return on success.
183 */
184 pushl B_ARG1
185 movl B_ARG0, %edi
186 call *%edi
187 popl %edi
188
189 /* sleep failed, no cpu context lost */
190 jmp wake_restore
191
192wake_prot:
91447636
A
193 /* protected mode, paging disabled */
194 POSTCODE(ACPI_WAKE_PROT_ENTRY)
195
c0fea474
A
196 movl PA(saved_cr3), %ebx
197 movl PA(saved_cr4), %ecx
198 /*
199 * restore cr3, PAE and NXE states in an orderly fashion
200 */
201 movl %ebx, %cr3
202 movl %ecx, %cr4
203
204 movl $(MSR_IA32_EFER), %ecx /* MSR number in ecx */
205 rdmsr /* MSR value return in edx: eax */
206 orl $(MSR_IA32_EFER_NXE), %eax /* Set NXE bit in low 32-bits */
207 wrmsr /* Update Extended Feature Enable reg */
208
91447636
A
209 /* restore kernel GDT */
210 lgdt PA(saved_gdt)
211
91447636
A
212 movl PA(saved_cr2), %eax
213 movl %eax, %cr2
91447636
A
214
215 /* restore CR0, paging enabled */
216 movl PA(saved_cr0), %eax
217 movl %eax, %cr0
218
219 /* switch to kernel code segment */
220 ljmpl $(KERNEL_CS), $wake_paged
221
222wake_paged:
223
224 /* protected mode, paging enabled */
225 POSTCODE(ACPI_WAKE_PAGED_ENTRY)
226
227 /* switch to kernel data segment */
228 movw $(KERNEL_DS), %ax
229 movw %ax, %ds
230
91447636
A
231 /* restore local and interrupt descriptor tables */
232 lldt saved_ldt
233 lidt saved_idt
234
235 /* restore segment registers */
236 movw saved_es, %es
237 movw saved_fs, %fs
238 movw saved_gs, %gs
239 movw saved_ss, %ss
240
241 /*
242 * Restore task register. Before doing this, clear the busy flag
243 * in the TSS descriptor set by the CPU.
244 */
245 movl $saved_gdt, %eax
246 movl 2(%eax), %edx /* GDT base, skip limit word */
247 movl $(KERNEL_TSS), %eax /* TSS segment selector */
248 movb $(K_TSS), 5(%edx, %eax) /* clear busy flag */
249 ltr saved_tr /* restore TR */
250
251wake_restore:
252
253 /* restore general purpose registers */
254 movl saved_esp, %esp
255 popal
256
257 /* restore flags */
258 popfl
259
260 leave
261 ret
262
263
264 .section __HIB, __text
265 .align 2
266
267 .globl EXT(acpi_wake_prot_entry)
268ENTRY(acpi_wake_prot_entry)
269 /* protected mode, paging enabled */
c0fea474 270
91447636
A
271 POSTCODE(ACPI_WAKE_PAGED_ENTRY)
272
273 /* restore kernel GDT */
c0fea474
A
274 lgdt saved_gdt
275
91447636 276 POSTCODE(0x40)
c0fea474 277
91447636 278 /* restore control registers */
c0fea474
A
279
280 movl saved_cr0, %eax
281 movl %eax, %cr0
282
91447636
A
283 movl saved_cr2, %eax
284 movl %eax, %cr2
285
286 POSTCODE(0x3E)
91447636 287
91447636
A
288 /* restore real PDE base */
289 movl saved_cr3, %eax
290 movl saved_cr4, %edx
291 movl %eax, %cr3
292 movl %edx, %cr4
c0fea474 293 movl %eax, %cr3
91447636 294
c0fea474
A
295 /* switch to kernel data segment */
296 movw $(KERNEL_DS), %ax
297 movw %ax, %ds
298
299 POSTCODE(0x3C)
91447636
A
300 /* restore local and interrupt descriptor tables */
301 lldt saved_ldt
302 lidt saved_idt
303
304 POSTCODE(0x3B)
305 /* restore segment registers */
306 movw saved_es, %es
307 movw saved_fs, %fs
308 movw saved_gs, %gs
309 movw saved_ss, %ss
310
311 POSTCODE(0x3A)
312 /*
313 * Restore task register. Before doing this, clear the busy flag
314 * in the TSS descriptor set by the CPU.
315 */
316 movl $saved_gdt, %eax
317 movl 2(%eax), %edx /* GDT base, skip limit word */
318 movl $(KERNEL_TSS), %eax /* TSS segment selector */
319 movb $(K_TSS), 5(%edx, %eax) /* clear busy flag */
320 ltr saved_tr /* restore TR */
321
322 /* restore general purpose registers */
323 movl saved_esp, %esp
324 popal
325
326 /* restore flags */
327 popfl
328
329 /* make sure interrupts are disabled */
330 cli
331
332 movl $2, %eax
333
334 leave
335 ret
336
337
338 .data
339 .section __HIB, __data
340 .align 2
341
342
343/*
344 * CPU registers saved across sleep/wake.
345 */
c0fea474 346
91447636
A
347saved_esp: .long 0
348saved_es: .word 0
349saved_fs: .word 0
350saved_gs: .word 0
351saved_ss: .word 0
352saved_cr0: .long 0
353saved_cr2: .long 0
354saved_cr3: .long 0
355saved_cr4: .long 0
356saved_gdt: .word 0
357 .long 0
358saved_idt: .word 0
359 .long 0
360saved_ldt: .word 0
361saved_tr: .word 0
362saved_eip: .long 0
363