aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-05-26 18:31:27 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-27 04:11:38 -0400
commit0e91398f2a5d4eb6b07df8115917d0d1cf3e9b58 (patch)
treec6a3b31b7bcbbfb55bb2304d8651abdd28cdad54 /arch/x86/xen
parent7d88d32a4670af583c896e5ecd3929b78538ca62 (diff)
xen: implement save/restore
This patch implements Xen save/restore and migration. Saving is triggered via xenbus, which is polled in drivers/xen/manage.c. When a suspend request comes in, the kernel prepares itself for saving by: 1 - Freeze all processes. This is primarily to prevent any partially-completed pagetable updates from confusing the suspend process. If CONFIG_PREEMPT isn't defined, then this isn't necessary. 2 - Suspend xenbus and other devices 3 - Stop_machine, to make sure all the other vcpus are quiescent. The Xen tools require the domain to run its save off vcpu0. 4 - Within the stop_machine state, it pins any unpinned pgds (under construction or destruction), performs canonicalizes various other pieces of state (mostly converting mfns to pfns), and finally 5 - Suspend the domain Restore reverses the steps used to save the domain, ending when all the frozen processes are thawed. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/Makefile2
-rw-r--r--arch/x86/xen/enlighten.c6
-rw-r--r--arch/x86/xen/mmu.c46
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--arch/x86/xen/suspend.c42
-rw-r--r--arch/x86/xen/time.c8
-rw-r--r--arch/x86/xen/xen-ops.h4
7 files changed, 105 insertions, 5 deletions
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 40b119b6b103..2ba2d1649131 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -1,4 +1,4 @@
1obj-y := enlighten.o setup.o multicalls.o mmu.o \ 1obj-y := enlighten.o setup.o multicalls.o mmu.o \
2 time.o xen-asm.o grant-table.o 2 time.o xen-asm.o grant-table.o suspend.o
3 3
4obj-$(CONFIG_SMP) += smp.o 4obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ce67dc8f36af..b94f63ac228b 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -857,7 +857,7 @@ static __init void xen_pagetable_setup_start(pgd_t *base)
857 PFN_DOWN(__pa(xen_start_info->pt_base))); 857 PFN_DOWN(__pa(xen_start_info->pt_base)));
858} 858}
859 859
860static __init void setup_shared_info(void) 860void xen_setup_shared_info(void)
861{ 861{
862 if (!xen_feature(XENFEAT_auto_translated_physmap)) { 862 if (!xen_feature(XENFEAT_auto_translated_physmap)) {
863 unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP); 863 unsigned long addr = fix_to_virt(FIX_PARAVIRT_BOOTMAP);
@@ -894,7 +894,7 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
894 pv_mmu_ops.release_pmd = xen_release_pmd; 894 pv_mmu_ops.release_pmd = xen_release_pmd;
895 pv_mmu_ops.set_pte = xen_set_pte; 895 pv_mmu_ops.set_pte = xen_set_pte;
896 896
897 setup_shared_info(); 897 xen_setup_shared_info();
898 898
899 /* Actually pin the pagetable down, but we can't set PG_pinned 899 /* Actually pin the pagetable down, but we can't set PG_pinned
900 yet because the page structures don't exist yet. */ 900 yet because the page structures don't exist yet. */
@@ -902,7 +902,7 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
902} 902}
903 903
904/* This is called once we have the cpu_possible_map */ 904/* This is called once we have the cpu_possible_map */
905void __init xen_setup_vcpu_info_placement(void) 905void xen_setup_vcpu_info_placement(void)
906{ 906{
907 int cpu; 907 int cpu;
908 908
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 4740cda36563..e95955968ba3 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -560,6 +560,29 @@ void xen_pgd_pin(pgd_t *pgd)
560 xen_mc_issue(0); 560 xen_mc_issue(0);
561} 561}
562 562
563/*
564 * On save, we need to pin all pagetables to make sure they get their
565 * mfns turned into pfns. Search the list for any unpinned pgds and pin
566 * them (unpinned pgds are not currently in use, probably because the
567 * process is under construction or destruction).
568 */
569void xen_mm_pin_all(void)
570{
571 unsigned long flags;
572 struct page *page;
573
574 spin_lock_irqsave(&pgd_lock, flags);
575
576 list_for_each_entry(page, &pgd_list, lru) {
577 if (!PagePinned(page)) {
578 xen_pgd_pin((pgd_t *)page_address(page));
579 SetPageSavePinned(page);
580 }
581 }
582
583 spin_unlock_irqrestore(&pgd_lock, flags);
584}
585
563/* The init_mm pagetable is really pinned as soon as its created, but 586/* The init_mm pagetable is really pinned as soon as its created, but
564 that's before we have page structures to store the bits. So do all 587 that's before we have page structures to store the bits. So do all
565 the book-keeping now. */ 588 the book-keeping now. */
@@ -617,6 +640,29 @@ static void xen_pgd_unpin(pgd_t *pgd)
617 xen_mc_issue(0); 640 xen_mc_issue(0);
618} 641}
619 642
643/*
644 * On resume, undo any pinning done at save, so that the rest of the
645 * kernel doesn't see any unexpected pinned pagetables.
646 */
647void xen_mm_unpin_all(void)
648{
649 unsigned long flags;
650 struct page *page;
651
652 spin_lock_irqsave(&pgd_lock, flags);
653
654 list_for_each_entry(page, &pgd_list, lru) {
655 if (PageSavePinned(page)) {
656 BUG_ON(!PagePinned(page));
657 printk("unpinning pinned %p\n", page_address(page));
658 xen_pgd_unpin((pgd_t *)page_address(page));
659 ClearPageSavePinned(page);
660 }
661 }
662
663 spin_unlock_irqrestore(&pgd_lock, flags);
664}
665
620void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next) 666void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
621{ 667{
622 spin_lock(&next->page_table_lock); 668 spin_lock(&next->page_table_lock);
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 74ab8968c525..d2e3c20127d7 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -35,7 +35,7 @@
35#include "xen-ops.h" 35#include "xen-ops.h"
36#include "mmu.h" 36#include "mmu.h"
37 37
38static cpumask_t xen_cpu_initialized_map; 38cpumask_t xen_cpu_initialized_map;
39static DEFINE_PER_CPU(int, resched_irq) = -1; 39static DEFINE_PER_CPU(int, resched_irq) = -1;
40static DEFINE_PER_CPU(int, callfunc_irq) = -1; 40static DEFINE_PER_CPU(int, callfunc_irq) = -1;
41static DEFINE_PER_CPU(int, debug_irq) = -1; 41static DEFINE_PER_CPU(int, debug_irq) = -1;
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
new file mode 100644
index 000000000000..7620a16fe535
--- /dev/null
+++ b/arch/x86/xen/suspend.c
@@ -0,0 +1,42 @@
1#include <linux/types.h>
2
3#include <xen/interface/xen.h>
4#include <xen/grant_table.h>
5#include <xen/events.h>
6
7#include <asm/xen/hypercall.h>
8#include <asm/xen/page.h>
9
10#include "xen-ops.h"
11#include "mmu.h"
12
13void xen_pre_suspend(void)
14{
15 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
16 xen_start_info->console.domU.mfn =
17 mfn_to_pfn(xen_start_info->console.domU.mfn);
18
19 BUG_ON(!irqs_disabled());
20
21 HYPERVISOR_shared_info = &xen_dummy_shared_info;
22 if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
23 __pte_ma(0), 0))
24 BUG();
25}
26
27void xen_post_suspend(int suspend_cancelled)
28{
29 if (suspend_cancelled) {
30 xen_start_info->store_mfn =
31 pfn_to_mfn(xen_start_info->store_mfn);
32 xen_start_info->console.domU.mfn =
33 pfn_to_mfn(xen_start_info->console.domU.mfn);
34 } else {
35#ifdef CONFIG_SMP
36 xen_cpu_initialized_map = cpu_online_map;
37#endif
38 }
39
40 xen_setup_shared_info();
41}
42
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index c39e1a5aa241..0bef256e5f2d 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -572,6 +572,14 @@ void xen_setup_cpu_clockevents(void)
572 clockevents_register_device(&__get_cpu_var(xen_clock_events)); 572 clockevents_register_device(&__get_cpu_var(xen_clock_events));
573} 573}
574 574
575void xen_time_suspend(void)
576{
577}
578
579void xen_time_resume(void)
580{
581}
582
575__init void xen_time_init(void) 583__init void xen_time_init(void)
576{ 584{
577 int cpu = smp_processor_id(); 585 int cpu = smp_processor_id();
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index a1bc89a8f169..a0503acad664 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -9,6 +9,7 @@
9extern const char xen_hypervisor_callback[]; 9extern const char xen_hypervisor_callback[];
10extern const char xen_failsafe_callback[]; 10extern const char xen_failsafe_callback[];
11 11
12struct trap_info;
12void xen_copy_trap_info(struct trap_info *traps); 13void xen_copy_trap_info(struct trap_info *traps);
13 14
14DECLARE_PER_CPU(unsigned long, xen_cr3); 15DECLARE_PER_CPU(unsigned long, xen_cr3);
@@ -19,6 +20,7 @@ extern struct shared_info xen_dummy_shared_info;
19extern struct shared_info *HYPERVISOR_shared_info; 20extern struct shared_info *HYPERVISOR_shared_info;
20 21
21void xen_setup_mfn_list_list(void); 22void xen_setup_mfn_list_list(void);
23void xen_setup_shared_info(void);
22 24
23char * __init xen_memory_setup(void); 25char * __init xen_memory_setup(void);
24void __init xen_arch_setup(void); 26void __init xen_arch_setup(void);
@@ -59,6 +61,8 @@ int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
59int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *), 61int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
60 void *info, int wait); 62 void *info, int wait);
61 63
64extern cpumask_t xen_cpu_initialized_map;
65
62 66
63/* Declare an asm function, along with symbols needed to make it 67/* Declare an asm function, along with symbols needed to make it
64 inlineable */ 68 inlineable */