2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <i386/proc_reg.h>
26 #include <i386/postcode.h>
27 #include <i386/acpi.h>
33 .align 12 /* Page align for single bcopy_phys() */
35 #define LJMP(segment, address) \
37 .long address - EXT(acpi_wake_start) ;\
40 #define PA(addr) ((addr)-KERNELBASE)
45 * The code from acpi_wake_start to acpi_wake_end is copied to
46 * memory below 1MB. The firmware waking vector is updated to
47 * point at acpi_wake_start in low memory before sleeping.
50 ENTRY(acpi_wake_start)
52 * CPU woke up from sleep, and is back in real mode.
53 * Initialize it just enough to get back to protected mode.
57 POSTCODE(ACPI_WAKE_START_ENTRY)
59 /* set up DS to match CS */
64 * Must initialize GDTR before entering protected mode.
65 * Use a temporary GDT that is 0 based, 4GB limit, code and data.
66 * Restoring the actual GDT will come later.
70 lgdt EXT(acpi_gdtr) - EXT(acpi_wake_start)
72 /* set CR0.PE to enter protected mode */
79 * Make intra-segment jump to flush pipeline and reload CS register.
80 * If GDT is bogus, it will blow up here.
83 LJMP(0x8, acpi_wake_prot + ACPI_WAKE_ADDR)
87 /* protected mode, paging disabled */
89 /* setup the protected mode segment registers */
97 /* jump back to the sleep function in the kernel */
98 movl PA(saved_eip), %eax
101 /* Segment Descriptor
104 * ------------------------------------------------------------
105 * | | |B| |A| | | |1|0|E|W|A| |
106 * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
107 * | | |D| |L| 19..16| | |1|1|C|R|A| |
108 * ------------------------------------------------------------
110 * | BASE 15..0 | LIMIT 15..0 |
112 * ------------------------------------------------------------
115 .word 0, 0 /* 0x0 : null */
118 .word 0xffff, 0x0000 /* 0x8 : code */
119 .byte 0, 0x9e, 0xcf, 0
121 .word 0xffff, 0x0000 /* 0x10 : data */
122 .byte 0, 0x92, 0xcf, 0
125 .word 24 /* limit (8*3 segs) */
126 .long EXT(acpi_gdt) - EXT(acpi_wake_start) + ACPI_WAKE_ADDR
132 * acpi_sleep_cpu(acpi_sleep_callback func, void * refcon)
134 * Save CPU state before platform sleep. Restore CPU state
138 ENTRY(acpi_sleep_cpu)
145 /* save general purpose registers */
149 /* save control registers */
159 /* save segment registers */
165 /* save descriptor table registers */
172 * When system wakes up, the real mode wake handler will revert to
173 * protected mode, then jump to the address stored at saved_eip.
175 movl $(PA(wake_prot)), saved_eip
178 * Call ACPI function provided by the caller to sleep the platform.
179 * This call will not return on success.
186 /* sleep failed, no cpu context lost */
191 /* protected mode, paging disabled */
192 POSTCODE(ACPI_WAKE_PROT_ENTRY)
194 /* restore kernel GDT */
197 /* restore control registers */
198 movl PA(saved_cr2), %eax
202 movl PA(EXT(IdlePDPT)), %eax
203 movl (%eax), %esi /* save orig */
205 movl %ebx, (%eax) /* identity map low mem */
208 movl PA(saved_cr4), %eax
211 movl PA(saved_cr4), %eax
215 * Temporarily use the page tables at IdlePTD
216 * to enable paging. Copy the KPTDI entry to
217 * entry 0 in the PTD to identity map the kernel.
219 movl PA(EXT(IdlePTD)), %eax
221 addl $(KPTDI << PTEINDX), %ebx /* bytes per PDE */
222 movl (%ebx), %ebx /* IdlePTD[KPTDI] */
223 movl (%eax), %esi /* save original IdlePTD[0] */
224 movl %ebx, (%eax) /* update IdlePTD[0] */
225 movl %eax, %cr3 /* CR3 = IdlePTD */
228 /* restore CR0, paging enabled */
229 movl PA(saved_cr0), %eax
232 /* switch to kernel code segment */
233 ljmpl $(KERNEL_CS), $wake_paged
237 /* protected mode, paging enabled */
238 POSTCODE(ACPI_WAKE_PAGED_ENTRY)
240 /* switch to kernel data segment */
241 movw $(KERNEL_DS), %ax
244 /* undo changes to IdlePTD */
246 movl EXT(IdlePDPT), %eax
248 movl EXT(IdlePTD), %eax
250 addl $(KERNELBASE), %eax /* make virtual */
253 /* restore real PDE base */
258 /* restore local and interrupt descriptor tables */
262 /* restore segment registers */
269 * Restore task register. Before doing this, clear the busy flag
270 * in the TSS descriptor set by the CPU.
272 movl $saved_gdt, %eax
273 movl 2(%eax), %edx /* GDT base, skip limit word */
274 movl $(KERNEL_TSS), %eax /* TSS segment selector */
275 movb $(K_TSS), 5(%edx, %eax) /* clear busy flag */
276 ltr saved_tr /* restore TR */
280 /* restore general purpose registers */
291 .section __HIB, __text
294 .globl EXT(acpi_wake_prot_entry)
295 ENTRY(acpi_wake_prot_entry)
296 /* protected mode, paging enabled */
297 POSTCODE(ACPI_WAKE_PAGED_ENTRY)
299 /* restore kernel GDT */
303 /* restore control registers */
308 /* switch to kernel data segment */
309 movw $(KERNEL_DS), %ax
313 /* restore real PDE base */
320 /* restore local and interrupt descriptor tables */
325 /* restore segment registers */
333 * Restore task register. Before doing this, clear the busy flag
334 * in the TSS descriptor set by the CPU.
336 movl $saved_gdt, %eax
337 movl 2(%eax), %edx /* GDT base, skip limit word */
338 movl $(KERNEL_TSS), %eax /* TSS segment selector */
339 movb $(K_TSS), 5(%edx, %eax) /* clear busy flag */
340 ltr saved_tr /* restore TR */
342 /* restore general purpose registers */
349 /* make sure interrupts are disabled */
359 .section __HIB, __data
364 * CPU registers saved across sleep/wake.