From: Keir Fraser Date: Mon, 14 Dec 2009 07:46:57 +0000 (+0000) Subject: Add RDTSCP instruction support for HVM VMX guest. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~12915 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=f0308bbb5b79db5be81a511f9c33c0e147bde625;p=xen.git Add RDTSCP instruction support for HVM VMX guest. 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 --- diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 8c974b79ca..c4fe4c1ed3 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -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); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index e2b55a5a04..be4eb7b4f6 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -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; diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h index 1ac3a971ad..72fe0db491 100644 --- a/xen/include/asm-x86/cpufeature.h +++ b/xen/include/asm-x86/cpufeature.h @@ -196,6 +196,8 @@ #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 */ /* diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index a24985bd64..44b6e4cae4 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -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 diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index 8894dbf6d8..28e61ef413 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -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 diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h index aafcec821c..1045fb1f10 100644 --- a/xen/include/asm-x86/msr-index.h +++ b/xen/include/asm-x86/msr-index.h @@ -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 */ diff --git a/xen/include/public/arch-x86/hvm/save.h b/xen/include/public/arch-x86/hvm/save.h index fd81420439..5996cbc8fd 100644 --- a/xen/include/public/arch-x86/hvm/save.h +++ b/xen/include/public/arch-x86/hvm/save.h @@ -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;