aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2012-11-01 17:02:30 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-11-02 11:04:01 -0400
commit9d02b43dee0d7fb18dfb13a00915550b1a3daa9f (patch)
tree5e8ea29e63c463496c1bd0d514539bec6e09d319 /arch/x86/xen
parent8f0d8163b50e01f398b14bcd4dc039ac5ab18d64 (diff)
xen PVonHVM: use E820_Reserved area for shared_info
This is a respin of 00e37bdb0113a98408de42db85be002f21dbffd3 ("xen PVonHVM: move shared_info to MMIO before kexec"). Currently kexec in a PVonHVM guest fails with a triple fault because the new kernel overwrites the shared info page. The exact failure depends on the size of the kernel image. This patch moves the pfn from RAM into an E820 reserved memory area. The pfn containing the shared_info is located somewhere in RAM. This will cause trouble if the current kernel is doing a kexec boot into a new kernel. The new kernel (and its startup code) can not know where the pfn is, so it can not reserve the page. The hypervisor will continue to update the pfn, and as a result memory corruption occours in the new kernel. The toolstack marks the memory area FC000000-FFFFFFFF as reserved in the E820 map. Within that range newer toolstacks (4.3+) will keep 1MB starting from FE700000 as reserved for guest use. Older Xen4 toolstacks will usually not allocate areas up to FE700000, so FE700000 is expected to work also with older toolstacks. In Xen3 there is no reserved area at a fixed location. If the guest is started on such old hosts the shared_info page will be placed in RAM. As a result kexec can not be used. Signed-off-by: Olaf Hering <olaf@aepfle.de> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/enlighten.c75
-rw-r--r--arch/x86/xen/suspend.c2
-rw-r--r--arch/x86/xen/xen-ops.h2
3 files changed, 55 insertions, 24 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 586d83812b67..a90c3bb58bed 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1495,51 +1495,72 @@ asmlinkage void __init xen_start_kernel(void)
1495#endif 1495#endif
1496} 1496}
1497 1497
1498void __ref xen_hvm_init_shared_info(void) 1498#ifdef CONFIG_XEN_PVHVM
1499#define HVM_SHARED_INFO_ADDR 0xFE700000UL
1500static struct shared_info *xen_hvm_shared_info;
1501static unsigned long xen_hvm_sip_phys;
1502static int xen_major, xen_minor;
1503
1504static void xen_hvm_connect_shared_info(unsigned long pfn)
1499{ 1505{
1500 int cpu;
1501 struct xen_add_to_physmap xatp; 1506 struct xen_add_to_physmap xatp;
1502 static struct shared_info *shared_info_page = 0;
1503 1507
1504 if (!shared_info_page)
1505 shared_info_page = (struct shared_info *)
1506 extend_brk(PAGE_SIZE, PAGE_SIZE);
1507 xatp.domid = DOMID_SELF; 1508 xatp.domid = DOMID_SELF;
1508 xatp.idx = 0; 1509 xatp.idx = 0;
1509 xatp.space = XENMAPSPACE_shared_info; 1510 xatp.space = XENMAPSPACE_shared_info;
1510 xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; 1511 xatp.gpfn = pfn;
1511 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 1512 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
1512 BUG(); 1513 BUG();
1513 1514
1514 HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; 1515}
1516static void __init xen_hvm_set_shared_info(struct shared_info *sip)
1517{
1518 int cpu;
1519
1520 HYPERVISOR_shared_info = sip;
1515 1521
1516 /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info 1522 /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
1517 * page, we use it in the event channel upcall and in some pvclock 1523 * page, we use it in the event channel upcall and in some pvclock
1518 * related functions. We don't need the vcpu_info placement 1524 * related functions. We don't need the vcpu_info placement
1519 * optimizations because we don't use any pv_mmu or pv_irq op on 1525 * optimizations because we don't use any pv_mmu or pv_irq op on
1520 * HVM. 1526 * HVM. */
1521 * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is 1527 for_each_online_cpu(cpu)
1522 * online but xen_hvm_init_shared_info is run at resume time too and
1523 * in that case multiple vcpus might be online. */
1524 for_each_online_cpu(cpu) {
1525 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; 1528 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
1529}
1530
1531/* Reconnect the shared_info pfn to a (new) mfn */
1532void xen_hvm_resume_shared_info(void)
1533{
1534 xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
1535}
1536
1537/* Xen tools prior to Xen 4 do not provide a E820_Reserved area for guest usage.
1538 * On these old tools the shared info page will be placed in E820_Ram.
1539 * Xen 4 provides a E820_Reserved area at 0xFC000000, and this code expects
1540 * that nothing is mapped up to HVM_SHARED_INFO_ADDR.
1541 * Xen 4.3+ provides an explicit 1MB area at HVM_SHARED_INFO_ADDR which is used
1542 * here for the shared info page. */
1543static void __init xen_hvm_init_shared_info(void)
1544{
1545 if (xen_major < 4) {
1546 xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE);
1547 xen_hvm_sip_phys = __pa(xen_hvm_shared_info);
1548 } else {
1549 xen_hvm_sip_phys = HVM_SHARED_INFO_ADDR;
1550 set_fixmap(FIX_PARAVIRT_BOOTMAP, xen_hvm_sip_phys);
1551 xen_hvm_shared_info =
1552 (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
1526 } 1553 }
1554 xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
1555 xen_hvm_set_shared_info(xen_hvm_shared_info);
1527} 1556}
1528 1557
1529#ifdef CONFIG_XEN_PVHVM
1530static void __init init_hvm_pv_info(void) 1558static void __init init_hvm_pv_info(void)
1531{ 1559{
1532 int major, minor;
1533 uint32_t eax, ebx, ecx, edx, pages, msr, base; 1560 uint32_t eax, ebx, ecx, edx, pages, msr, base;
1534 u64 pfn; 1561 u64 pfn;
1535 1562
1536 base = xen_cpuid_base(); 1563 base = xen_cpuid_base();
1537 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
1538
1539 major = eax >> 16;
1540 minor = eax & 0xffff;
1541 printk(KERN_INFO "Xen version %d.%d.\n", major, minor);
1542
1543 cpuid(base + 2, &pages, &msr, &ecx, &edx); 1564 cpuid(base + 2, &pages, &msr, &ecx, &edx);
1544 1565
1545 pfn = __pa(hypercall_page); 1566 pfn = __pa(hypercall_page);
@@ -1590,12 +1611,22 @@ static void __init xen_hvm_guest_init(void)
1590 1611
1591static bool __init xen_hvm_platform(void) 1612static bool __init xen_hvm_platform(void)
1592{ 1613{
1614 uint32_t eax, ebx, ecx, edx, base;
1615
1593 if (xen_pv_domain()) 1616 if (xen_pv_domain())
1594 return false; 1617 return false;
1595 1618
1596 if (!xen_cpuid_base()) 1619 base = xen_cpuid_base();
1620 if (!base)
1597 return false; 1621 return false;
1598 1622
1623 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
1624
1625 xen_major = eax >> 16;
1626 xen_minor = eax & 0xffff;
1627
1628 printk(KERN_INFO "Xen version %d.%d.\n", xen_major, xen_minor);
1629
1599 return true; 1630 return true;
1600} 1631}
1601 1632
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index 45329c8c226e..ae8a00c39de4 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled)
30{ 30{
31#ifdef CONFIG_XEN_PVHVM 31#ifdef CONFIG_XEN_PVHVM
32 int cpu; 32 int cpu;
33 xen_hvm_init_shared_info(); 33 xen_hvm_resume_shared_info();
34 xen_callback_vector(); 34 xen_callback_vector();
35 xen_unplug_emulated_devices(); 35 xen_unplug_emulated_devices();
36 if (xen_feature(XENFEAT_hvm_safe_pvclock)) { 36 if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index a95b41744ad0..d2e73d19d366 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -40,7 +40,7 @@ void xen_enable_syscall(void);
40void xen_vcpu_restore(void); 40void xen_vcpu_restore(void);
41 41
42void xen_callback_vector(void); 42void xen_callback_vector(void);
43void xen_hvm_init_shared_info(void); 43void xen_hvm_resume_shared_info(void);
44void xen_unplug_emulated_devices(void); 44void xen_unplug_emulated_devices(void);
45 45
46void __init xen_build_dynamic_phys_to_machine(void); 46void __init xen_build_dynamic_phys_to_machine(void);