aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2012-07-17 11:43:35 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-07-19 15:52:05 -0400
commit00e37bdb0113a98408de42db85be002f21dbffd3 (patch)
tree13207109cddbc8c3550659eb67e3345ed6cca9a7 /drivers/xen
parent4ff2d06255461390ad685843d0d7364aaa6642d2 (diff)
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 MMIO space before the kexec boot. 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. One way to work around this issue is to allocate a page in the xen-platform pci device's BAR memory range. But pci init is done very late and the shared_info page is already in use very early to read the pvclock. So moving the pfn from RAM to MMIO is racy because some code paths on other vcpus could access the pfn during the small window when the old pfn is moved to the new pfn. There is even a small window were the old pfn is not backed by a mfn, and during that time all reads return -1. Because it is not known upfront where the MMIO region is located it can not be used right from the start in xen_hvm_init_shared_info. To minimise trouble the move of the pfn is done shortly before kexec. This does not eliminate the race because all vcpus are still online when the syscore_ops will be called. But hopefully there is no work pending at this point in time. Also the syscore_op is run last which reduces the risk further. Signed-off-by: Olaf Hering <olaf@aepfle.de> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/platform-pci.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c
index 97ca359ae2bd..d4c50d63acbc 100644
--- a/drivers/xen/platform-pci.c
+++ b/drivers/xen/platform-pci.c
@@ -101,6 +101,19 @@ static int platform_pci_resume(struct pci_dev *pdev)
101 return 0; 101 return 0;
102} 102}
103 103
104static void __devinit prepare_shared_info(void)
105{
106#ifdef CONFIG_KEXEC
107 unsigned long addr;
108 struct shared_info *hvm_shared_info;
109
110 addr = alloc_xen_mmio(PAGE_SIZE);
111 hvm_shared_info = ioremap(addr, PAGE_SIZE);
112 memset(hvm_shared_info, 0, PAGE_SIZE);
113 xen_hvm_prepare_kexec(hvm_shared_info, addr >> PAGE_SHIFT);
114#endif
115}
116
104static int __devinit platform_pci_init(struct pci_dev *pdev, 117static int __devinit platform_pci_init(struct pci_dev *pdev,
105 const struct pci_device_id *ent) 118 const struct pci_device_id *ent)
106{ 119{
@@ -138,6 +151,8 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
138 platform_mmio = mmio_addr; 151 platform_mmio = mmio_addr;
139 platform_mmiolen = mmio_len; 152 platform_mmiolen = mmio_len;
140 153
154 prepare_shared_info();
155
141 if (!xen_have_vector_callback) { 156 if (!xen_have_vector_callback) {
142 ret = xen_allocate_irq(pdev); 157 ret = xen_allocate_irq(pdev);
143 if (ret) { 158 if (ret) {