All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/12] Provide basic Xen PM infrastructure
@ 2007-02-14  9:13 Tian, Kevin
  2007-06-05  9:48 ` Keir Fraser
  0 siblings, 1 reply; 5+ messages in thread
From: Tian, Kevin @ 2007-02-14  9:13 UTC (permalink / raw)
  To: Keir Fraser, Ian Pratt, xen-devel; +Cc: Yu, Ke

[-- Attachment #1: Type: text/plain, Size: 17283 bytes --]

Add basic infrastructure for xen power management. Now
only S3 (suspend to ram) is supported.

Signed-off-by Ke Yu <ke.yu@intel.com>
Signed-off-by Kevin Tian <kevin.tian@intel.com>

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@suse.cz>
  */
 
+#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@osdl.org>
  */
 
+#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@intel.com>
+ * Copyright (c) 2005 Alexey Starikovskiy
<alexey.y.starikovskiy@intel.com>
+ *
+ * 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 #2: xen_pm_arch.patch --]
[-- Type: application/octet-stream, Size: 16646 bytes --]

Add basic infrastructure for xen power management. Now
only S3 (suspend to ram) is supported.

Signed-off-by Ke Yu <ke.yu@intel.com>
Signed-off-by Kevin Tian <kevin.tian@intel.com>

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@suse.cz>
  */
 
+#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@osdl.org>
  */
 
+#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@intel.com>
+ * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ *
+ * 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 #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-06-05 10:29 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-14  9:13 [PATCH 3/12] Provide basic Xen PM infrastructure Tian, Kevin
2007-06-05  9:48 ` Keir Fraser
2007-06-05 10:02   ` Tian, Kevin
2007-06-05 10:22   ` Tian, Kevin
2007-06-05 10:29     ` Keir Fraser

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.