Skip to content

Commit 9d02b43

Browse files
olafheringkonradwilk
authored andcommitted
xen PVonHVM: use E820_Reserved area for shared_info
This is a respin of 00e37bd ("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>
1 parent 8f0d816 commit 9d02b43

File tree

3 files changed

+55
-24
lines changed

3 files changed

+55
-24
lines changed

arch/x86/xen/enlighten.c

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,51 +1495,72 @@ asmlinkage void __init xen_start_kernel(void)
14951495
#endif
14961496
}
14971497

1498-
void __ref xen_hvm_init_shared_info(void)
1498+
#ifdef CONFIG_XEN_PVHVM
1499+
#define HVM_SHARED_INFO_ADDR 0xFE700000UL
1500+
static struct shared_info *xen_hvm_shared_info;
1501+
static unsigned long xen_hvm_sip_phys;
1502+
static int xen_major, xen_minor;
1503+
1504+
static void xen_hvm_connect_shared_info(unsigned long pfn)
14991505
{
1500-
int cpu;
15011506
struct xen_add_to_physmap xatp;
1502-
static struct shared_info *shared_info_page = 0;
15031507

1504-
if (!shared_info_page)
1505-
shared_info_page = (struct shared_info *)
1506-
extend_brk(PAGE_SIZE, PAGE_SIZE);
15071508
xatp.domid = DOMID_SELF;
15081509
xatp.idx = 0;
15091510
xatp.space = XENMAPSPACE_shared_info;
1510-
xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
1511+
xatp.gpfn = pfn;
15111512
if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
15121513
BUG();
15131514

1514-
HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
1515+
}
1516+
static void __init xen_hvm_set_shared_info(struct shared_info *sip)
1517+
{
1518+
int cpu;
1519+
1520+
HYPERVISOR_shared_info = sip;
15151521

15161522
/* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
15171523
* page, we use it in the event channel upcall and in some pvclock
15181524
* related functions. We don't need the vcpu_info placement
15191525
* optimizations because we don't use any pv_mmu or pv_irq op on
1520-
* HVM.
1521-
* When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
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) {
1526+
* HVM. */
1527+
for_each_online_cpu(cpu)
15251528
per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
1529+
}
1530+
1531+
/* Reconnect the shared_info pfn to a (new) mfn */
1532+
void 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. */
1543+
static 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);
15261553
}
1554+
xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
1555+
xen_hvm_set_shared_info(xen_hvm_shared_info);
15271556
}
15281557

1529-
#ifdef CONFIG_XEN_PVHVM
15301558
static void __init init_hvm_pv_info(void)
15311559
{
1532-
int major, minor;
15331560
uint32_t eax, ebx, ecx, edx, pages, msr, base;
15341561
u64 pfn;
15351562

15361563
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-
15431564
cpuid(base + 2, &pages, &msr, &ecx, &edx);
15441565

15451566
pfn = __pa(hypercall_page);
@@ -1590,12 +1611,22 @@ static void __init xen_hvm_guest_init(void)
15901611

15911612
static bool __init xen_hvm_platform(void)
15921613
{
1614+
uint32_t eax, ebx, ecx, edx, base;
1615+
15931616
if (xen_pv_domain())
15941617
return false;
15951618

1596-
if (!xen_cpuid_base())
1619+
base = xen_cpuid_base();
1620+
if (!base)
15971621
return false;
15981622

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+
15991630
return true;
16001631
}
16011632

arch/x86/xen/suspend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled)
3030
{
3131
#ifdef CONFIG_XEN_PVHVM
3232
int cpu;
33-
xen_hvm_init_shared_info();
33+
xen_hvm_resume_shared_info();
3434
xen_callback_vector();
3535
xen_unplug_emulated_devices();
3636
if (xen_feature(XENFEAT_hvm_safe_pvclock)) {

arch/x86/xen/xen-ops.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void xen_enable_syscall(void);
4040
void xen_vcpu_restore(void);
4141

4242
void xen_callback_vector(void);
43-
void xen_hvm_init_shared_info(void);
43+
void xen_hvm_resume_shared_info(void);
4444
void xen_unplug_emulated_devices(void);
4545

4646
void __init xen_build_dynamic_phys_to_machine(void);

0 commit comments

Comments
 (0)