xen/pvh: Set X86_CR0_WP and others in CR0 (v2)
authorRoger Pau Monne <roger.pau@citrix.com>
Mon, 20 Jan 2014 14:20:07 +0000 (09:20 -0500)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Tue, 21 Jan 2014 18:26:05 +0000 (13:26 -0500)
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]

arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/x86/xen/xen-ops.h

index b6d61c353fe5206a75859aec2c8ca16076511187..a4d7b647867f30783d9eab4f2091b3d991a314e1 100644 (file)
@@ -1414,7 +1414,7 @@ static void __init xen_boot_params_init_edd(void)
  * is PVH which is not going to use xen_load_gdt_boot or other
  * __init functions.
  */
-void __ref xen_setup_gdt(int cpu)
+static void __ref xen_setup_gdt(int cpu)
 {
        if (xen_feature(XENFEAT_auto_translated_physmap)) {
 #ifdef CONFIG_X86_64
@@ -1462,13 +1462,40 @@ void __ref xen_setup_gdt(int cpu)
        pv_cpu_ops.load_gdt = xen_load_gdt;
 }
 
+/*
+ * A PV guest starts with default flags that are not set for PVH, set them
+ * here asap.
+ */
+static void xen_pvh_set_cr_flags(int cpu)
+{
+
+       /* Some of these are setup in 'secondary_startup_64'. The others:
+        * X86_CR0_TS, X86_CR0_PE, X86_CR0_ET are set by Xen for HVM guests
+        * (which PVH shared codepaths), while X86_CR0_PG is for PVH. */
+       write_cr0(read_cr0() | X86_CR0_MP | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM);
+}
+
+/*
+ * Note, that it is ref - because the only caller of this after init
+ * is PVH which is not going to use xen_load_gdt_boot or other
+ * __init functions.
+ */
+void __ref xen_pvh_secondary_vcpu_init(int cpu)
+{
+       xen_setup_gdt(cpu);
+       xen_pvh_set_cr_flags(cpu);
+}
+
 static void __init xen_pvh_early_guest_init(void)
 {
        if (!xen_feature(XENFEAT_auto_translated_physmap))
                return;
 
-       if (xen_feature(XENFEAT_hvm_callback_vector))
-               xen_have_vector_callback = 1;
+       if (!xen_feature(XENFEAT_hvm_callback_vector))
+               return;
+
+       xen_have_vector_callback = 1;
+       xen_pvh_set_cr_flags(0);
 
 #ifdef CONFIG_X86_32
        BUG(); /* PVH: Implement proper support. */
index 5e46190133b248049188b6315a6841b902e58d45..a18eadd8bb4039a6616b2f5b31afd1c72dd68c88 100644 (file)
@@ -105,7 +105,7 @@ static void cpu_bringup_and_idle(int cpu)
 #ifdef CONFIG_X86_64
        if (xen_feature(XENFEAT_auto_translated_physmap) &&
            xen_feature(XENFEAT_supervisor_mode_kernel))
-               xen_setup_gdt(cpu);
+               xen_pvh_secondary_vcpu_init(cpu);
 #endif
        cpu_bringup();
        cpu_startup_entry(CPUHP_ONLINE);
index 9059c24ed5641442e6cf7d8d44dbdfa9de63676c..1cb6f4c373002b39971d08cdfc71f3add935daf3 100644 (file)
@@ -123,5 +123,5 @@ __visible void xen_adjust_exception_frame(void);
 
 extern int xen_panic_handler_init(void);
 
-void xen_setup_gdt(int cpu);
+void xen_pvh_secondary_vcpu_init(int cpu);
 #endif /* XEN_OPS_H */