[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/12] Provide basic Xen PM infrastructure
Add basic infrastructure for xen power management. Now only S3 (suspend to ram) is supported. Signed-off-by Ke Yu <ke.yu@xxxxxxxxx> Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx> diff -r 13e258a58044 xen/arch/x86/acpi/Makefile --- a/xen/arch/x86/acpi/Makefile Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/acpi/Makefile Wed Feb 14 11:13:40 2007 +0800 @@ -1,1 +1,2 @@ obj-y += boot.o obj-y += boot.o +obj-y += power.o diff -r 13e258a58044 xen/arch/x86/boot/x86_32.S --- a/xen/arch/x86/boot/x86_32.S Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/boot/x86_32.S Wed Feb 14 11:13:40 2007 +0800 @@ -146,6 +146,8 @@ start_paging: rdmsr bts $_EFER_NX,%eax wrmsr + mov $1,%eax + mov %eax, nx_enabled-__PAGE_OFFSET no_execute_disable: pop %ebx #endif diff -r 13e258a58044 xen/arch/x86/smp.c --- a/xen/arch/x86/smp.c Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/smp.c Wed Feb 14 14:59:49 2007 +0800 @@ -276,8 +276,9 @@ int on_selected_cpus( { struct call_data_struct data; unsigned int nr_cpus = cpus_weight(selected); - - ASSERT(local_irq_is_enabled()); + unsigned int self = cpu_isset(smp_processor_id(), selected); + + ASSERT(!self || local_irq_is_enabled()); if ( nr_cpus == 0 ) return 0; diff -r 13e258a58044 xen/arch/x86/x86_32/Makefile --- a/xen/arch/x86/x86_32/Makefile Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_32/Makefile Wed Feb 14 11:13:40 2007 +0800 @@ -6,3 +6,5 @@ obj-y += traps.o obj-y += traps.o obj-$(supervisor_mode_kernel) += supervisor_mode_kernel.o +subdir-y += acpi +subdir-y += power diff -r 13e258a58044 xen/arch/x86/x86_32/acpi/sleep.c --- a/xen/arch/x86/x86_32/acpi/sleep.c Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_32/acpi/sleep.c Wed Feb 14 11:13:40 2007 +0800 @@ -5,16 +5,29 @@ * Copyright (C) 2001-2003 Pavel Machek <pavel@xxxxxxx> */ +#ifndef __XEN__ #include <linux/acpi.h> #include <linux/bootmem.h> #include <linux/dmi.h> #include <linux/cpumask.h> #include <asm/smp.h> +#else +#include <asm/config.h> +#include <xen/string.h> +#include <xen/domain_page.h> +#include <asm/init.h> +#include <asm/page.h> +#include <asm/flushtlb.h> +#include <xen/init.h> +#endif /* address in low memory of the wakeup routine. */ unsigned long acpi_wakeup_address = 0; unsigned long acpi_video_flags; +#ifdef __XEN__ +unsigned long saved_videomode = 0; +#endif extern char wakeup_start, wakeup_end; extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); @@ -29,6 +42,9 @@ int acpi_save_state_mem(void) { if (!acpi_wakeup_address) return 1; +#ifdef __XEN__ + init_low_mappings(); +#endif memcpy((void *)acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); acpi_copy_wakeup_routine(acpi_wakeup_address); @@ -59,11 +75,20 @@ void __init acpi_reserve_bootmem(void) return; } +#ifndef __XEN__ acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); +#else + /* 0~640K is not used by anyone, except 0x9000 is used by smp + * trampoline code, so choose 0x7000 for XEN acpi wake up code + */ + + acpi_wakeup_address = (unsigned long)__va(0x7000); +#endif if (!acpi_wakeup_address) printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); } +#ifndef __XEN__ static int __init acpi_sleep_setup(char *str) { while ((str != NULL) && (*str != '\0')) { @@ -104,3 +129,4 @@ static int __init acpisleep_dmi_init(voi } core_initcall(acpisleep_dmi_init); +#endif diff -r 13e258a58044 xen/arch/x86/x86_32/acpi/wakeup.S --- a/xen/arch/x86/x86_32/acpi/wakeup.S Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_32/acpi/wakeup.S Wed Feb 14 11:13:40 2007 +0800 @@ -1,6 +1,11 @@ .text +#ifndef __XEN__ #include <linux/linkage.h> #include <asm/segment.h> +#else +#include <xen/config.h> +#include <asm/asm_defns.h> +#endif #include <asm/page.h> # @@ -56,7 +61,11 @@ 1: 1: # set up page table +#ifndef __XEN__ movl $swsusp_pg_dir-__PAGE_OFFSET, %eax +#else + movl $idle_pg_table-__PAGE_OFFSET, %eax +#endif movl %eax, %cr3 testl $1, real_efer_save_restore - wakeup_code @@ -88,7 +97,11 @@ 1: cmpl $0x12345678, %eax jne bogus_real_magic +#ifndef __XEN__ ljmpl $__KERNEL_CS,$wakeup_pmode_return +#else + ljmpl $(__HYPERVISOR_CS),$wakeup_pmode_return +#endif real_save_gdt: .word 0 .long 0 @@ -184,7 +197,11 @@ ENTRY(wakeup_end) .org 0x1000 wakeup_pmode_return: +#ifndef __XEN__ movw $__KERNEL_DS, %ax +#else + movw $__HYPERVISOR_DS, %ax +#endif movw %ax, %ss movw %ax, %ds movw %ax, %es @@ -196,7 +213,11 @@ wakeup_pmode_return: lgdt saved_gdt lidt saved_idt lldt saved_ldt +#ifndef __XEN__ ljmp $(__KERNEL_CS),$1f +#else + ljmp $(__HYPERVISOR_CS),$1f +#endif 1: movl %cr3, %eax movl %eax, %cr3 diff -r 13e258a58044 xen/arch/x86/x86_32/mm.c --- a/xen/arch/x86/x86_32/mm.c Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_32/mm.c Wed Feb 14 11:13:40 2007 +0800 @@ -34,6 +34,7 @@ unsigned int PAGE_HYPERVISOR_NOCACHE = _ unsigned int PAGE_HYPERVISOR_NOCACHE = __PAGE_HYPERVISOR_NOCACHE; static unsigned long mpt_size; +int nx_enabled = 0; struct page_info *alloc_xen_pagetable(void) { @@ -132,7 +133,7 @@ void __init setup_idle_pagetable(void) __PAGE_HYPERVISOR)); } -void __init zap_low_mappings(l2_pgentry_t *base) +void zap_low_mappings(l2_pgentry_t *base) { int i; u32 addr; @@ -146,6 +147,15 @@ void __init zap_low_mappings(l2_pgentry_ continue; l2e_write(&base[i], l2e_empty()); } + + flush_tlb_all_pge(); +} + +void init_low_mappings(void) +{ + memcpy(idle_pg_table_l2, + idle_pg_table_l2 + (DIRECTMAP_VIRT_START >> L2_PAGETABLE_SHIFT), + (DIRECTMAP_MBYTES << 20) >> L2_PAGETABLE_SHIFT); flush_tlb_all_pge(); } diff -r 13e258a58044 xen/arch/x86/x86_32/power/cpu.c --- a/xen/arch/x86/x86_32/power/cpu.c Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_32/power/cpu.c Wed Feb 14 14:59:56 2007 +0800 @@ -7,10 +7,91 @@ * Copyright (c) 2001 Patrick Mochel <mochel@xxxxxxxx> */ +#ifndef __XEN__ #include <linux/module.h> #include <linux/suspend.h> #include <asm/mtrr.h> #include <asm/mce.h> +#else +#include <xen/config.h> +#include <xen/acpi.h> +#include <xen/smp.h> +#include <asm/processor.h> +#include <asm/msr.h> +#include <asm/flushtlb.h> + +/* image of the saved processor state */ +struct saved_context { + u16 es, fs, gs, ss; + unsigned long cr0, cr2, cr3, cr4; + u16 gdt_pad; + u16 gdt_limit; + unsigned long gdt_base; + u16 idt_pad; + u16 idt_limit; + unsigned long idt_base; + u16 ldt; + u16 tss; + unsigned long tr; + unsigned long safety; + unsigned long return_address; +} __attribute__((packed)); + +#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) +#define load_LDT_desc() __asm__ __volatile__("lldt %w0"::"q" (GDT_ENTRY_LDT*8)) + +#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr)) +#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr)) +#define load_tr(tr) __asm__ __volatile("ltr %0"::"mr" (tr)) +#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"mr" (ldt)) + +#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr)) +#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr)) +#define store_tr(tr) __asm__ ("str %0":"=mr" (tr)) +#define store_ldt(ldt) __asm__ ("sldt %0":"=mr" (ldt)) + +/* + * Load a segment. Fall back on loading the zero + * segment if something goes wrong.. + */ +#define loadsegment(seg,value) \ + asm volatile("\n" \ + "1:\t" \ + "mov %0,%%" #seg "\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\t" \ + "pushl $0\n\t" \ + "popl %%" #seg "\n\t" \ + "jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".align 4\n\t" \ + ".long 1b,3b\n" \ + ".previous" \ + : :"rm" (value)) + +/* + * Save a segment register away + */ +#define savesegment(seg, value) \ + asm volatile("mov %%" #seg ",%0":"=rm" (value)) + +#define set_debugreg(value, register) \ + __asm__("movl %0,%%db" #register \ + : /* no output */ \ + :"r" (value)) + +void kernel_fpu_begin(void) +{ + clts(); +} + +void kernel_fpu_end(void) +{ + stts(); +} +#endif static struct saved_context saved_context; @@ -34,8 +115,10 @@ void __save_processor_state(struct saved * segment registers */ savesegment(es, ctxt->es); +#ifndef __XEN__ savesegment(fs, ctxt->fs); savesegment(gs, ctxt->gs); +#endif savesegment(ss, ctxt->ss); /* @@ -60,6 +143,7 @@ static void do_fpu_end(void) kernel_fpu_end(); } +#ifndef __XEN__ static void fix_processor_context(void) { int cpu = smp_processor_id(); @@ -84,6 +168,32 @@ static void fix_processor_context(void) } } +#else +static void fix_processor_context(void) +{ + int cpu = smp_processor_id(); + struct tss_struct * t = &init_tss[cpu];; + + if ( supervisor_mode_kernel && cpu_has_sep ) + wrmsr(MSR_IA32_SYSENTER_ESP, &t->esp1, 0); + + 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. */ + + load_TR(cpu); /* This does ltr */ + __asm__ __volatile__ ( "lldt %%ax" : : "a" (0) );/* This does lldt */ + + /* + * Now maybe reset the debug registers + */ + set_debugreg(0UL, 0); + set_debugreg(0UL, 1); + set_debugreg(0UL, 2); + set_debugreg(0UL, 3); + /* no 4 and 5 */ + set_debugreg(0UL, 6); + set_debugreg(0UL, 7); +} +#endif void __restore_processor_state(struct saved_context *ctxt) { @@ -106,15 +216,19 @@ void __restore_processor_state(struct sa * segment registers */ loadsegment(es, ctxt->es); +#ifndef __XEN__ loadsegment(fs, ctxt->fs); loadsegment(gs, ctxt->gs); +#endif loadsegment(ss, ctxt->ss); +#ifndef __XEN__ /* * sysenter MSRs */ if (boot_cpu_has(X86_FEATURE_SEP)) enable_sep_cpu(); +#endif fix_processor_context(); do_fpu_end(); @@ -127,6 +241,8 @@ void restore_processor_state(void) __restore_processor_state(&saved_context); } +#ifndef __XEN__ /* Needed by apm.c */ EXPORT_SYMBOL(save_processor_state); EXPORT_SYMBOL(restore_processor_state); +#endif diff -r 13e258a58044 xen/arch/x86/x86_64/mm.c --- a/xen/arch/x86/x86_64/mm.c Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/arch/x86/x86_64/mm.c Wed Feb 14 11:13:40 2007 +0800 @@ -185,9 +185,16 @@ void __init setup_idle_pagetable(void) __PAGE_HYPERVISOR)); } -void __init zap_low_mappings(void) +void zap_low_mappings(void) { l4e_write(&idle_pg_table[0], l4e_empty()); + flush_tlb_all_pge(); +} + +void init_low_mappings(void) +{ + l4e_write(&idle_pg_table[0], + l4e_from_paddr(__pa(idle_pg_table_l3), __PAGE_HYPERVISOR)); flush_tlb_all_pge(); } diff -r 13e258a58044 xen/include/asm-x86/config.h --- a/xen/include/asm-x86/config.h Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/include/asm-x86/config.h Wed Feb 14 14:59:48 2007 +0800 @@ -251,6 +251,7 @@ #define CONFIG_DOMAIN_PAGE 1 #define asmlinkage __attribute__((regparm(0))) +#define FASTCALL(x) fastcall(x) /* * Memory layout (high to low): SIZE PAE-SIZE diff -r 13e258a58044 xen/include/asm-x86/processor.h --- a/xen/include/asm-x86/processor.h Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/include/asm-x86/processor.h Wed Feb 14 11:13:40 2007 +0800 @@ -295,6 +295,11 @@ static inline unsigned long read_cr2(voi unsigned long __cr2; __asm__("mov %%cr2,%0\n\t" :"=r" (__cr2)); return __cr2; +} + +static inline void write_cr2(unsigned long val) +{ + __asm__("mov %0,%%cr2": :"r" ((unsigned long)val)); } static inline unsigned long read_cr4(void) diff -r 13e258a58044 xen/include/asm-x86/smp.h --- a/xen/include/asm-x86/smp.h Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/include/asm-x86/smp.h Wed Feb 14 14:59:48 2007 +0800 @@ -45,6 +45,7 @@ extern void zap_low_mappings(l2_pgentry_ extern void zap_low_mappings(l2_pgentry_t *base); #endif +extern void init_low_mappings(void); #define MAX_APICID 256 extern u8 x86_cpu_to_apicid[]; diff -r 13e258a58044 xen/include/asm-x86/page.h --- a/xen/include/asm-x86/page.h Wed Feb 14 11:13:40 2007 +0800 +++ b/xen/include/asm-x86/page.h Wed Feb 14 15:00:49 2007 +0800 @@ -288,6 +288,9 @@ extern l2_pgentry_t idle_pg_table_l2[R #else extern root_pgentry_t idle_pg_table[ROOT_PAGETABLE_ENTRIES]; extern l2_pgentry_t idle_pg_table_l2[ROOT_PAGETABLE_ENTRIES]; +#if CONFIG_PAGING_LEVELS == 4 +extern l3_pgentry_t idle_pg_table_l3[L3_PAGETABLE_ENTRIES]; +#endif #ifdef CONFIG_COMPAT extern l2_pgentry_t *compat_idle_pg_table_l2; extern unsigned int m2p_compat_vstart; diff -r 13e258a58044 xen/arch/x86/acpi/power.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/acpi/power.c Wed Feb 14 14:59:58 2007 +0800 @@ -0,0 +1,149 @@ +/* drivers/acpi/sleep/power.c - PM core functionality for Xen + * + * Copyrights from Linux side: + * Copyright (c) 2000-2003 Patrick Mochel + * Copyright (c) 2003 Open Source Development Lab + * Copyright (c) 2004 David Shaohua Li <shaohua.li@xxxxxxxxx> + * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@xxxxxxxxx> + * + * Slimmed with Xen specific support. + */ + +#include <asm/io.h> +#define CONFIG_ACPI_SLEEP +#include <asm/acpi.h> +#include <xen/acpi.h> +#include <xen/errno.h> +#include <xen/iocap.h> +#include <xen/sched.h> +#include <asm/acpi.h> +#include <asm/irq.h> +#include <asm/init.h> +#include <xen/spinlock.h> +#include <xen/sched.h> +#include <xen/domain.h> +#include <xen/console.h> + +u8 sleep_states[ACPI_S_STATE_COUNT]; +DEFINE_SPINLOCK(pm_lock); + +extern void do_suspend_lowlevel(void); + +static char *acpi_states[ACPI_S_STATE_COUNT] = +{ + [ACPI_STATE_S1] = "standby", + [ACPI_STATE_S3] = "mem", + [ACPI_STATE_S4] = "disk", +}; + +/* Add suspend failure recover later */ +static int device_power_down(void) +{ + console_suspend(); + + time_suspend(); + + i8259A_suspend(); + + ioapic_suspend(); + + lapic_suspend(); + + return 0; +} + +static void device_power_up(void) +{ + lapic_resume(); + + ioapic_resume(); + + i8259A_resume(); + + time_resume(); + + console_resume(); +} + +int enter_state(u32 state) +{ + struct domain *d; + unsigned long flags; + int error; + + if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX) + return -EINVAL; + + if (!spin_trylock(&pm_lock)) + return -EBUSY; + + for_each_domain(d) + if (d->domain_id != 0) + domain_pause(d); + + printk("PM: Preparing system for %s sleep\n", acpi_states[state]); + + local_irq_save(flags); + + if ((error = device_power_down())) { + printk(KERN_ERR "Some devices failed to power down\n"); + goto Done; + } + + ACPI_FLUSH_CPU_CACHE(); + + /* Do arch specific saving of state. */ + if (state > ACPI_STATE_S1) { + error = acpi_save_state_mem(); + if (error) + goto Powerup; + } + + switch (state) { + case ACPI_STATE_S3: + do_suspend_lowlevel(); + break; + default: + error = -EINVAL; + goto Powerup; + } + + printk("Back to C!\n"); + if (state > ACPI_STATE_S1) + acpi_restore_state_mem(); + + Powerup: + device_power_up(); + + printk("PM: Finishing wakeup.\n"); + for_each_domain(d) + if (d->domain_id!=0) + domain_unpause(d); + + Done: + local_irq_restore(flags); + spin_unlock(&pm_lock); + return error; + +} + +static int __init acpi_sleep_init(void) +{ + int i = 0; + + printk("ACPI (supports"); + for (i = 0; i < ACPI_S_STATE_COUNT; i++) { + if (i == ACPI_STATE_S3){ + sleep_states[i] = 1; + printk(" S%d", i); + } + else{ + sleep_states[i] = 0; + } + } + printk(")\n"); + + acpi_reserve_bootmem(); + return 0; +} +__initcall(acpi_sleep_init); diff -r 13e258a58044 xen/arch/x86/x86_32/acpi/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/x86_32/acpi/Makefile Wed Feb 14 11:13:40 2007 +0800 @@ -0,0 +1,2 @@ +obj-y += wakeup.o +obj-y += sleep.o diff -r 13e258a58044 xen/arch/x86/x86_32/power/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/x86_32/power/Makefile Wed Feb 14 11:13:40 2007 +0800 @@ -0,0 +1,1 @@ +obj-y += cpu.o Attachment:
xen_pm_arch.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |