#include <i386/misc_protos.h>
#include <i386/proc_reg.h>
#include <i386/pmap.h>
#include <i386/mtrr.h>
#include <i386/acpi.h>
#include <i386/fpu.h>
#include <i386/mp.h>
#include <i386/mp_desc.h>
#include <kern/cpu_data.h>
#include <IOKit/IOHibernatePrivate.h>
#include <IOKit/IOPlatformExpert.h>
extern void acpi_sleep_cpu(acpi_sleep_callback, void * refcon);
extern char acpi_wake_start[];
extern char acpi_wake_end[];
extern int serial_init(void);
extern unsigned int disableSerialOuput;
extern void set_kbd_leds(int leds);
extern void fpinit(void);
vm_offset_t
acpi_install_wake_handler(void)
{
bcopy_phys(kvtophys((vm_offset_t)acpi_wake_start),
(addr64_t) ACPI_WAKE_ADDR,
acpi_wake_end - acpi_wake_start);
wbinvd();
return ACPI_WAKE_ADDR;
}
typedef struct acpi_hibernate_callback_data {
acpi_sleep_callback func;
void *refcon;
} acpi_hibernate_callback_data;
static void
acpi_hibernate(void *refcon)
{
boolean_t dohalt;
acpi_hibernate_callback_data *data = (acpi_hibernate_callback_data *)refcon;
if (current_cpu_datap()->cpu_hibernate) {
dohalt = hibernate_write_image();
if (dohalt)
{
HIBLOG("power off\n");
if (PE_halt_restart)
(*PE_halt_restart)(kPEHaltCPU);
}
else
{
HIBLOG("sleep\n");
cpu_datap(0)->cpu_hibernate = 0;
}
}
(data->func)(data->refcon);
}
void
acpi_sleep_kernel(acpi_sleep_callback func, void *refcon)
{
acpi_hibernate_callback_data data;
boolean_t did_hibernate;
kprintf("acpi_sleep_kernel hib=%d\n", current_cpu_datap()->cpu_hibernate);
lapic_shutdown();
data.func = func;
data.refcon = refcon;
hpet_save();
if (cpu_mode_is64bit()) {
cpu_IA32e_disable(current_cpu_datap());
kprintf("acpi_sleep_kernel legacy mode re-entered\n");
}
acpi_sleep_cpu(acpi_hibernate, &data);
if (FALSE == disableSerialOuput)
serial_init();
kprintf("ret from acpi_sleep_cpu hib=%d\n", current_cpu_datap()->cpu_hibernate);
if (current_cpu_datap()->cpu_hibernate) {
int i;
for (i=0; i<PMAP_NWINDOWS; i++) {
*current_cpu_datap()->cpu_pmap->mapwindow[i].prv_CMAP = 0;
}
current_cpu_datap()->cpu_hibernate = 0;
did_hibernate = TRUE;
} else {
did_hibernate = FALSE;
}
if (cpu_mode_is64bit()) {
cpu_IA32e_enable(current_cpu_datap());
cpu_desc_load64(current_cpu_datap());
kprintf("acpi_sleep_kernel 64-bit mode re-enabled\n");
fast_syscall_init64();
} else {
fast_syscall_init();
}
mtrr_update_cpu();
pat_init();
if (did_hibernate) {
hibernate_machine_init();
}
if (lapic_probe())
lapic_init();
hpet_restore();
rtc_sleep_wakeup();
fpinit();
clear_fpu();
if (did_hibernate) {
enable_preemption();
}
}