]> xenbits.xensource.com Git - xen.git/commitdiff
x86: allow pv guests to disable TSC for applications
authorKeir Fraser <keir@xensource.com>
Mon, 29 Oct 2007 16:49:02 +0000 (16:49 +0000)
committerKeir Fraser <keir@xensource.com>
Mon, 29 Oct 2007 16:49:02 +0000 (16:49 +0000)
Linux, under CONFIG_SECCOMP, has been capable of hiding the TSC from
processes for quite a while. This patch enables this to actually work
for pv kernels, by allowing them to control CR4.TSD (and, as a simple
thing to do at the same time, CR4.DE).

Applies cleanly only on top of the previously submitted debug register
handling patch.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Also clean up CR4 and EFER handling, and hack-n-slash header file
inclusion madness to get the tree building again.

Signed-off-by: Keir Fraser <keir@xensource.com>
26 files changed:
xen/arch/x86/acpi/boot.c
xen/arch/x86/acpi/power.c
xen/arch/x86/domain.c
xen/arch/x86/flushtlb.c
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-detect.c
xen/arch/x86/hvm/svm/amd_iommu/amd-iommu-init.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/setup.c
xen/arch/x86/smp.c
xen/arch/x86/smpboot.c
xen/arch/x86/traps.c
xen/include/asm-x86/amd-iommu.h
xen/include/asm-x86/apic.h
xen/include/asm-x86/domain.h
xen/include/asm-x86/hvm/io.h
xen/include/asm-x86/hvm/irq.h
xen/include/asm-x86/io_apic.h
xen/include/asm-x86/iommu.h
xen/include/asm-x86/msr.h
xen/include/asm-x86/page.h
xen/include/asm-x86/processor.h
xen/include/asm-x86/smp.h
xen/include/asm-x86/x86_32/elf.h
xen/include/asm-x86/x86_64/elf.h

index cbaa5ecbe704e3ff08ea2ad9ad2a8acdb92e4846..7db32263c115fc39c0b39ba8a04643dc6844d996 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/apic.h>
 #include <asm/io.h>
 #include <asm/mpspec.h>
+#include <asm/processor.h>
 #include <mach_apic.h>
 #include <mach_mpparse.h>
 
index ae4d2149cf0563256e3473e2a14582c08a0ffd98..f14fda92fb8383b9843475d06bc0b54bce9426dc 100644 (file)
@@ -155,6 +155,10 @@ static int enter_state(u32 state)
 
     pmprintk(XENLOG_DEBUG, "Back to C.");
 
+    /* Restore CR4 and EFER from cached values. */
+    write_cr4(read_cr4());
+    write_efer(read_efer());
+
     device_power_up();
 
     pmprintk(XENLOG_INFO, "Finishing wakeup from ACPI S%d state.", state);
index e874ad7eb25c2b8cd7101bc6cd1fa59430574492..6ca6f0cd9e38a4e6eb5e6240b990580571c331d4 100644 (file)
@@ -50,7 +50,8 @@
 #endif
 
 DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
-DEFINE_PER_CPU(__u64, efer);
+DEFINE_PER_CPU(u64, efer);
+DEFINE_PER_CPU(unsigned long, cr4);
 
 static void unmap_vcpu_info(struct vcpu *v);
 
@@ -413,6 +414,8 @@ int vcpu_initialise(struct vcpu *v)
             v->arch.schedule_tail = continue_idle_domain;
             v->arch.cr3           = __pa(idle_pg_table);
         }
+
+        v->arch.guest_context.ctrlreg[4] = mmu_cr4_features;
     }
 
     v->arch.perdomain_ptes =
@@ -568,13 +571,28 @@ void arch_domain_destroy(struct domain *d)
     free_xenheap_page(d->shared_info);
 }
 
+unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4)
+{
+    unsigned long hv_cr4 = read_cr4(), hv_cr4_mask = ~X86_CR4_TSD;
+    if ( cpu_has_de )
+        hv_cr4_mask &= ~X86_CR4_DE;
+
+    if ( (guest_cr4 & hv_cr4_mask) !=
+         (hv_cr4 & hv_cr4_mask & ~(X86_CR4_PGE|X86_CR4_PSE)) )
+        gdprintk(XENLOG_WARNING,
+                 "Attempt to change CR4 flags %08lx -> %08lx\n",
+                 hv_cr4 & ~(X86_CR4_PGE|X86_CR4_PSE), guest_cr4);
+
+    return  (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask);
+}
+
 /* This is called by arch_final_setup_guest and do_boot_vcpu */
 int arch_set_info_guest(
     struct vcpu *v, vcpu_guest_context_u c)
 {
     struct domain *d = v->domain;
     unsigned long cr3_pfn = INVALID_MFN;
-    unsigned long flags;
+    unsigned long flags, cr4;
     int i, rc = 0, compat;
 
     /* The context is a compat-mode one if the target domain is compat-mode;
@@ -665,6 +683,10 @@ int arch_set_info_guest(
     /* Ensure real hardware interrupts are enabled. */
     v->arch.guest_context.user_regs.eflags |= EF_IE;
 
+    cr4 = v->arch.guest_context.ctrlreg[4];
+    v->arch.guest_context.ctrlreg[4] =
+        (cr4 == 0) ? mmu_cr4_features : pv_guest_cr4_fixup(cr4);
+
     if ( v->is_initialised )
         goto out;
 
@@ -1194,6 +1216,9 @@ static void paravirt_ctxt_switch_to(struct vcpu *v)
 {
     set_int80_direct_trap(v);
     switch_kernel_stack(v);
+
+    if ( unlikely(read_cr4() != v->arch.guest_context.ctrlreg[4]) )
+        write_cr4(v->arch.guest_context.ctrlreg[4]);
 }
 
 #define loaddebug(_v,_reg) \
index cb0fbb758009effb76c091565e7e2878081ba087..5a012d4a0daa49f6c67f83dcdb33b3ce6cec2130 100644 (file)
@@ -83,9 +83,12 @@ void write_cr3(unsigned long cr3)
     hvm_flush_guest_tlbs();
 
 #ifdef USER_MAPPINGS_ARE_GLOBAL
-    __pge_off();
-    asm volatile ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
-    __pge_on();
+    {
+        unsigned long cr4 = read_cr4();
+        write_cr4(cr4 & ~X86_CR4_PGE);
+        asm volatile ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
+        write_cr4(cr4);
+    }
 #else
     asm volatile ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
 #endif
@@ -124,8 +127,7 @@ void flush_area_local(const void *va, unsigned int flags)
             hvm_flush_guest_tlbs();
 
 #ifndef USER_MAPPINGS_ARE_GLOBAL
-            if ( !(flags & FLUSH_TLB_GLOBAL) ||
-                 !(mmu_cr4_features & X86_CR4_PGE) )
+            if ( !(flags & FLUSH_TLB_GLOBAL) || !(read_cr4() & X86_CR4_PGE) )
             {
                 asm volatile ( "mov %0, %%cr3"
                                : : "r" (read_cr3()) : "memory" );
@@ -133,9 +135,10 @@ void flush_area_local(const void *va, unsigned int flags)
             else
 #endif
             {
-                __pge_off();
+                unsigned long cr4 = read_cr4();
+                write_cr4(cr4 & ~X86_CR4_PGE);
                 barrier();
-                __pge_on();
+                write_cr4(cr4);
             }
 
             post_flush(t);
index c4c8af3c92659fb7316d438965c0e342fb8c76e2..032ac0028d91451447c30e815255774e24fe8e7a 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <xen/config.h>
+#include <xen/errno.h>
 #include <asm/iommu.h>
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
index 7bd73f18f0a30866d48c74607efedd21655b65bb..78af93ddbad8df4a4d17e257ed3efd7760adb297 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <xen/config.h>
+#include <xen/errno.h>
 #include <asm/amd-iommu.h>
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include <asm-x86/fixmap.h>
index 899aad2bafbb5e2f508761709d7e961ec4229cd6..b5dbe893d2fd912ef4e303507230a88dd498e4da 100644 (file)
@@ -441,7 +441,7 @@ static enum hvm_intblk svm_interrupt_blocked(
     ASSERT((intack.source == hvm_intsrc_pic) ||
            (intack.source == hvm_intsrc_lapic));
 
-    if ( irq_masked(guest_cpu_user_regs()->eflags) )
+    if ( !(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) )
         return hvm_intblk_rflags_ie;
 
     if ( (intack.source == hvm_intsrc_lapic) &&
index 363f88442d9cefb0e5945aabcac466d87adef104..96b2ca6b6d3a3e592810227ecaae75260d65dd29 100644 (file)
@@ -498,7 +498,7 @@ static int construct_vmcs(struct vcpu *v)
 
     /* Host control registers. */
     __vmwrite(HOST_CR0, read_cr0() | X86_CR0_TS);
-    __vmwrite(HOST_CR4, read_cr4());
+    __vmwrite(HOST_CR4, mmu_cr4_features);
 
     /* Host CS:RIP. */
     __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
index 75bceb035ff28a4534c609e65aeeb0e8c8826d70..d74442b93140fe4ce52c27cde46ed2ce05e2fd74 100644 (file)
@@ -727,6 +727,10 @@ static void vmx_ctxt_switch_from(struct vcpu *v)
 
 static void vmx_ctxt_switch_to(struct vcpu *v)
 {
+    /* HOST_CR4 in VMCS is always mmu_cr4_features. Sync CR4 now. */
+    if ( unlikely(read_cr4() != mmu_cr4_features) )
+        write_cr4(mmu_cr4_features);
+
     vmx_restore_guest_msrs(v);
     vmx_restore_dr(v);
 }
@@ -990,7 +994,7 @@ static enum hvm_intblk vmx_interrupt_blocked(
     ASSERT((intack.source == hvm_intsrc_pic) ||
            (intack.source == hvm_intsrc_lapic));
 
-    if ( irq_masked(guest_cpu_user_regs()->eflags) )
+    if ( !(guest_cpu_user_regs()->eflags & X86_EFLAGS_IF) )
         return hvm_intblk_rflags_ie;
 
     if ( intack.source == hvm_intsrc_lapic )
index 47d81c4adaa14f4d5714bdc38168168d6de7a78b..1555f589415ed1a219ecf574b3909637ad0c0f72 100644 (file)
@@ -415,6 +415,8 @@ void __init __start_xen(unsigned long mbi_p)
     set_current((struct vcpu *)0xfffff000); /* debug sanity */
     idle_vcpu[0] = current;
     set_processor_id(0); /* needed early, for smp_processor_id() */
+    rdmsrl(MSR_EFER, this_cpu(efer));
+    asm volatile ( "mov %%cr4,%0" : "=r" (this_cpu(cr4)) );
 
     smp_prepare_boot_cpu();
 
index 5f7585acf8d445bfc38100a6f548adb3f45e5fbc..c8886e947abc758061edb8e396035ac5d8b35f58 100644 (file)
@@ -86,6 +86,12 @@ static inline void check_IPI_mask(cpumask_t cpumask)
     ASSERT(!cpus_empty(cpumask));
 }
 
+void apic_wait_icr_idle(void)
+{
+       while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY )
+               cpu_relax();
+}
+
 void send_IPI_mask_flat(cpumask_t cpumask, int vector)
 {
     unsigned long mask = cpus_addr(cpumask)[0];
index 0ed832d511109243b0e6482dea8d06340c30523d..101918ac8f5f85e1d2fd029e9c1c3b8232629564 100644 (file)
@@ -495,6 +495,8 @@ void __devinit start_secondary(void *unused)
        set_processor_id(cpu);
        set_current(idle_vcpu[cpu]);
        this_cpu(curr_vcpu) = idle_vcpu[cpu];
+       rdmsrl(MSR_EFER, this_cpu(efer));
+       asm volatile ( "mov %%cr4,%0" : "=r" (this_cpu(cr4)) );
 
        percpu_traps_init();
 
index 9ac1d52cbb5f1c1a0ec0e9b49d596757c72bb6eb..7248189304cd993e0bf66ecad33b1d2e48cc9ae8 100644 (file)
@@ -1794,10 +1794,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
             break;
 
         case 4: /* Write CR4 */
-            if ( *reg != (read_cr4() & ~(X86_CR4_PGE|X86_CR4_PSE)) )
-                gdprintk(XENLOG_WARNING,
-                         "Attempt to change CR4 flags %08lx -> %08lx\n",
-                         read_cr4() & ~(X86_CR4_PGE|X86_CR4_PSE), *reg);
+            v->arch.guest_context.ctrlreg[4] = pv_guest_cr4_fixup(*reg);
+            write_cr4(v->arch.guest_context.ctrlreg[4]);
             break;
 
         default:
@@ -1868,6 +1866,10 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         }
         break;
 
+    case 0x31: /* RDTSC */
+        rdtsc(regs->eax, regs->edx);
+        break;
+
     case 0x32: /* RDMSR */
         switch ( regs->ecx )
         {
index fb5c87f94da3c1cefc3167be51a4f95ef76dd600..e91158b6a73bd6b47d1f3be63c16d8be395c20d3 100644 (file)
@@ -22,8 +22,8 @@
 
 #include <xen/init.h>
 #include <xen/types.h>
+#include <xen/list.h>
 #include <xen/spinlock.h>
-#include <xen/mm.h>
 #include <asm/hvm/svm/amd-iommu-defs.h>
 
 #define iommu_found()           (!list_empty(&amd_iommu_head))
index fd0ee81a017cc7236a67ec457f43adcc30286c13..9b1308481adeaa1d72c3a292643f364f456ca690 100644 (file)
@@ -2,9 +2,7 @@
 #define __ASM_APIC_H
 
 #include <xen/config.h>
-#include <asm/fixmap.h>
 #include <asm/apicdef.h>
-#include <asm/processor.h>
 #include <asm/system.h>
 
 #define Dprintk(x...)
@@ -51,11 +49,7 @@ static __inline u32 apic_read(unsigned long reg)
        return *((volatile u32 *)(APIC_BASE+reg));
 }
 
-static __inline__ void apic_wait_icr_idle(void)
-{
-       while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY )
-               cpu_relax();
-}
+void apic_wait_icr_idle(void);
 
 int get_physical_broadcast(void);
 
index 498c2fe591890ae37f3f525c9a43682da8bbfd07..28fbd7b1f73cfa1c79724aa787635a38a2589eb5 100644 (file)
@@ -350,6 +350,8 @@ struct arch_vcpu
 /* Continue the current hypercall via func(data) on specified cpu. */
 int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data);
 
+unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4);
+
 #endif /* __ASM_DOMAIN_H__ */
 
 /*
index 019ecb7acd0f482eb69d82bc857a9bff079dd4b2..1a0287a884a1ba57250fe2a17eb8b05cbdb7a0a6 100644 (file)
@@ -149,13 +149,6 @@ static inline int register_buffered_io_handler(
     return register_io_handler(d, addr, size, action, HVM_BUFFERED_IO);
 }
 
-#if defined(__i386__) || defined(__x86_64__)
-static inline int irq_masked(unsigned long eflags)
-{
-    return ((eflags & X86_EFLAGS_IF) == 0);
-}
-#endif
-
 extern void send_pio_req(unsigned long port, unsigned long count, int size,
                          paddr_t value, int dir, int df, int value_is_ptr);
 void send_timeoffset_req(unsigned long timeoff);
index a211eb5e9fe65190b167c2d0c139bbd045404612..b5107c8e6834ca1465f7e42f87864e7905c934d6 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <xen/types.h>
 #include <xen/spinlock.h>
+#include <asm/irq.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/vpic.h>
 #include <asm/hvm/vioapic.h>
index b8731bf2785450f36bff06215e6ff8c2f38595dd..e8e102a6b87892cad7161de01acb220b8d557238 100644 (file)
@@ -2,9 +2,10 @@
 #define __ASM_IO_APIC_H
 
 #include <xen/config.h>
-#include <asm/fixmap.h>
 #include <asm/types.h>
 #include <asm/mpspec.h>
+#include <asm/apicdef.h>
+#include <asm/fixmap.h>
 
 /*
  * Intel IO-APIC support for SMP and UP systems.
index 2a119f0d661d4a394e94f13788dd3ed39185ce40..e2ceffc7de53ebc5f515ea30773e8987670a462e 100644 (file)
 #define _IOMMU_H_
 
 #include <xen/init.h>
-#include <xen/bitmap.h>
-#include <xen/irq.h>
+#include <xen/list.h>
 #include <xen/spinlock.h>
-#include <xen/mm.h>
-#include <xen/xmalloc.h>
 #include <asm/hvm/vmx/intel-iommu.h>
 #include <public/hvm/ioreq.h>
 #include <public/domctl.h>
index 79d37a33adff9b9cc485443dfd38c3faa00d92bd..96a078824e9ccc42f401f1516c673f672714afda 100644 (file)
@@ -90,16 +90,14 @@ static inline void wrmsrl(unsigned int msr, __u64 val)
                          : "c" (counter))
 
 
-DECLARE_PER_CPU(__u64, efer);
+DECLARE_PER_CPU(u64, efer);
 
-static inline __u64 read_efer(void)
+static inline u64 read_efer(void)
 {
-    if (!this_cpu(efer))
-        rdmsrl(MSR_EFER, this_cpu(efer));
     return this_cpu(efer);
 }
 
-static inline void write_efer(__u64 val)
+static inline void write_efer(u64 val)
 {
     this_cpu(efer) = val;
     wrmsrl(MSR_EFER, val);
index 0ddbd0e214b75b7c240bbcc337002df92365891a..958eee029228e904d489e9922a8628fce36adf15 100644 (file)
@@ -294,9 +294,6 @@ void paging_init(void);
 void setup_idle_pagetable(void);
 #endif /* !defined(__ASSEMBLY__) */
 
-#define __pge_off() write_cr4(mmu_cr4_features & ~X86_CR4_PGE)
-#define __pge_on()  write_cr4(mmu_cr4_features)
-
 #define _PAGE_PRESENT  0x001U
 #define _PAGE_RW       0x002U
 #define _PAGE_USER     0x004U
index 0af78e21c1af6ce4fcecc0d64a7a0af8e4e20e63..e2285cc5f3b223736f40d157493d632d62a16d50 100644 (file)
@@ -8,6 +8,8 @@
 #include <xen/config.h>
 #include <xen/cache.h>
 #include <xen/types.h>
+#include <xen/smp.h>
+#include <xen/percpu.h>
 #include <public/xen.h>
 #include <asm/types.h>
 #include <asm/cpufeature.h>
@@ -298,16 +300,17 @@ static inline unsigned long read_cr2(void)
     return cr2;
 }
 
+DECLARE_PER_CPU(unsigned long, cr4);
+
 static inline unsigned long read_cr4(void)
 {
-    unsigned long cr4;
-    asm volatile ( "mov %%cr4,%0\n\t" : "=r" (cr4) );
-    return cr4;
-} 
-    
+    return this_cpu(cr4);
+}
+
 static inline void write_cr4(unsigned long val)
 {
-    asm volatile ( "mov %0,%%cr4" : : "r" ((unsigned long)val) );
+    this_cpu(cr4) = val;
+    asm volatile ( "mov %0,%%cr4" : : "r" (val) );
 }
 
 /* Clear and set 'TS' bit respectively */
@@ -332,13 +335,13 @@ extern unsigned long mmu_cr4_features;
 static always_inline void set_in_cr4 (unsigned long mask)
 {
     mmu_cr4_features |= mask;
-    write_cr4(mmu_cr4_features);
+    write_cr4(read_cr4() | mask);
 }
 
 static always_inline void clear_in_cr4 (unsigned long mask)
 {
-       mmu_cr4_features &= ~mask;
-       write_cr4(mmu_cr4_features);
+    mmu_cr4_features &= ~mask;
+    write_cr4(read_cr4() & ~mask);
 }
 
 /*
index 9b36a644378f6474c0681482897d275a763bbbb5..55b8cf77055f1cefc6dffe30fe0d10dcccf1c85d 100644 (file)
@@ -13,7 +13,6 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #ifndef __ASSEMBLY__
-#include <asm/fixmap.h>
 #include <asm/bitops.h>
 #include <asm/mpspec.h>
 #ifdef CONFIG_X86_IO_APIC
index 1aa4e07148ea671344a4fd85a4ba31bf6b486332..1abcaaf2836f92077a4054ef6ad1e1786cd57402 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __X86_32_ELF_H__
 #define __X86_32_ELF_H__
 
-#include <asm/processor.h>
-
 typedef struct {
     unsigned long ebx;
     unsigned long ecx;
@@ -40,7 +38,7 @@ static inline void elf_core_save_regs(ELF_Gregset *core_regs,
     asm volatile("movw %%fs, %%ax;" :"=a"(core_regs->fs));
     asm volatile("movw %%gs, %%ax;" :"=a"(core_regs->gs));
     /* orig_eax not filled in for now */
-    core_regs->eip = (unsigned long)current_text_addr();
+    core_regs->eip = (unsigned long)elf_core_save_regs;
     asm volatile("movw %%cs, %%ax;" :"=a"(core_regs->cs));
     asm volatile("pushfl; popl %0" :"=m"(core_regs->eflags));
     asm volatile("movl %%esp,%0" : "=m"(core_regs->esp));
index 39c90b76f6210904d2e88cf9c1f9c0d256722622..df92ec0e64f455f06433f0b4a97d4fbdd3644dd3 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __X86_64_ELF_H__
 #define __X86_64_ELF_H__
 
-#include <asm/processor.h>
-
 typedef struct {
     unsigned long r15;
     unsigned long r14;
@@ -54,7 +52,7 @@ static inline void elf_core_save_regs(ELF_Gregset *core_regs,
     asm volatile("movq %%rsi,%0" : "=m"(core_regs->rsi));
     asm volatile("movq %%rdi,%0" : "=m"(core_regs->rdi));
     /* orig_rax not filled in for now */
-    core_regs->rip = (unsigned long)current_text_addr();
+    core_regs->rip = (unsigned long)elf_core_save_regs;
     asm volatile("movl %%cs, %%eax;" :"=a"(core_regs->cs));
     asm volatile("pushfq; popq %0" :"=m"(core_regs->eflags));
     asm volatile("movq %%rsp,%0" : "=m"(core_regs->rsp));