]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/acpi.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / osfmk / i386 / acpi.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <i386/misc_protos.h>
24 #include <i386/proc_reg.h>
25 #include <i386/pmap.h>
26 #include <i386/mtrr.h>
27 #include <i386/acpi.h>
28 #include <i386/fpu.h>
29 #include <i386/mp.h>
30 #include <i386/mp_desc.h>
31
32 #include <kern/cpu_data.h>
33
34 #include <IOKit/IOHibernatePrivate.h>
35 #include <IOKit/IOPlatformExpert.h>
36
37 extern void acpi_sleep_cpu(acpi_sleep_callback, void * refcon);
38 extern char acpi_wake_start[];
39 extern char acpi_wake_end[];
40
41 extern int serial_init(void);
42 extern unsigned int disableSerialOuput;
43
44 extern void set_kbd_leds(int leds);
45
46 extern void fpinit(void);
47
48 vm_offset_t
49 acpi_install_wake_handler(void)
50 {
51 /* copy wake code to ACPI_WAKE_ADDR in low memory */
52 bcopy_phys(kvtophys((vm_offset_t)acpi_wake_start),
53 (addr64_t) ACPI_WAKE_ADDR,
54 acpi_wake_end - acpi_wake_start);
55
56 /* flush cache */
57 wbinvd();
58
59 /* return physical address of the wakeup code */
60 return ACPI_WAKE_ADDR;
61 }
62
63 typedef struct acpi_hibernate_callback_data {
64 acpi_sleep_callback func;
65 void *refcon;
66 } acpi_hibernate_callback_data;
67
68 static void
69 acpi_hibernate(void *refcon)
70 {
71 boolean_t dohalt;
72
73 acpi_hibernate_callback_data *data = (acpi_hibernate_callback_data *)refcon;
74
75 if (current_cpu_datap()->cpu_hibernate) {
76
77 dohalt = hibernate_write_image();
78 if (dohalt)
79 {
80 // off
81 HIBLOG("power off\n");
82 if (PE_halt_restart)
83 (*PE_halt_restart)(kPEHaltCPU);
84 }
85 else
86 {
87 // sleep
88 HIBLOG("sleep\n");
89
90 // should we come back via regular wake, set the state in memory.
91 cpu_datap(0)->cpu_hibernate = 0;
92 }
93 }
94
95 (data->func)(data->refcon);
96
97 /* should never get here! */
98 }
99
100 void
101 acpi_sleep_kernel(acpi_sleep_callback func, void *refcon)
102 {
103 acpi_hibernate_callback_data data;
104 boolean_t did_hibernate;
105
106 kprintf("acpi_sleep_kernel hib=%d\n", current_cpu_datap()->cpu_hibernate);
107
108 /* shutdown local APIC before passing control to BIOS */
109 lapic_shutdown();
110
111 data.func = func;
112 data.refcon = refcon;
113
114 /* Save HPET state */
115 hpet_save();
116
117 /*
118 * If we're in 64-bit mode, drop back into legacy mode during sleep.
119 */
120 if (cpu_mode_is64bit()) {
121 cpu_IA32e_disable(current_cpu_datap());
122 kprintf("acpi_sleep_kernel legacy mode re-entered\n");
123 }
124
125 /*
126 * Save master CPU state and sleep platform.
127 * Will not return until platform is woken up,
128 * or if sleep failed.
129 */
130 acpi_sleep_cpu(acpi_hibernate, &data);
131
132 /* reset UART if kprintf is enabled */
133 if (FALSE == disableSerialOuput)
134 serial_init();
135
136 kprintf("ret from acpi_sleep_cpu hib=%d\n", current_cpu_datap()->cpu_hibernate);
137
138 if (current_cpu_datap()->cpu_hibernate) {
139 int i;
140 for (i=0; i<PMAP_NWINDOWS; i++) {
141 *current_cpu_datap()->cpu_pmap->mapwindow[i].prv_CMAP = 0;
142 }
143 current_cpu_datap()->cpu_hibernate = 0;
144 did_hibernate = TRUE;
145
146 } else {
147 did_hibernate = FALSE;
148 }
149
150 /* Re-enable 64-bit mode if necessary. */
151 if (cpu_mode_is64bit()) {
152 cpu_IA32e_enable(current_cpu_datap());
153 cpu_desc_load64(current_cpu_datap());
154 kprintf("acpi_sleep_kernel 64-bit mode re-enabled\n");
155 fast_syscall_init64();
156 } else {
157 fast_syscall_init();
158 }
159
160 /* restore MTRR settings */
161 mtrr_update_cpu();
162
163 /* set up PAT following boot processor power up */
164 pat_init();
165
166 if (did_hibernate) {
167 hibernate_machine_init();
168 }
169
170 /* re-enable and re-init local apic */
171 if (lapic_probe())
172 lapic_init();
173
174 /* Restore HPET state */
175 hpet_restore();
176
177 /* let the realtime clock reset */
178 rtc_sleep_wakeup();
179
180 fpinit();
181 clear_fpu();
182
183 if (did_hibernate) {
184 enable_preemption();
185 }
186 }