]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/acpi.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / osfmk / i386 / acpi.c
CommitLineData
91447636 1/*
e2fac8b1 2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
91447636 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#include <i386/misc_protos.h>
2d21ac55 30#include <i386/cpu_data.h>
91447636
A
31#include <i386/proc_reg.h>
32#include <i386/pmap.h>
33#include <i386/mtrr.h>
2d21ac55 34#include <i386/vmx/vmx_cpu.h>
91447636 35#include <i386/acpi.h>
0c530ab8 36#include <i386/fpu.h>
593a1d5f 37#include <i386/lapic.h>
91447636 38#include <i386/mp.h>
0c530ab8 39#include <i386/mp_desc.h>
2d21ac55 40#include <i386/serial_io.h>
0c530ab8 41#include <i386/machine_check.h>
593a1d5f 42#include <i386/pmCPU.h>
91447636
A
43
44#include <kern/cpu_data.h>
2d21ac55 45#include <console/serial_protos.h>
3a60a9f5 46
2d21ac55 47#if HIBERNATION
3a60a9f5 48#include <IOKit/IOHibernatePrivate.h>
2d21ac55 49#endif
91447636
A
50#include <IOKit/IOPlatformExpert.h>
51
52extern void acpi_sleep_cpu(acpi_sleep_callback, void * refcon);
53extern char acpi_wake_start[];
54extern char acpi_wake_end[];
55
91447636
A
56extern void set_kbd_leds(int leds);
57
0c530ab8
A
58extern void fpinit(void);
59
91447636
A
60vm_offset_t
61acpi_install_wake_handler(void)
62{
63 /* copy wake code to ACPI_WAKE_ADDR in low memory */
0c530ab8 64 bcopy_phys(kvtophys((vm_offset_t)acpi_wake_start),
91447636
A
65 (addr64_t) ACPI_WAKE_ADDR,
66 acpi_wake_end - acpi_wake_start);
67
68 /* flush cache */
69 wbinvd();
70
71 /* return physical address of the wakeup code */
72 return ACPI_WAKE_ADDR;
73}
74
2d21ac55
A
75#if HIBERNATION
76struct acpi_hibernate_callback_data {
77 acpi_sleep_callback func;
78 void *refcon;
79};
80typedef struct acpi_hibernate_callback_data acpi_hibernate_callback_data_t;
91447636
A
81
82static void
3a60a9f5 83acpi_hibernate(void *refcon)
91447636 84{
2d21ac55 85 uint32_t mode;
3a60a9f5 86
2d21ac55
A
87 acpi_hibernate_callback_data_t *data =
88 (acpi_hibernate_callback_data_t *)refcon;
91447636 89
2d21ac55 90 if (current_cpu_datap()->cpu_hibernate)
0c530ab8 91 {
2d21ac55
A
92 cpu_IA32e_enable(current_cpu_datap());
93
94 mode = hibernate_write_image();
95
96 if( mode == kIOHibernatePostWriteHalt )
97 {
98 // off
99 HIBLOG("power off\n");
100 if (PE_halt_restart) (*PE_halt_restart)(kPEHaltCPU);
101 }
102 else if( mode == kIOHibernatePostWriteRestart )
103 {
104 // restart
105 HIBLOG("restart\n");
106 if (PE_halt_restart) (*PE_halt_restart)(kPERestartCPU);
107 }
108 else
109 {
110 // sleep
111 HIBLOG("sleep\n");
112
113 // should we come back via regular wake, set the state in memory.
114 cpu_datap(0)->cpu_hibernate = 0;
115 }
116
117 /*
118 * If we're in 64-bit mode, drop back into legacy mode during sleep.
119 */
120 cpu_IA32e_disable(current_cpu_datap());
0c530ab8 121
0c530ab8 122 }
91447636 123
2d21ac55 124 (data->func)(data->refcon);
91447636 125
2d21ac55 126 /* should never get here! */
91447636 127}
2d21ac55 128#endif
91447636 129
0c530ab8
A
130static uint64_t acpi_sleep_abstime;
131
91447636
A
132void
133acpi_sleep_kernel(acpi_sleep_callback func, void *refcon)
134{
2d21ac55
A
135#if HIBERNATION
136 acpi_hibernate_callback_data_t data;
137 boolean_t did_hibernate;
138#endif
e2fac8b1
A
139 unsigned int cpu;
140 kern_return_t rc;
141 unsigned int my_cpu;
91447636 142
2d21ac55
A
143 kprintf("acpi_sleep_kernel hib=%d\n",
144 current_cpu_datap()->cpu_hibernate);
0c530ab8 145
e2fac8b1
A
146 /* Geta ll CPUs to be in the "off" state */
147 my_cpu = cpu_number();
148 for (cpu = 0; cpu < real_ncpus; cpu += 1) {
149 if (cpu == my_cpu)
150 continue;
151 rc = pmCPUExitHaltToOff(cpu);
152 if (rc != KERN_SUCCESS)
153 panic("Error %d trying to transition CPU %d to OFF",
154 rc, cpu);
155 }
156
2d21ac55
A
157 /* shutdown local APIC before passing control to BIOS */
158 lapic_shutdown();
91447636 159
2d21ac55
A
160#if HIBERNATION
161 data.func = func;
162 data.refcon = refcon;
163#endif
91447636 164
593a1d5f
A
165 /* Save power management timer state */
166 pmTimerSave();
0c530ab8 167
2d21ac55
A
168 /*
169 * Turn off VT, otherwise switching to legacy mode will fail
170 */
171 vmx_suspend();
172
173 /*
174 * If we're in 64-bit mode, drop back into legacy mode during sleep.
175 */
0c530ab8 176 cpu_IA32e_disable(current_cpu_datap());
0c530ab8
A
177
178 acpi_sleep_abstime = mach_absolute_time();
2d21ac55
A
179
180 /*
181 * Save master CPU state and sleep platform.
182 * Will not return until platform is woken up,
183 * or if sleep failed.
184 */
185#if HIBERNATION
186 acpi_sleep_cpu(acpi_hibernate, &data);
187#else
188 acpi_sleep_cpu(func, refcon);
189#endif
190
4a3eedf9
A
191 /* Reset UART if kprintf is enabled.
192 * However kprintf should not be used before rtc_sleep_wakeup()
193 * for compatibility with firewire kprintf.
194 */
195
2d21ac55
A
196 if (FALSE == disable_serial_output)
197 serial_init();
198
199#if HIBERNATION
200 if (current_cpu_datap()->cpu_hibernate) {
201 int i;
202 for (i = 0; i < PMAP_NWINDOWS; i++)
203 *current_cpu_datap()->cpu_pmap->mapwindow[i].prv_CMAP = 0;
204 current_cpu_datap()->cpu_hibernate = 0;
205 did_hibernate = TRUE;
206
207 } else
208#endif
209 {
210 did_hibernate = FALSE;
0c530ab8 211 }
3a60a9f5 212
2d21ac55
A
213 /* Re-enable mode (including 64-bit if applicable) */
214 cpu_mode_init(current_cpu_datap());
3a60a9f5 215
2d21ac55
A
216 /* Re-enable machine check handling */
217 mca_cpu_init();
91447636 218
2d21ac55
A
219 /* restore MTRR settings */
220 mtrr_update_cpu();
0c530ab8 221
2d21ac55
A
222 /*
223 * Restore VT mode
224 */
225 vmx_resume();
0c530ab8 226
2d21ac55
A
227 /* set up PAT following boot processor power up */
228 pat_init();
91447636 229
593a1d5f
A
230 /*
231 * Go through all of the CPUs and mark them as requiring
232 * a full restart.
233 */
234 pmMarkAllCPUsOff();
235
0c530ab8
A
236 /* let the realtime clock reset */
237 rtc_sleep_wakeup(acpi_sleep_abstime);
91447636 238
2d21ac55
A
239 if (did_hibernate)
240 hibernate_machine_init();
241
242 /* re-enable and re-init local apic */
243 if (lapic_probe())
593a1d5f
A
244 lapic_configure();
245
246 /* Restore power management register state */
247 pmCPUMarkRunning(current_cpu_datap());
91447636 248
593a1d5f
A
249 /* Restore power management timer state */
250 pmTimerRestore();
0c530ab8
A
251
252 /* Restart tick interrupts from the LAPIC timer */
253 rtc_lapic_start_ticking();
254
2d21ac55
A
255 fpinit();
256 clear_fpu();
257
258#if HIBERNATION
259 if (did_hibernate)
260 enable_preemption();
91447636 261
2d21ac55
A
262 kprintf("ret from acpi_sleep_cpu hib=%d\n", did_hibernate);
263#endif
91447636 264}