#include <i386/misc_protos.h>
#include <i386/cpu_data.h>
#include <i386/proc_reg.h>
#include <i386/pmap.h>
#include <i386/mtrr.h>
#include <i386/vmx/vmx_cpu.h>
#include <i386/acpi.h>
#include <i386/fpu.h>
#include <i386/mp.h>
#include <i386/mp_desc.h>
#include <i386/serial_io.h>
#include <i386/hpet.h>
#include <i386/machine_check.h>
#include <kern/cpu_data.h>
#include <console/serial_protos.h>
#if HIBERNATION
#include <IOKit/IOHibernatePrivate.h>
#endif
#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 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;
}
#if HIBERNATION
struct acpi_hibernate_callback_data {
acpi_sleep_callback func;
void *refcon;
};
typedef struct acpi_hibernate_callback_data acpi_hibernate_callback_data_t;
static void
acpi_hibernate(void *refcon)
{
uint32_t mode;
acpi_hibernate_callback_data_t *data =
(acpi_hibernate_callback_data_t *)refcon;
if (current_cpu_datap()->cpu_hibernate)
{
cpu_IA32e_enable(current_cpu_datap());
mode = hibernate_write_image();
if( mode == kIOHibernatePostWriteHalt )
{
HIBLOG("power off\n");
if (PE_halt_restart) (*PE_halt_restart)(kPEHaltCPU);
}
else if( mode == kIOHibernatePostWriteRestart )
{
HIBLOG("restart\n");
if (PE_halt_restart) (*PE_halt_restart)(kPERestartCPU);
}
else
{
HIBLOG("sleep\n");
cpu_datap(0)->cpu_hibernate = 0;
}
cpu_IA32e_disable(current_cpu_datap());
}
(data->func)(data->refcon);
}
#endif
static uint64_t acpi_sleep_abstime;
void
acpi_sleep_kernel(acpi_sleep_callback func, void *refcon)
{
#if HIBERNATION
acpi_hibernate_callback_data_t data;
boolean_t did_hibernate;
#endif
kprintf("acpi_sleep_kernel hib=%d\n",
current_cpu_datap()->cpu_hibernate);
lapic_shutdown();
#if HIBERNATION
data.func = func;
data.refcon = refcon;
#endif
hpet_save();
vmx_suspend();
cpu_IA32e_disable(current_cpu_datap());
acpi_sleep_abstime = mach_absolute_time();
#if HIBERNATION
acpi_sleep_cpu(acpi_hibernate, &data);
#else
acpi_sleep_cpu(func, refcon);
#endif
if (FALSE == disable_serial_output)
serial_init();
#if HIBERNATION
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
#endif
{
did_hibernate = FALSE;
}
cpu_mode_init(current_cpu_datap());
mca_cpu_init();
mtrr_update_cpu();
vmx_resume();
pat_init();
rtc_sleep_wakeup(acpi_sleep_abstime);
if (did_hibernate)
hibernate_machine_init();
if (lapic_probe())
lapic_init();
hpet_restore();
rtc_lapic_start_ticking();
fpinit();
clear_fpu();
#if HIBERNATION
if (did_hibernate)
enable_preemption();
kprintf("ret from acpi_sleep_cpu hib=%d\n", did_hibernate);
#endif
}