x86 hvm: New boot option 'softtsc' to cause RDTSC to be trapped-and-emulated.
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 10 Jul 2008 14:45:18 +0000 (15:45 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 10 Jul 2008 14:45:18 +0000 (15:45 +0100)
Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/svm/vmcb.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/support.h

index 04e9da6e0e9e54479417dfee05c14d1c9d281723..4b58db1d679b8c6f8e14d576a8917893b17194b5 100644 (file)
@@ -57,6 +57,9 @@ int hvm_enabled __read_mostly;
 unsigned int opt_hvm_debug_level __read_mostly;
 integer_param("hvm_debug", opt_hvm_debug_level);
 
+int opt_softtsc;
+boolean_param("softtsc", opt_softtsc);
+
 struct hvm_function_table hvm_funcs __read_mostly;
 
 /* I/O permission bitmap is globally shared by all HVM guests. */
@@ -148,7 +151,11 @@ u64 hvm_get_guest_tsc(struct vcpu *v)
 {
     u64 host_tsc;
 
-    rdtscll(host_tsc);
+    if ( opt_softtsc )
+        host_tsc = hvm_get_guest_time(v);
+    else
+        rdtscll(host_tsc);
+
     return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
 }
 
@@ -1651,6 +1658,16 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
     }
 }
 
+void hvm_rdtsc_intercept(struct cpu_user_regs *regs)
+{
+    uint64_t tsc;
+    struct vcpu *v = current;
+
+    tsc = hvm_get_guest_tsc(v);
+    regs->eax = (uint32_t)tsc;
+    regs->edx = (uint32_t)(tsc >> 32);
+}
+
 int hvm_msr_read_intercept(struct cpu_user_regs *regs)
 {
     uint32_t ecx = regs->ecx;
index 86a476773786cdb6f2f78690647b327e34e4c3c0..ea72939413637fe89a0f38642bd8c507f49b1365 100644 (file)
@@ -1340,6 +1340,10 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
         hvm_triple_fault();
         break;
 
+    case VMEXIT_RDTSC:
+        hvm_rdtsc_intercept(regs);
+        break;
+
     case VMEXIT_RDTSCP:
     case VMEXIT_MONITOR:
     case VMEXIT_MWAIT:
index 0cf8347d85099e2642a370066cc3d86f55f349f7..73894f881c286eaaf497e430687a1649b7e4767d 100644 (file)
@@ -165,7 +165,9 @@ static int construct_vmcb(struct vcpu *v)
 
     /* TSC. */
     vmcb->tsc_offset = 0;
-    
+    if ( opt_softtsc )
+        vmcb->general1_intercepts |= GENERAL1_INTERCEPT_RDTSC;
+
     /* Guest EFER: *must* contain SVME or VMRUN will fail. */
     vmcb->efer = EFER_SVME;
 
index bda2ec953e3eee51d8376b6500b4add59805ec1c..4341859bce51a1ce50fbfa87d053d413c0148d28 100644 (file)
@@ -95,7 +95,8 @@ static void vmx_init_vmcs_config(void)
            CPU_BASED_MWAIT_EXITING |
            CPU_BASED_MOV_DR_EXITING |
            CPU_BASED_ACTIVATE_IO_BITMAP |
-           CPU_BASED_USE_TSC_OFFSETING);
+           CPU_BASED_USE_TSC_OFFSETING |
+           (opt_softtsc ? CPU_BASED_RDTSC_EXITING : 0));
     opt = (CPU_BASED_ACTIVATE_MSR_BITMAP |
            CPU_BASED_TPR_SHADOW |
            CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
index 8114a93ad2bd6a10a43fa5ef3174201550d07ca0..fbefbd7f75368af4021d64f7e281557af3311b40 100644 (file)
@@ -2205,6 +2205,11 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs)
         vmx_invlpg_intercept(exit_qualification);
         break;
     }
+    case EXIT_REASON_RDTSC:
+        inst_len = __get_instruction_length();
+        __update_guest_eip(inst_len);
+        hvm_rdtsc_intercept(regs);
+        break;
     case EXIT_REASON_VMCALL:
     {
         int rc;
index 38a0025855e468d291562efdd02ee5ea3f08af1c..9e3ef99e9b690117d38031b1ea6d77ca70892aea 100644 (file)
@@ -125,6 +125,9 @@ int hvm_do_hypercall(struct cpu_user_regs *pregs);
 void hvm_hlt(unsigned long rflags);
 void hvm_triple_fault(void);
 
+extern int opt_softtsc;
+void hvm_rdtsc_intercept(struct cpu_user_regs *regs);
+
 /* These functions all return X86EMUL return codes. */
 int hvm_set_efer(uint64_t value);
 int hvm_set_cr0(unsigned long value);