ia64/xen-unstable

changeset 15582:24379dde8ac4

Provide basic Xen PM infrastructure

Basic infrastructure for Xen S3 support with a common CPU
context save/restore logic for both 32bit and 64bit.

Wakeup code is split into two parts:
- the first locates after trampoline code, to share all the
tricks on the latter, like relocation base and identy mapping
- the 2nd part locates in xen code segment, to do the actual
CPU context restore

Signed-off-by Ke Yu <ke.yu@intel.com>
Signed-off-by Kevin Tian <kevin.tian@intel.com>
author kfraser@localhost.localdomain
date Wed Jul 11 15:47:14 2007 +0100 (2007-07-11)
parents c6491ed12f84
children ad11f74d298c
files xen/arch/x86/acpi/Makefile xen/arch/x86/acpi/power.c xen/arch/x86/acpi/suspend.c xen/arch/x86/acpi/wakeup_prot.S xen/arch/x86/boot/Makefile xen/arch/x86/boot/head.S xen/arch/x86/boot/wakeup.S xen/arch/x86/dmi_scan.c xen/arch/x86/platform_hypercall.c xen/include/asm-x86/acpi.h xen/include/asm-x86/config.h xen/include/public/platform.h
line diff
     1.1 --- a/xen/arch/x86/acpi/Makefile	Wed Jul 11 13:49:11 2007 +0100
     1.2 +++ b/xen/arch/x86/acpi/Makefile	Wed Jul 11 15:47:14 2007 +0100
     1.3 @@ -1,1 +1,2 @@
     1.4  obj-y += boot.o
     1.5 +obj-y += power.o suspend.o wakeup_prot.o
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/xen/arch/x86/acpi/power.c	Wed Jul 11 15:47:14 2007 +0100
     2.3 @@ -0,0 +1,258 @@
     2.4 +/* drivers/acpi/sleep/power.c - PM core functionality for Xen
     2.5 + *
     2.6 + * Copyrights from Linux side:
     2.7 + * Copyright (c) 2000-2003 Patrick Mochel
     2.8 + * Copyright (C) 2001-2003 Pavel Machek <pavel@suse.cz>
     2.9 + * Copyright (c) 2003 Open Source Development Lab
    2.10 + * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
    2.11 + * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    2.12 + *
    2.13 + * Slimmed with Xen specific support.
    2.14 + */
    2.15 +
    2.16 +#include <xen/config.h>
    2.17 +#include <asm/io.h>
    2.18 +#include <asm/acpi.h>
    2.19 +#include <xen/acpi.h>
    2.20 +#include <xen/errno.h>
    2.21 +#include <xen/iocap.h>
    2.22 +#include <xen/sched.h>
    2.23 +#include <asm/acpi.h>
    2.24 +#include <asm/irq.h>
    2.25 +#include <asm/init.h>
    2.26 +#include <xen/spinlock.h>
    2.27 +#include <xen/sched.h>
    2.28 +#include <xen/domain.h>
    2.29 +#include <xen/console.h>
    2.30 +#include <public/platform.h>
    2.31 +
    2.32 +#define pmprintk(_l, _f, _a...) printk(_l "<PM>" _f, ## _a )
    2.33 +
    2.34 +u8 sleep_states[ACPI_S_STATE_COUNT];
    2.35 +DEFINE_SPINLOCK(pm_lock);
    2.36 +
    2.37 +struct acpi_sleep_info {
    2.38 +    uint16_t pm1a_cnt;
    2.39 +    uint16_t pm1b_cnt;
    2.40 +    uint16_t pm1a_evt;
    2.41 +    uint16_t pm1b_evt;
    2.42 +    uint16_t pm1a_cnt_val;
    2.43 +    uint16_t pm1b_cnt_val;
    2.44 +    uint32_t sleep_state;
    2.45 +} acpi_sinfo;
    2.46 +
    2.47 +extern void do_suspend_lowlevel(void);
    2.48 +
    2.49 +static char *acpi_states[ACPI_S_STATE_COUNT] =
    2.50 +{
    2.51 +    [ACPI_STATE_S1] = "standby",
    2.52 +    [ACPI_STATE_S3] = "mem",
    2.53 +    [ACPI_STATE_S4] = "disk",
    2.54 +};
    2.55 +
    2.56 +unsigned long acpi_video_flags;
    2.57 +unsigned long saved_videomode;
    2.58 +
    2.59 +/* XXX: Add suspend failure recover later */
    2.60 +static int device_power_down(void)
    2.61 +{
    2.62 +    console_suspend();
    2.63 +
    2.64 +    time_suspend();
    2.65 +
    2.66 +    i8259A_suspend();
    2.67 +    
    2.68 +    ioapic_suspend();
    2.69 +    
    2.70 +    lapic_suspend();
    2.71 +
    2.72 +    return 0;
    2.73 +}
    2.74 +
    2.75 +static void device_power_up(void)
    2.76 +{
    2.77 +    lapic_resume();
    2.78 +    
    2.79 +    ioapic_resume();
    2.80 +
    2.81 +    i8259A_resume();
    2.82 +    
    2.83 +    time_resume();
    2.84 +
    2.85 +    console_resume();
    2.86 +}
    2.87 +
    2.88 +/* Main interface to do xen specific suspend/resume */
    2.89 +int enter_state(u32 state)
    2.90 +{
    2.91 +    struct domain *d;
    2.92 +    unsigned long flags;
    2.93 +    int error;
    2.94 +
    2.95 +    if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
    2.96 +        return -EINVAL;
    2.97 +
    2.98 +    /* Sync lazy state on ths cpu */
    2.99 +    __sync_lazy_execstate();
   2.100 +    pmprintk(XENLOG_INFO, "Flush lazy state\n");
   2.101 +
   2.102 +    if (!spin_trylock(&pm_lock))
   2.103 +        return -EBUSY;
   2.104 +    
   2.105 +    for_each_domain(d)
   2.106 +        if (d->domain_id != 0)
   2.107 +            domain_pause(d);
   2.108 +
   2.109 +    pmprintk(XENLOG_INFO, "PM: Preparing system for %s sleep\n",
   2.110 +        acpi_states[state]);
   2.111 +
   2.112 +    local_irq_save(flags);
   2.113 +
   2.114 +    if ((error = device_power_down()))
   2.115 +    {
   2.116 +        printk(XENLOG_ERR "Some devices failed to power down\n");
   2.117 +        goto Done;
   2.118 +    }
   2.119 +
   2.120 +    ACPI_FLUSH_CPU_CACHE();
   2.121 +
   2.122 +    switch (state)
   2.123 +    {
   2.124 +        case ACPI_STATE_S3:
   2.125 +            do_suspend_lowlevel();
   2.126 +            break;
   2.127 +        default:
   2.128 +            error = -EINVAL;
   2.129 +            break;
   2.130 +    }
   2.131 +
   2.132 +    pmprintk(XENLOG_INFO, "Back to C!\n");
   2.133 +
   2.134 +    device_power_up();
   2.135 +
   2.136 +    pmprintk(XENLOG_INFO, "PM: Finishing wakeup.\n");
   2.137 +
   2.138 + Done:
   2.139 +    local_irq_restore(flags);
   2.140 +
   2.141 +    for_each_domain(d)
   2.142 +       if (d->domain_id!=0)
   2.143 +           domain_unpause(d);
   2.144 +
   2.145 +    spin_unlock(&pm_lock);
   2.146 +    return error;
   2.147 +
   2.148 +}
   2.149 +
   2.150 +/*
   2.151 + * Xen just requires address of pm1x_cnt, and ACPI interpreter
   2.152 + * is still kept in dom0. Address of xen wakeup stub will be
   2.153 + * returned, and then dom0 writes that address to FACS.
   2.154 + */
   2.155 +int set_acpi_sleep_info(struct xenpf_set_acpi_sleep *info)
   2.156 +{
   2.157 +    if (acpi_sinfo.pm1a_cnt)
   2.158 +        pmprintk(XENLOG_WARNING, "Multiple setting on acpi sleep info\n");
   2.159 +
   2.160 +    acpi_sinfo.pm1a_cnt = info->pm1a_cnt_port;
   2.161 +    acpi_sinfo.pm1b_cnt = info->pm1b_cnt_port;
   2.162 +    acpi_sinfo.pm1a_evt = info->pm1a_evt_port;
   2.163 +    acpi_sinfo.pm1b_evt = info->pm1b_evt_port;
   2.164 +    info->xen_waking_vec = (uint64_t)bootsym_phys(wakeup_start);
   2.165 +
   2.166 +    pmprintk(XENLOG_INFO, "pm1a[%x],pm1b[%x],pm1a_e[%x],pm1b_e[%x]"
   2.167 +                       "wake[%"PRIx64"]",
   2.168 +                       acpi_sinfo.pm1a_cnt, acpi_sinfo.pm1b_cnt,
   2.169 +                       acpi_sinfo.pm1a_evt, acpi_sinfo.pm1b_evt,
   2.170 +                       info->xen_waking_vec);
   2.171 +    return 0;
   2.172 +}
   2.173 +
   2.174 +/*
   2.175 + * Dom0 issues this hypercall in place of writing pm1a_cnt. Xen then
   2.176 + * takes over the control and put the system into sleep state really.
   2.177 + * Also video flags and mode are passed here, in case user may use
   2.178 + * "acpi_sleep=***" for video resume.
   2.179 + *
   2.180 + * Guest may issue a two-phases write to PM1x_CNT, to work
   2.181 + * around poorly implemented hardware. It's better to keep
   2.182 + * this logic here. Two writes can be differentiated by 
   2.183 + * enable bit setting.
   2.184 + */
   2.185 +int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
   2.186 +{
   2.187 +    if (!IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt)
   2.188 +        return -EPERM;
   2.189 +
   2.190 +    /* Sanity check */
   2.191 +    if (acpi_sinfo.pm1b_cnt_val &&
   2.192 +        ((sleep->pm1a_cnt_val ^ sleep->pm1b_cnt_val) &
   2.193 +        ACPI_BITMASK_SLEEP_ENABLE))
   2.194 +    {
   2.195 +        pmprintk(XENLOG_ERR, "Mismatched pm1a/pm1b setting\n");
   2.196 +        return -EINVAL;
   2.197 +    }
   2.198 +
   2.199 +    /* Write #1 */
   2.200 +    if (!(sleep->pm1a_cnt_val & ACPI_BITMASK_SLEEP_ENABLE))
   2.201 +    {
   2.202 +        outw((u16)sleep->pm1a_cnt_val, acpi_sinfo.pm1a_cnt);
   2.203 +        if (acpi_sinfo.pm1b_cnt)
   2.204 +            outw((u16)sleep->pm1b_cnt_val, acpi_sinfo.pm1b_cnt);
   2.205 +        return 0;
   2.206 +    }
   2.207 +
   2.208 +    /* Write #2 */
   2.209 +    acpi_sinfo.pm1a_cnt_val = sleep->pm1a_cnt_val;
   2.210 +    acpi_sinfo.pm1b_cnt_val = sleep->pm1b_cnt_val;
   2.211 +    acpi_sinfo.sleep_state = sleep->sleep_state;
   2.212 +    acpi_video_flags = sleep->video_flags;
   2.213 +    saved_videomode = sleep->video_mode;
   2.214 +
   2.215 +    return enter_state(acpi_sinfo.sleep_state);
   2.216 +}
   2.217 +
   2.218 +static int acpi_get_wake_status(void)
   2.219 +{
   2.220 +    uint16_t val;
   2.221 +
   2.222 +    /* Wake status is the 15th bit of PM1 status register. (ACPI spec 3.0) */
   2.223 +    val = inw(acpi_sinfo.pm1a_evt) | inw(acpi_sinfo.pm1b_evt);
   2.224 +    val &= ACPI_BITMASK_WAKE_STATUS;
   2.225 +    val >>= ACPI_BITPOSITION_WAKE_STATUS;
   2.226 +    return val;
   2.227 +}
   2.228 +
   2.229 +/* System is really put into sleep state by this stub */
   2.230 +acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
   2.231 +{
   2.232 +    ACPI_FLUSH_CPU_CACHE();
   2.233 +
   2.234 +    outw((u16)acpi_sinfo.pm1a_cnt_val, acpi_sinfo.pm1a_cnt);
   2.235 +    if (acpi_sinfo.pm1b_cnt)
   2.236 +        outw((u16)acpi_sinfo.pm1b_cnt_val, acpi_sinfo.pm1b_cnt);
   2.237 +    
   2.238 +    /* Wait until we enter sleep state, and spin until we wake */
   2.239 +    while (!acpi_get_wake_status());
   2.240 +    return_ACPI_STATUS(AE_OK);
   2.241 +}
   2.242 +
   2.243 +static int __init acpi_sleep_init(void)
   2.244 +{
   2.245 +    int i = 0; 
   2.246 +
   2.247 +    pmprintk(XENLOG_INFO, "ACPI (supports");
   2.248 +    for (i = 0; i < ACPI_S_STATE_COUNT; i++)
   2.249 +    {
   2.250 +        if (i == ACPI_STATE_S3)
   2.251 +        {
   2.252 +            sleep_states[i] = 1;
   2.253 +            printk(" S%d", i);
   2.254 +        }
   2.255 +        else
   2.256 +            sleep_states[i] = 0;
   2.257 +    }
   2.258 +    printk(")\n");
   2.259 +    return 0;
   2.260 +}
   2.261 +__initcall(acpi_sleep_init);
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/xen/arch/x86/acpi/suspend.c	Wed Jul 11 15:47:14 2007 +0100
     3.3 @@ -0,0 +1,85 @@
     3.4 +/*
     3.5 + * Suspend support specific for i386.
     3.6 + *
     3.7 + * Distribute under GPLv2
     3.8 + *
     3.9 + * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
    3.10 + * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
    3.11 + */
    3.12 +#include <xen/config.h>
    3.13 +#include <xen/acpi.h>
    3.14 +#include <xen/smp.h>
    3.15 +#include <asm/processor.h>
    3.16 +#include <asm/msr.h>
    3.17 +#include <asm/flushtlb.h>
    3.18 +#include <asm/hvm/hvm.h>
    3.19 +#include <asm/hvm/support.h>
    3.20 +#include <asm/i387.h>
    3.21 +
    3.22 +/* Following context save/restore happens on the real context
    3.23 + * of current vcpu, with a lazy state sync forced earlier. 
    3.24 + */
    3.25 +#if defined(CONFIG_X86_64)
    3.26 +unsigned long saved_lstar, saved_cstar;
    3.27 +#endif
    3.28 +void save_rest_processor_state(void)
    3.29 +{
    3.30 +    /*
    3.31 +     * Net effect of unlazy_fpu is to set cr0.ts and thus there's no
    3.32 +     * need to restore fpu after resume.
    3.33 +     */
    3.34 +    if (!is_idle_vcpu(current))
    3.35 +        unlazy_fpu(current);
    3.36 +
    3.37 +#if defined(CONFIG_X86_64)
    3.38 +    rdmsrl(MSR_CSTAR, saved_cstar);
    3.39 +    rdmsrl(MSR_LSTAR, saved_lstar);
    3.40 +#endif
    3.41 +
    3.42 +    bootsym(video_flags) = acpi_video_flags;
    3.43 +    bootsym(video_mode) = saved_videomode;
    3.44 +}
    3.45 +
    3.46 +#define loaddebug(_v,_reg) \
    3.47 +    __asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
    3.48 +
    3.49 +void restore_rest_processor_state(void)
    3.50 +{
    3.51 +    int cpu = smp_processor_id();
    3.52 +    struct tss_struct *t = &init_tss[cpu];
    3.53 +    struct vcpu *v = current;
    3.54 +
    3.55 +    /* Really scared by suffixed comment from Linux, and keep it for safe */
    3.56 +    set_tss_desc(cpu, t);    /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
    3.57 +
    3.58 +    load_TR(cpu);
    3.59 +
    3.60 +#if defined(CONFIG_X86_64)
    3.61 +    /* Recover syscall MSRs */
    3.62 +    wrmsrl(MSR_LSTAR, saved_lstar);
    3.63 +    wrmsrl(MSR_CSTAR, saved_cstar);
    3.64 +    wrmsr(MSR_STAR, 0, (FLAT_RING3_CS32<<16) | __HYPERVISOR_CS);
    3.65 +    wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);    
    3.66 +#else /* !defined(CONFIG_X86_64) */
    3.67 +    if (supervisor_mode_kernel && cpu_has_sep)
    3.68 +        wrmsr(MSR_IA32_SYSENTER_ESP, &t->esp1, 0);
    3.69 +#endif
    3.70 +
    3.71 +    /* Maybe load the debug registers. */
    3.72 +    if ( !is_idle_vcpu(v) && unlikely(v->arch.guest_context.debugreg[7]) )
    3.73 +    {
    3.74 +        loaddebug(&v->arch.guest_context, 0);
    3.75 +        loaddebug(&v->arch.guest_context, 1);
    3.76 +        loaddebug(&v->arch.guest_context, 2);
    3.77 +        loaddebug(&v->arch.guest_context, 3);
    3.78 +        /* no 4 and 5 */
    3.79 +        loaddebug(&v->arch.guest_context, 6);
    3.80 +        loaddebug(&v->arch.guest_context, 7);
    3.81 +    }
    3.82 +
    3.83 +    /* Do we start fpu really? Just set cr0.ts to monitor it */
    3.84 +    stts();
    3.85 +
    3.86 +    mtrr_ap_init();
    3.87 +    mcheck_init(&boot_cpu_data);
    3.88 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/xen/arch/x86/acpi/wakeup_prot.S	Wed Jul 11 15:47:14 2007 +0100
     4.3 @@ -0,0 +1,267 @@
     4.4 +        .text
     4.5 +
     4.6 +#include <xen/config.h>
     4.7 +#include <xen/multiboot.h>
     4.8 +#include <public/xen.h>
     4.9 +#include <asm/asm_defns.h>
    4.10 +#include <asm/desc.h>
    4.11 +#include <asm/page.h>
    4.12 +#include <asm/msr.h>
    4.13 +
    4.14 +#if defined(__x86_64__)
    4.15 +
    4.16 +        .code64
    4.17 +
    4.18 +#define GREG(x)         %r##x
    4.19 +#define SAVED_GREG(x)   saved_r##x(%rip)
    4.20 +#define DECLARE_GREG(x) saved_r##x:     .quad   0
    4.21 +#define SAVE_GREG(x)    movq GREG(x), SAVED_GREG(x)
    4.22 +#define LOAD_GREG(x)    movq SAVED_GREG(x), GREG(x)
    4.23 +
    4.24 +#define REF(x)          x(%rip)
    4.25 +
    4.26 +#define RDMSR(ind, m)                   \
    4.27 +        xorq    %rdx, %rdx;             \
    4.28 +        mov     $ind, %ecx;             \
    4.29 +        rdmsr;                          \
    4.30 +        shlq    $0x20, %rdx;              \
    4.31 +        orq     %rax, %rdx;             \
    4.32 +        movq    %rdx, m(%rip);
    4.33 +
    4.34 +#define WRMSR(ind, m)                   \
    4.35 +        mov     $ind, %ecx;             \
    4.36 +        movq    m(%rip), %rdx;          \
    4.37 +        mov     %edx, %eax;             \
    4.38 +        shrq    $0x20, %rdx;              \
    4.39 +        wrmsr;
    4.40 +
    4.41 +#else /* !defined(__x86_64__) */
    4.42 +
    4.43 +        .code32
    4.44 +
    4.45 +#define GREG(x)         %e##x
    4.46 +#define SAVED_GREG(x)   saved_e##x
    4.47 +#define DECLARE_GREG(x) saved_e##x:     .long   0
    4.48 +#define SAVE_GREG(x)    movl GREG(x), SAVED_GREG(x)
    4.49 +#define LOAD_GREG(x)    movl SAVED_GREG(x), GREG(x)
    4.50 +
    4.51 +#define REF(x)          x
    4.52 +
    4.53 +#endif
    4.54 +
    4.55 +ENTRY(do_suspend_lowlevel)
    4.56 +
    4.57 +        SAVE_GREG(sp)
    4.58 +        SAVE_GREG(ax)
    4.59 +        SAVE_GREG(bx)
    4.60 +        SAVE_GREG(cx)
    4.61 +        SAVE_GREG(dx)
    4.62 +        SAVE_GREG(bp)
    4.63 +        SAVE_GREG(si)
    4.64 +        SAVE_GREG(di)
    4.65 +
    4.66 +#if defined(__x86_64__)
    4.67 +
    4.68 +        SAVE_GREG(8)     # save r8...r15
    4.69 +        SAVE_GREG(9)
    4.70 +        SAVE_GREG(10)
    4.71 +        SAVE_GREG(11)
    4.72 +        SAVE_GREG(12)
    4.73 +        SAVE_GREG(13)
    4.74 +        SAVE_GREG(14)
    4.75 +        SAVE_GREG(15)
    4.76 +        pushfq;
    4.77 +        popq    SAVED_GREG(flags)
    4.78 +
    4.79 +        mov     %cr8, GREG(ax)
    4.80 +        mov     GREG(ax), REF(saved_cr8)
    4.81 +
    4.82 +        RDMSR(MSR_FS_BASE, saved_fs_base)
    4.83 +        RDMSR(MSR_GS_BASE, saved_gs_base)
    4.84 +        RDMSR(MSR_SHADOW_GS_BASE, saved_kernel_gs_base)
    4.85 +
    4.86 +#else /* !defined(__x86_64__) */
    4.87 +
    4.88 +        pushfl;
    4.89 +        popl    SAVED_GREG(flags)
    4.90 +
    4.91 +#endif
    4.92 +
    4.93 +        mov     %ds, REF(saved_ds)
    4.94 +        mov     %es, REF(saved_es)
    4.95 +        mov     %fs, REF(saved_fs)
    4.96 +        mov     %gs, REF(saved_gs)
    4.97 +        mov     %ss, REF(saved_ss)
    4.98 +
    4.99 +        sgdt    REF(saved_gdt)
   4.100 +        sidt    REF(saved_idt)
   4.101 +        sldt    REF(saved_ldt)
   4.102 +
   4.103 +        mov     %cr0, GREG(ax)
   4.104 +        mov     GREG(ax), REF(saved_cr0)
   4.105 +
   4.106 +        mov     %cr3, GREG(ax)
   4.107 +        mov     GREG(ax), REF(saved_cr3)
   4.108 +
   4.109 +        call    save_rest_processor_state
   4.110 +
   4.111 +#if defined(__x86_64__)
   4.112 +
   4.113 +        mov     $3, %rdi
   4.114 +        xor     %eax, %eax
   4.115 +
   4.116 +#else /* !defined(__x86_64__) */
   4.117 +
   4.118 +        push    $3
   4.119 +
   4.120 +#endif
   4.121 +
   4.122 +        /* enter sleep state physically */
   4.123 +        call    acpi_enter_sleep_state
   4.124 +        jmp     __ret_point
   4.125 +
   4.126 +        .align  16
   4.127 +        .globl  __ret_point
   4.128 +__ret_point:
   4.129 +
   4.130 +        /* mmu_cr4_features contains latest cr4 setting */
   4.131 +        mov     REF(mmu_cr4_features), GREG(ax)
   4.132 +        mov     GREG(ax), %cr4
   4.133 +
   4.134 +        mov     REF(saved_cr3), GREG(ax)
   4.135 +        mov     GREG(ax), %cr3
   4.136 +
   4.137 +        mov     REF(saved_cr0), GREG(ax)
   4.138 +        mov     GREG(ax), %cr0
   4.139 +
   4.140 +        lgdt    REF(saved_gdt)
   4.141 +        lidt    REF(saved_idt)
   4.142 +        lldt    REF(saved_ldt)
   4.143 +
   4.144 +        mov     REF(saved_ss), %ss
   4.145 +        LOAD_GREG(sp)
   4.146 +
   4.147 +#if defined(__x86_64__)
   4.148 +
   4.149 +        mov     REF(saved_cr8), %rax
   4.150 +        mov     %rax, %cr8
   4.151 +
   4.152 +        pushq   SAVED_GREG(flags)
   4.153 +        popfq
   4.154 +
   4.155 +        /* Idle vcpu doesn't need segment selectors reload, since
   4.156 +         * those may contain stale value from other domains and 
   4.157 +         * reload may result page fault due to no matched gdt entry
   4.158 +         */
   4.159 +        mov     $(STACK_SIZE - 8), %rax
   4.160 +        or      %rsp, %rax
   4.161 +        and     $~7, %rax
   4.162 +        mov     (%rax), %rax
   4.163 +        mov     0x10(%rax), %rax
   4.164 +        cmpw    $0x7fff, (%rax)
   4.165 +        je      1f
   4.166 +
   4.167 +        /* These selectors are from guest, and thus need reload */
   4.168 +        mov     REF(saved_ds), %ds
   4.169 +        mov     REF(saved_es), %es
   4.170 +        mov     REF(saved_fs), %fs
   4.171 +
   4.172 +        /* gs load is special */
   4.173 +        mov     REF(saved_gs), %rsi
   4.174 +        mov     $3, %rdi        # SEGBASE_GS_USER_SEL
   4.175 +        call    do_set_segment_base
   4.176 +
   4.177 +1:
   4.178 +        # MSR restore
   4.179 +        WRMSR(MSR_FS_BASE, saved_fs_base)
   4.180 +        WRMSR(MSR_GS_BASE, saved_gs_base)
   4.181 +        WRMSR(MSR_SHADOW_GS_BASE, saved_kernel_gs_base)
   4.182 +
   4.183 +#else /* !defined(__x86_64__) */
   4.184 +
   4.185 +        pushl   SAVED_GREG(flags)
   4.186 +        popfl
   4.187 +
   4.188 +        /* No reload to fs/gs, which is saved in bottom stack already */
   4.189 +        mov     REF(saved_ds), %ds
   4.190 +        mov     REF(saved_es), %es
   4.191 +
   4.192 +#endif
   4.193 +
   4.194 +        call restore_rest_processor_state
   4.195 +
   4.196 +        LOAD_GREG(bp)
   4.197 +        LOAD_GREG(ax)
   4.198 +        LOAD_GREG(bx)
   4.199 +        LOAD_GREG(cx)
   4.200 +        LOAD_GREG(dx)
   4.201 +        LOAD_GREG(si)
   4.202 +        LOAD_GREG(di)
   4.203 +#if defined(__x86_64__)
   4.204 +        LOAD_GREG(8)     # save r8...r15
   4.205 +        LOAD_GREG(9)
   4.206 +        LOAD_GREG(10)
   4.207 +        LOAD_GREG(11)
   4.208 +        LOAD_GREG(12)
   4.209 +        LOAD_GREG(13)
   4.210 +        LOAD_GREG(14)
   4.211 +        LOAD_GREG(15)
   4.212 +#endif
   4.213 +        ret 
   4.214 +
   4.215 +.data
   4.216 +        .align 16
   4.217 +saved_ds:        .word   0
   4.218 +saved_es:        .word   0
   4.219 +saved_ss:        .word   0
   4.220 +saved_gs:        .word   0
   4.221 +saved_fs:        .word   0
   4.222 +
   4.223 +        .align 4
   4.224 +        .globl   saved_magic
   4.225 +saved_magic:     .long   0x9abcdef0
   4.226 +
   4.227 +        .align 8
   4.228 +DECLARE_GREG(sp)
   4.229 +DECLARE_GREG(bp)
   4.230 +DECLARE_GREG(ax)
   4.231 +DECLARE_GREG(bx)
   4.232 +DECLARE_GREG(cx)
   4.233 +DECLARE_GREG(dx)
   4.234 +DECLARE_GREG(si)
   4.235 +DECLARE_GREG(di)
   4.236 +DECLARE_GREG(flags)
   4.237 +
   4.238 +#if defined(__x86_64__)
   4.239 +
   4.240 +DECLARE_GREG(8)
   4.241 +DECLARE_GREG(9)
   4.242 +DECLARE_GREG(10)
   4.243 +DECLARE_GREG(11)
   4.244 +DECLARE_GREG(12)
   4.245 +DECLARE_GREG(13)
   4.246 +DECLARE_GREG(14)
   4.247 +DECLARE_GREG(15)
   4.248 +
   4.249 +saved_gdt:      .quad   0,0
   4.250 +saved_idt:      .quad   0,0
   4.251 +saved_ldt:      .quad   0,0
   4.252 +
   4.253 +saved_cr0:      .quad   0
   4.254 +saved_cr3:      .quad   0
   4.255 +saved_cr8:      .quad   0
   4.256 +
   4.257 +saved_gs_base:  .quad   0
   4.258 +saved_fs_base:  .quad   0
   4.259 +saved_kernel_gs_base:   .quad   0
   4.260 +
   4.261 +#else /* !defined(__x86_64__) */
   4.262 +
   4.263 +saved_gdt:      .long   0,0
   4.264 +saved_idt:      .long   0,0
   4.265 +saved_ldt:      .long   0
   4.266 +
   4.267 +saved_cr0:      .long   0
   4.268 +saved_cr3:      .long   0
   4.269 +
   4.270 +#endif 
     5.1 --- a/xen/arch/x86/boot/Makefile	Wed Jul 11 13:49:11 2007 +0100
     5.2 +++ b/xen/arch/x86/boot/Makefile	Wed Jul 11 15:47:14 2007 +0100
     5.3 @@ -1,3 +1,4 @@
     5.4  obj-y += head.o
     5.5  
     5.6 -head.o: head.S $(TARGET_SUBARCH).S trampoline.S mem.S video.S cmdline.S edd.S
     5.7 +head.o: head.S $(TARGET_SUBARCH).S trampoline.S mem.S video.S \
     5.8 +	cmdline.S edd.S wakeup.S
     6.1 --- a/xen/arch/x86/boot/head.S	Wed Jul 11 13:49:11 2007 +0100
     6.2 +++ b/xen/arch/x86/boot/head.S	Wed Jul 11 15:47:14 2007 +0100
     6.3 @@ -175,9 +175,11 @@ 1:      stosl   /* low mappings cover up
     6.4  
     6.5  #include "cmdline.S"
     6.6  
     6.7 +        .align 16
     6.8          .globl trampoline_start, trampoline_end
     6.9  trampoline_start:
    6.10  #include "trampoline.S"
    6.11 +#include "wakeup.S"
    6.12  trampoline_end:
    6.13  
    6.14          .text
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/xen/arch/x86/boot/wakeup.S	Wed Jul 11 15:47:14 2007 +0100
     7.3 @@ -0,0 +1,212 @@
     7.4 +        .code16
     7.5 +
     7.6 +#undef wakesym
     7.7 +/* Used in real mode, to cal offset in current segment */
     7.8 +#define wakesym(sym) (sym - wakeup_start)
     7.9 +
    7.10 +ENTRY(wakeup_start)
    7.11 +        wakeup_code_start = .
    7.12 +
    7.13 +        cli
    7.14 +        cld
    7.15 +
    7.16 +        # setup data segment
    7.17 +        movw    %cs, %ax
    7.18 +        movw    %ax, %ds
    7.19 +        movw    %ax, %ss        # A stack required for BIOS call
    7.20 +        movw    $wakesym(wakeup_stack), %sp
    7.21 +
    7.22 +        pushl   $0              # Kill dangerous flag early
    7.23 +        popfl
    7.24 +
    7.25 +        # check magic number
    7.26 +        movl    wakesym(real_magic), %eax
    7.27 +        cmpl    $0x12345678, %eax
    7.28 +        jne     bogus_real_magic
    7.29 +
    7.30 +        # for acpi_sleep=s3_bios
    7.31 +        testl   $1, wakesym(video_flags)
    7.32 +        jz      1f
    7.33 +        lcall   $0xc000, $3
    7.34 +        movw    %cs, %ax        # In case messed by BIOS
    7.35 +        movw    %ax, %ds
    7.36 +        movw    %ax, %ss        # Need this? How to ret if clobbered?
    7.37 +
    7.38 +1:      # for acpi_sleep=s3_mode
    7.39 +        testl   $2, wakesym(video_flags)
    7.40 +        jz      1f
    7.41 +        movl    wakesym(video_mode), %eax
    7.42 +        call    mode_setw
    7.43 +
    7.44 +1:      # Show some progress if VGA is resumed
    7.45 +        movw    $0xb800, %ax
    7.46 +        movw    %ax, %fs
    7.47 +        movw    $0x0e00 + 'L', %fs:(0x10)
    7.48 +
    7.49 +        # boot trampoline is under 1M, and shift its start into
    7.50 +        # %fs to reference symbols in that area
    7.51 +        movl    $BOOT_TRAMPOLINE, %eax
    7.52 +        shrl    $4, %eax
    7.53 +        movl    %eax, %fs
    7.54 +        lidt    %fs:bootsym(idt_48)
    7.55 +        lgdt    %fs:bootsym(gdt_48)
    7.56 +
    7.57 +        movw    $1, %ax
    7.58 +        lmsw    %ax             # Turn on CR0.PE 
    7.59 +        jmp     1f
    7.60 +1:      ljmpl   $BOOT_CS32, $bootsym_phys(wakeup_32)
    7.61 +
    7.62 +/* This code uses an extended set of video mode numbers. These include:
    7.63 + * Aliases for standard modes
    7.64 + *      NORMAL_VGA (-1)
    7.65 + *      EXTENDED_VGA (-2)
    7.66 + *      ASK_VGA (-3)
    7.67 + * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
    7.68 + * of compatibility when extending the table. These are between 0x00 and 0xff.
    7.69 + */
    7.70 +#define VIDEO_FIRST_MENU 0x0000
    7.71 +
    7.72 +/* Standard BIOS video modes (BIOS number + 0x0100) */
    7.73 +#define VIDEO_FIRST_BIOS 0x0100
    7.74 +
    7.75 +/* VESA BIOS video modes (VESA number + 0x0200) */
    7.76 +#define VIDEO_FIRST_VESA 0x0200
    7.77 +
    7.78 +/* Video7 special modes (BIOS number + 0x0900) */
    7.79 +#define VIDEO_FIRST_V7 0x0900
    7.80 +
    7.81 +# Setting of user mode (AX=mode ID) => CF=success
    7.82 +mode_setw:
    7.83 +        movw    %ax, %bx
    7.84 +        cmpb    $VIDEO_FIRST_VESA>>8, %ah
    7.85 +        jnc     check_vesaw
    7.86 +        decb    %ah
    7.87 +
    7.88 +setbadw: clc
    7.89 +        ret
    7.90 +
    7.91 +check_vesaw:
    7.92 +        subb    $VIDEO_FIRST_VESA>>8, %bh
    7.93 +        orw     $0x4000, %bx                    # Use linear frame buffer
    7.94 +        movw    $0x4f02, %ax                    # VESA BIOS mode set call
    7.95 +        int     $0x10
    7.96 +        cmpw    $0x004f, %ax                    # AL=4f if implemented
    7.97 +        jnz     _setbadw                        # AH=0 if OK
    7.98 +
    7.99 +        stc
   7.100 +        ret
   7.101 +
   7.102 +_setbadw: jmp    setbadw
   7.103 +
   7.104 +bogus_real_magic:
   7.105 +        movw    $0x0e00 + 'B', %fs:(0x12)
   7.106 +        jmp     bogus_real_magic
   7.107 +
   7.108 +        .align 4
   7.109 +real_magic:     .long 0x12345678
   7.110 +         .globl video_mode, video_flags
   7.111 +video_mode:     .long 0
   7.112 +video_flags:    .long 0
   7.113 +
   7.114 +        .code32
   7.115 +
   7.116 +        # Now in protect mode, with paging disabled
   7.117 +        # Add offset for any reference to xen specific symbols
   7.118 +
   7.119 +wakeup_32:
   7.120 +        mov     $BOOT_DS, %eax
   7.121 +        mov     %eax, %ds
   7.122 +        mov     %eax, %ss
   7.123 +        mov     $bootsym_phys(wakeup_stack), %esp
   7.124 +
   7.125 +        # check saved magic again
   7.126 +        mov     $sym_phys(saved_magic), %eax
   7.127 +        add     bootsym_phys(trampoline_xen_phys_start), %eax
   7.128 +        mov     (%eax), %eax
   7.129 +        cmp     $0x9abcdef0, %eax
   7.130 +        jne     bogus_saved_magic
   7.131 +        
   7.132 +        /* fpu init? */
   7.133 +
   7.134 +        /* Initialise CR4. */
   7.135 +#if CONFIG_PAGING_LEVELS == 2
   7.136 +        mov     $X86_CR4_PSE, %ecx
   7.137 +#else
   7.138 +        mov     $X86_CR4_PAE, %ecx
   7.139 +#endif
   7.140 +        mov     %ecx, %cr4
   7.141 +
   7.142 +        /* Load pagetable base register */
   7.143 +        mov     $sym_phys(idle_pg_table),%eax
   7.144 +        add     bootsym_phys(trampoline_xen_phys_start),%eax
   7.145 +        mov     %eax,%cr3
   7.146 +
   7.147 +        /* Will cpuid feature change after resume? */
   7.148 +#if CONFIG_PAGING_LEVELS != 2
   7.149 +        /* Set up EFER (Extended Feature Enable Register). */
   7.150 +        mov     bootsym_phys(cpuid_ext_features),%edi
   7.151 +        test    $0x20100800,%edi /* SYSCALL/SYSRET, No Execute, Long Mode? */
   7.152 +        jz      .Lskip_eferw
   7.153 +        movl    $MSR_EFER,%ecx
   7.154 +        rdmsr
   7.155 +#if CONFIG_PAGING_LEVELS == 4
   7.156 +        btsl    $_EFER_LME,%eax /* Long Mode      */
   7.157 +        btsl    $_EFER_SCE,%eax /* SYSCALL/SYSRET */
   7.158 +#endif
   7.159 +        btl     $20,%edi        /* No Execute?    */
   7.160 +        jnc     1f
   7.161 +        btsl    $_EFER_NX,%eax  /* No Execute     */
   7.162 +1:      wrmsr
   7.163 +.Lskip_eferw:
   7.164 +#endif
   7.165 +
   7.166 +        wbinvd
   7.167 +
   7.168 +        mov     $0x80050033,%eax /* hi-to-lo: PG,AM,WP,NE,ET,MP,PE */
   7.169 +        mov     %eax,%cr0
   7.170 +        jmp     1f
   7.171 +1:
   7.172 +
   7.173 +#if defined(__x86_64__)
   7.174 +
   7.175 +        /* Now in compatibility mode. Long-jump to 64-bit mode */
   7.176 +        ljmp    $BOOT_CS64, $bootsym_phys(wakeup_64)
   7.177 +
   7.178 +        .code64
   7.179 +        .align  8
   7.180 +        .word   0,0,0
   7.181 +lgdt_descr:
   7.182 +        .word   LAST_RESERVED_GDT_BYTE
   7.183 +        .quad   gdt_table - FIRST_RESERVED_GDT_BYTE
   7.184 +        
   7.185 +wakeup_64:
   7.186 +        lgdt    lgdt_descr(%rip)
   7.187 +        mov     $(__HYPERVISOR_DS64), %eax
   7.188 +        mov     %eax, %ds
   7.189 +
   7.190 +        # long jump to return point, with cs reload
   7.191 +        rex64 ljmp    *ret_point(%rip)
   7.192 +
   7.193 +        .align 8
   7.194 +ret_point:
   7.195 +        .quad   __ret_point
   7.196 +        .word   __HYPERVISOR_CS64
   7.197 +
   7.198 +#else /* !defined(__x86_64__) */
   7.199 +        lgdt    gdt_descr
   7.200 +        mov     $(__HYPERVISOR_DS), %eax
   7.201 +        mov     %eax, %ds
   7.202 +
   7.203 +        ljmp    $(__HYPERVISOR_CS), $__ret_point
   7.204 +#endif
   7.205 +
   7.206 +bogus_saved_magic:
   7.207 +        movw    $0x0e00 + 'S', 0xb8014
   7.208 +        jmp     bogus_saved_magic
   7.209 +
   7.210 +        .align  16
   7.211 +wakeup_stack_begin:     # Stack grows down
   7.212 +
   7.213 +        .fill   PAGE_SIZE,1,0
   7.214 +wakeup_stack:           # Just below end of first page in this section
   7.215 +ENTRY(wakeup_end)
     8.1 --- a/xen/arch/x86/dmi_scan.c	Wed Jul 11 13:49:11 2007 +0100
     8.2 +++ b/xen/arch/x86/dmi_scan.c	Wed Jul 11 15:47:14 2007 +0100
     8.3 @@ -184,7 +184,6 @@ static __init int broken_toshiba_keyboar
     8.4  static __init int reset_videomode_after_s3(struct dmi_blacklist *d)
     8.5  {
     8.6  	/* See acpi_wakeup.S */
     8.7 -	extern long acpi_video_flags;
     8.8  	acpi_video_flags |= 2;
     8.9  	return 0;
    8.10  }
     9.1 --- a/xen/arch/x86/platform_hypercall.c	Wed Jul 11 13:49:11 2007 +0100
     9.2 +++ b/xen/arch/x86/platform_hypercall.c	Wed Jul 11 15:47:14 2007 +0100
     9.3 @@ -18,6 +18,7 @@
     9.4  #include <xen/console.h>
     9.5  #include <xen/iocap.h>
     9.6  #include <xen/guest_access.h>
     9.7 +#include <xen/acpi.h>
     9.8  #include <asm/current.h>
     9.9  #include <public/platform.h>
    9.10  #include <asm/edd.h>
    9.11 @@ -247,6 +248,22 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
    9.12          }
    9.13          break;
    9.14  
    9.15 +#if 0
    9.16 +    case XENPF_set_acpi_sleep:
    9.17 +    {
    9.18 +        ret = set_acpi_sleep_info(&op->u.set_acpi_sleep);
    9.19 +        if (!ret && copy_to_guest(u_xenpf_op, op, 1))
    9.20 +            ret = -EFAULT;
    9.21 +    }
    9.22 +    break;
    9.23 +
    9.24 +    case XENPF_enter_acpi_sleep:
    9.25 +    {
    9.26 +        ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);
    9.27 +    }
    9.28 +    break;
    9.29 +#endif
    9.30 +
    9.31      default:
    9.32          ret = -ENOSYS;
    9.33          break;
    10.1 --- a/xen/include/asm-x86/acpi.h	Wed Jul 11 13:49:11 2007 +0100
    10.2 +++ b/xen/include/asm-x86/acpi.h	Wed Jul 11 15:47:14 2007 +0100
    10.3 @@ -173,6 +173,14 @@ extern unsigned long acpi_wakeup_address
    10.4  /* early initialization routine */
    10.5  extern void acpi_reserve_bootmem(void);
    10.6  
    10.7 +extern unsigned long acpi_video_flags;
    10.8 +extern unsigned long saved_videomode;
    10.9 +struct xenpf_set_acpi_sleep;
   10.10 +struct xenpf_enter_acpi_sleep;
   10.11 +extern int set_acpi_sleep_info(struct xenpf_set_acpi_sleep *info);
   10.12 +extern int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep);
   10.13 +extern int acpi_enter_state(u32 state);
   10.14 +
   10.15  #endif /*CONFIG_ACPI_SLEEP*/
   10.16  
   10.17  extern u8 x86_acpiid_to_apicid[];
    11.1 --- a/xen/include/asm-x86/config.h	Wed Jul 11 13:49:11 2007 +0100
    11.2 +++ b/xen/include/asm-x86/config.h	Wed Jul 11 15:47:14 2007 +0100
    11.3 @@ -25,9 +25,7 @@
    11.4  #define CONFIG_X86_PM_TIMER 1
    11.5  #define CONFIG_HPET_TIMER 1
    11.6  #define CONFIG_X86_MCE_P4THERMAL 1
    11.7 -#define CONFIG_ACPI_NUMA 1
    11.8  #define CONFIG_NUMA 1
    11.9 -#define CONFIG_ACPI_SRAT 1
   11.10  #define CONFIG_DISCONTIGMEM 1
   11.11  #define CONFIG_NUMA_EMU 1
   11.12  
   11.13 @@ -36,6 +34,9 @@
   11.14  
   11.15  #define CONFIG_ACPI 1
   11.16  #define CONFIG_ACPI_BOOT 1
   11.17 +#define CONFIG_ACPI_SLEEP 1
   11.18 +#define CONFIG_ACPI_NUMA 1
   11.19 +#define CONFIG_ACPI_SRAT 1
   11.20  
   11.21  #define CONFIG_VGA 1
   11.22  
   11.23 @@ -100,6 +101,8 @@ extern char trampoline_start[], trampoli
   11.24  extern char trampoline_realmode_entry[];
   11.25  extern unsigned int trampoline_xen_phys_start;
   11.26  extern unsigned char trampoline_cpu_started;
   11.27 +extern char wakeup_start[];
   11.28 +extern unsigned int video_mode, video_flags;
   11.29  #endif
   11.30  
   11.31  #if defined(__x86_64__)
    12.1 --- a/xen/include/public/platform.h	Wed Jul 11 13:49:11 2007 +0100
    12.2 +++ b/xen/include/public/platform.h	Wed Jul 11 15:47:14 2007 +0100
    12.3 @@ -153,6 +153,31 @@ struct xenpf_firmware_info {
    12.4  typedef struct xenpf_firmware_info xenpf_firmware_info_t;
    12.5  DEFINE_XEN_GUEST_HANDLE(xenpf_firmware_info_t);
    12.6  
    12.7 +#define XENPF_set_acpi_sleep      51
    12.8 +struct xenpf_set_acpi_sleep {
    12.9 +    /* IN variables. */
   12.10 +    uint16_t pm1a_cnt_port;
   12.11 +    uint16_t pm1b_cnt_port;
   12.12 +    uint16_t pm1a_evt_port;
   12.13 +    uint16_t pm1b_evt_port;
   12.14 +    /* OUT variables */
   12.15 +    uint64_t xen_waking_vec;   /* Tell dom0 to set FACS waking vector */
   12.16 +};
   12.17 +typedef struct xenpf_set_acpi_sleep xenpf_set_acpi_sleep_t;
   12.18 +DEFINE_XEN_GUEST_HANDLE(xenpf_set_acpi_sleep_t);
   12.19 +
   12.20 +#define XENPF_enter_acpi_sleep    52
   12.21 +struct xenpf_enter_acpi_sleep {
   12.22 +    /* IN variables */
   12.23 +    uint16_t pm1a_cnt_val;
   12.24 +    uint16_t pm1b_cnt_val;
   12.25 +    uint32_t sleep_state;       /* Which state to enter */
   12.26 +    uint32_t video_flags;       /* S3_bios or s3_mode */
   12.27 +    uint32_t video_mode;        /* Mode setting for s3_mode */
   12.28 +};
   12.29 +typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t;
   12.30 +DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t);
   12.31 +
   12.32  struct xen_platform_op {
   12.33      uint32_t cmd;
   12.34      uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
   12.35 @@ -164,6 +189,8 @@ struct xen_platform_op {
   12.36          struct xenpf_microcode_update  microcode;
   12.37          struct xenpf_platform_quirk    platform_quirk;
   12.38          struct xenpf_firmware_info     firmware_info;
   12.39 +        struct xenpf_set_acpi_sleep    set_acpi_sleep;
   12.40 +        struct xenpf_enter_acpi_sleep  enter_acpi_sleep;
   12.41          uint8_t                        pad[128];
   12.42      } u;
   12.43  };