aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoger Pau Monne <roger.pau@citrix.com>2014-01-20 09:20:07 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2014-01-21 13:26:05 -0500
commitc9f6e9977e38de15da96b732a8dec0ef56cbf977 (patch)
treea310a4c47d227d330d8f31749827fd8bc0821c0f
parentea70ba3ab99a10f1eda4ab6473ea11d6acfd57f5 (diff)
xen/pvh: Set X86_CR0_WP and others in CR0 (v2)
otherwise we will get for some user-space applications that use 'clone' with CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID end up hitting an assert in glibc manifested by: general protection ip:7f80720d364c sp:7fff98fd8a80 error:0 in libc-2.13.so[7f807209e000+180000] This is due to the nature of said operations which sets and clears the PID. "In the successful one I can see that the page table of the parent process has been updated successfully to use a different physical page, so the write of the tid on that page only affects the child... On the other hand, in the failed case, the write seems to happen before the copy of the original page is done, so both the parent and the child end up with the same value (because the parent copies the page after the write of the child tid has already happened)." (Roger's analysis). The nature of this is due to the Xen's commit of 51e2cac257ec8b4080d89f0855c498cbbd76a5e5 "x86/pvh: set only minimal cr0 and cr4 flags in order to use paging" the CR0_WP was removed so COW features of the Linux kernel were not operating properly. While doing that also update the rest of the CR0 flags to be inline with what a baremetal Linux kernel would set them to. In 'secondary_startup_64' (baremetal Linux) sets: X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | X86_CR0_PG The hypervisor for HVM type guests (which PVH is a bit) sets: X86_CR0_PE | X86_CR0_ET | X86_CR0_TS For PVH it specifically sets: X86_CR0_PG Which means we need to set the rest: X86_CR0_MP | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM to have full parity. Signed-off-by: Roger Pau Monne <roger.pau@citrix.com> Signed-off-by: Mukesh Rathor <mukesh.rathor@oracle.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> [v1: Took out the cr4 writes to be a seperate patch] [v2: 0-DAY kernel found xen_setup_gdt to be missing a static]
-rw-r--r--arch/x86/xen/enlighten.c33
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--arch/x86/xen/xen-ops.h2
3 files changed, 32 insertions, 5 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index b6d61c353fe5..a4d7b647867f 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1414,7 +1414,7 @@ static void __init xen_boot_params_init_edd(void)
1414 * is PVH which is not going to use xen_load_gdt_boot or other 1414 * is PVH which is not going to use xen_load_gdt_boot or other
1415 * __init functions. 1415 * __init functions.
1416 */ 1416 */
1417void __ref xen_setup_gdt(int cpu) 1417static void __ref xen_setup_gdt(int cpu)
1418{ 1418{
1419 if (xen_feature(XENFEAT_auto_translated_physmap)) { 1419 if (xen_feature(XENFEAT_auto_translated_physmap)) {
1420#ifdef CONFIG_X86_64 1420#ifdef CONFIG_X86_64
@@ -1462,13 +1462,40 @@ void __ref xen_setup_gdt(int cpu)
1462 pv_cpu_ops.load_gdt = xen_load_gdt; 1462 pv_cpu_ops.load_gdt = xen_load_gdt;
1463} 1463}
1464 1464
1465/*
1466 * A PV guest starts with default flags that are not set for PVH, set them
1467 * here asap.
1468 */
1469static void xen_pvh_set_cr_flags(int cpu)
1470{
1471
1472 /* Some of these are setup in 'secondary_startup_64'. The others:
1473 * X86_CR0_TS, X86_CR0_PE, X86_CR0_ET are set by Xen for HVM guests
1474 * (which PVH shared codepaths), while X86_CR0_PG is for PVH. */
1475 write_cr0(read_cr0() | X86_CR0_MP | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM);
1476}
1477
1478/*
1479 * Note, that it is ref - because the only caller of this after init
1480 * is PVH which is not going to use xen_load_gdt_boot or other
1481 * __init functions.
1482 */
1483void __ref xen_pvh_secondary_vcpu_init(int cpu)
1484{
1485 xen_setup_gdt(cpu);
1486 xen_pvh_set_cr_flags(cpu);
1487}
1488
1465static void __init xen_pvh_early_guest_init(void) 1489static void __init xen_pvh_early_guest_init(void)
1466{ 1490{
1467 if (!xen_feature(XENFEAT_auto_translated_physmap)) 1491 if (!xen_feature(XENFEAT_auto_translated_physmap))
1468 return; 1492 return;
1469 1493
1470 if (xen_feature(XENFEAT_hvm_callback_vector)) 1494 if (!xen_feature(XENFEAT_hvm_callback_vector))
1471 xen_have_vector_callback = 1; 1495 return;
1496
1497 xen_have_vector_callback = 1;
1498 xen_pvh_set_cr_flags(0);
1472 1499
1473#ifdef CONFIG_X86_32 1500#ifdef CONFIG_X86_32
1474 BUG(); /* PVH: Implement proper support. */ 1501 BUG(); /* PVH: Implement proper support. */
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 5e46190133b2..a18eadd8bb40 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -105,7 +105,7 @@ static void cpu_bringup_and_idle(int cpu)
105#ifdef CONFIG_X86_64 105#ifdef CONFIG_X86_64
106 if (xen_feature(XENFEAT_auto_translated_physmap) && 106 if (xen_feature(XENFEAT_auto_translated_physmap) &&
107 xen_feature(XENFEAT_supervisor_mode_kernel)) 107 xen_feature(XENFEAT_supervisor_mode_kernel))
108 xen_setup_gdt(cpu); 108 xen_pvh_secondary_vcpu_init(cpu);
109#endif 109#endif
110 cpu_bringup(); 110 cpu_bringup();
111 cpu_startup_entry(CPUHP_ONLINE); 111 cpu_startup_entry(CPUHP_ONLINE);
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 9059c24ed564..1cb6f4c37300 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -123,5 +123,5 @@ __visible void xen_adjust_exception_frame(void);
123 123
124extern int xen_panic_handler_init(void); 124extern int xen_panic_handler_init(void);
125 125
126void xen_setup_gdt(int cpu); 126void xen_pvh_secondary_vcpu_init(int cpu);
127#endif /* XEN_OPS_H */ 127#endif /* XEN_OPS_H */