Add RDTSCP instruction support for HVM VMX guest.
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 14 Dec 2009 07:46:57 +0000 (07:46 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 14 Dec 2009 07:46:57 +0000 (07:46 +0000)
RDTSCP is introduced in Nehalem processor on Intel platform. Like
RDTSC, RDTSCP will return the TSC value, besides, it will return the
low 32bit of TSC_AUX MSR. Currently Linux kernel will write (node_id
<< 12 | process_id) into that MSR, so that when guest execs RDTSCP, it
will also get processor information.  - This instruction is supported
for HVM only when the hardware has this capability (indicated by
cpuid).

Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/cpufeature.h
xen/include/asm-x86/hvm/vmx/vmcs.h
xen/include/asm-x86/hvm/vmx/vmx.h
xen/include/asm-x86/msr-index.h
xen/include/public/arch-x86/hvm/save.h

index 8c974b79caaafa41e8f1db8cf4b2d6360a3df844..c4fe4c1ed35efade280df2e4e246a5b17d485d0f 100644 (file)
@@ -594,6 +594,11 @@ static int construct_vmcs(struct vcpu *v)
         __vmwrite(PLE_WINDOW, ple_window);
     }
 
+#ifdef __x86_64__
+    if ( cpu_has_rdtscp )
+        v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_RDTSCP;
+#endif
+
     if ( cpu_has_vmx_secondary_exec_control )
         __vmwrite(SECONDARY_VM_EXEC_CONTROL,
                   v->arch.hvm_vmx.secondary_exec_control);
index e2b55a5a04c19159b825f5660c54caadc5bf5677..be4eb7b4f6e9244f559353b23b3568004e078e3a 100644 (file)
@@ -136,18 +136,31 @@ static void vmx_vcpu_destroy(struct vcpu *v)
 
 static DEFINE_PER_CPU(struct vmx_msr_state, host_msr_state);
 
-static u32 msr_index[VMX_MSR_COUNT] =
+static u32 msr_index[] =
 {
     MSR_LSTAR, MSR_STAR, MSR_SYSCALL_MASK
 };
 
+#define MSR_INDEX_SIZE (ARRAY_SIZE(msr_index))
+
 static void vmx_save_host_msrs(void)
 {
     struct vmx_msr_state *host_msr_state = &this_cpu(host_msr_state);
     int i;
 
-    for ( i = 0; i < VMX_MSR_COUNT; i++ )
+    /*
+     * If new MSR is needed to add into msr_index[] and VMX_INDEX_MSR_*** enum,
+     * please note that elements in msr_index[] and VMX_INDEX_MSR_*** enum
+     * are not the same. Currently we only save three MSRs(MSR_LSTAR, MSR_STAR,
+     * and MSR_SYSCALL_MASK into host state. 
+     */
+    BUILD_BUG_ON(MSR_INDEX_SIZE != VMX_INDEX_MSR_TSC_AUX ||
+                 VMX_INDEX_MSR_TSC_AUX != VMX_MSR_COUNT - 1);
+    for ( i = 0; i < MSR_INDEX_SIZE; i++ )
         rdmsrl(msr_index[i], host_msr_state->msrs[i]);
+
+    if ( cpu_has_rdtscp )
+        rdmsrl(MSR_TSC_AUX, host_msr_state->msrs[VMX_INDEX_MSR_TSC_AUX]);
 }
 
 #define WRITE_MSR(address)                                              \
@@ -198,6 +211,21 @@ static enum handler_return long_mode_do_msr_read(struct cpu_user_regs *regs)
         msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK];
         break;
 
+    case MSR_TSC_AUX:
+        if ( cpu_has_rdtscp ) 
+        {
+            msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_TSC_AUX];
+            break;
+        }
+        else
+        {
+            HVM_DBG_LOG(DBG_LEVEL_0, "Reading from nonexistence msr 0x%x\n",
+                        ecx);
+            vmx_inject_hw_exception(TRAP_gp_fault, 0);
+            return HNDL_exception_raised;
+        }
+            
+
     default:
         return HNDL_unhandled;
     }
@@ -259,6 +287,20 @@ static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
     case MSR_SYSCALL_MASK:
         WRITE_MSR(SYSCALL_MASK);
 
+    case MSR_TSC_AUX:
+        if ( cpu_has_rdtscp )
+        {
+            struct vmx_msr_state *guest_state = &v->arch.hvm_vmx.msr_state;
+            guest_state->msrs[VMX_INDEX_MSR_TSC_AUX] = msr_content;
+            wrmsrl(MSR_TSC_AUX, msr_content);
+        }
+        else
+        {
+            HVM_DBG_LOG(DBG_LEVEL_0, "Writing to nonexistence msr 0x%x\n", ecx);
+            vmx_inject_hw_exception(TRAP_gp_fault, 0);
+            return HNDL_exception_raised;
+        }
+
     default:
         return HNDL_unhandled;
     }
@@ -289,15 +331,21 @@ static void vmx_restore_host_msrs(void)
         wrmsrl(msr_index[i], host_msr_state->msrs[i]);
         clear_bit(i, &host_msr_state->flags);
     }
+
+    if ( cpu_has_rdtscp )
+        wrmsrl(MSR_TSC_AUX, host_msr_state->msrs[VMX_INDEX_MSR_TSC_AUX]);
 }
 
 static void vmx_save_guest_msrs(struct vcpu *v)
 {
+    struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state;
     /*
      * We cannot cache SHADOW_GS_BASE while the VCPU runs, as it can
      * be updated at any time via SWAPGS, which we cannot trap.
      */
     rdmsrl(MSR_SHADOW_GS_BASE, v->arch.hvm_vmx.shadow_gs);
+    if ( cpu_has_rdtscp )
+        rdmsrl(MSR_TSC_AUX, guest_msr_state->msrs[VMX_INDEX_MSR_TSC_AUX]);
 }
 
 static void vmx_restore_guest_msrs(struct vcpu *v)
@@ -333,6 +381,9 @@ static void vmx_restore_guest_msrs(struct vcpu *v)
         write_efer((read_efer() & ~EFER_SCE) |
                    (v->arch.hvm_vcpu.guest_efer & EFER_SCE));
     }
+
+    if ( cpu_has_rdtscp )
+        wrmsrl(MSR_TSC_AUX, guest_msr_state->msrs[VMX_INDEX_MSR_TSC_AUX]);
 }
 
 #else  /* __i386__ */
@@ -574,6 +625,8 @@ static void vmx_save_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
     data->msr_lstar        = guest_state->msrs[VMX_INDEX_MSR_LSTAR];
     data->msr_star         = guest_state->msrs[VMX_INDEX_MSR_STAR];
     data->msr_syscall_mask = guest_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK];
+    if ( cpu_has_rdtscp )
+        data->msr_tsc_aux = guest_state->msrs[VMX_INDEX_MSR_TSC_AUX];
 #endif
 
     data->tsc = hvm_get_guest_tsc(v);
@@ -592,6 +645,8 @@ static void vmx_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
 
     v->arch.hvm_vmx.cstar     = data->msr_cstar;
     v->arch.hvm_vmx.shadow_gs = data->shadow_gs;
+    if ( cpu_has_rdtscp )
+        guest_state->msrs[VMX_INDEX_MSR_TSC_AUX] = data->msr_tsc_aux;
 #endif
 
     hvm_set_guest_tsc(v, data->tsc);
@@ -1507,6 +1562,14 @@ static void vmx_cpuid_intercept(
                 *edx |= bitmaskof(X86_FEATURE_SYSCALL);
             else
                 *edx &= ~(bitmaskof(X86_FEATURE_SYSCALL));
+
+#ifdef __x86_64__
+            if ( cpu_has_rdtscp )
+                *edx |= bitmaskof(X86_FEATURE_RDTSCP);
+            else
+                *edx &= ~(bitmaskof(X86_FEATURE_RDTSCP));
+#endif
+
             break;
     }
 
@@ -2495,6 +2558,15 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs)
         __update_guest_eip(inst_len);
         hvm_rdtsc_intercept(regs);
         break;
+    case EXIT_REASON_RDTSCP:
+    {
+        struct vmx_msr_state *guest_state = &v->arch.hvm_vmx.msr_state;
+        inst_len = __get_instruction_length();
+        __update_guest_eip(inst_len);
+        hvm_rdtsc_intercept(regs);
+        regs->ecx = (uint32_t)(guest_state->msrs[VMX_INDEX_MSR_TSC_AUX]);
+        break;
+    }
     case EXIT_REASON_VMCALL:
     {
         int rc;
index 1ac3a971ad72a82b7a78a2699f580f1e9c76ef51..72fe0db491e7208b0a8ed2e97a34994913c2b7d1 100644 (file)
 
 #define cpu_has_arch_perfmon    boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
 
+#define cpu_has_rdtscp          boot_cpu_has(X86_FEATURE_RDTSCP)
+
 #endif /* __ASM_I386_CPUFEATURE_H */
 
 /* 
index a24985bd645223c1c1d8ee81d7e37da5853dcd72..44b6e4cae48bf54c2994d622aedb160c751b3bf4 100644 (file)
@@ -44,6 +44,7 @@ enum {
     VMX_INDEX_MSR_LSTAR = 0,
     VMX_INDEX_MSR_STAR,
     VMX_INDEX_MSR_SYSCALL_MASK,
+    VMX_INDEX_MSR_TSC_AUX,
 
     VMX_MSR_COUNT
 };
@@ -166,6 +167,7 @@ extern u32 vmx_vmentry_control;
 
 #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
 #define SECONDARY_EXEC_ENABLE_EPT               0x00000002
+#define SECONDARY_EXEC_ENABLE_RDTSCP            0x00000008
 #define SECONDARY_EXEC_ENABLE_VPID              0x00000020
 #define SECONDARY_EXEC_WBINVD_EXITING           0x00000040
 #define SECONDARY_EXEC_UNRESTRICTED_GUEST       0x00000080
index 8894dbf6d86b4581fccf633a08c8d805d6ad9bca..28e61ef4131377b0e8d6f33791c2bf58ce676532 100644 (file)
@@ -110,6 +110,7 @@ void vmx_update_debug_state(struct vcpu *v);
 #define EXIT_REASON_APIC_ACCESS         44
 #define EXIT_REASON_EPT_VIOLATION       48
 #define EXIT_REASON_EPT_MISCONFIG       49
+#define EXIT_REASON_RDTSCP              51
 #define EXIT_REASON_WBINVD              54
 #define EXIT_REASON_XSETBV              55
 
index aafcec821c1409e4f7817d622e9b069a4894c7ef..1045fb1f1030a8698d91064ec9606b5830bd99d6 100644 (file)
@@ -12,6 +12,7 @@
 #define MSR_FS_BASE            0xc0000100 /* 64bit FS base */
 #define MSR_GS_BASE            0xc0000101 /* 64bit GS base */
 #define MSR_SHADOW_GS_BASE     0xc0000102 /* SwapGS GS shadow */
+#define MSR_TSC_AUX            0xc0000103 /* Auxiliary TSC */
 
 /* EFER bits: */
 #define _EFER_SCE              0  /* SYSCALL/SYSRET */
index fd81420439a6d58de923a5f76120eb24ec6c9d4e..5996cbc8fd3975be66e7367703e8cf5b0b8204f9 100644 (file)
@@ -137,6 +137,7 @@ struct hvm_hw_cpu {
     uint64_t msr_cstar;
     uint64_t msr_syscall_mask;
     uint64_t msr_efer;
+    uint64_t msr_tsc_aux;
 
     /* guest's idea of what rdtsc() would return */
     uint64_t tsc;