diff mbox

[v3,7/7] KVM: x86: Add support for VMware backdoor Pseudo-PMCs

Message ID 1520853173-7709-8-git-send-email-liran.alon@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liran Alon March 12, 2018, 11:12 a.m. UTC
From: Arbel Moshe <arbel.moshe@oracle.com>

VMware exposes the following Pseudo PMCs:
0x10000: Physical host TSC
0x10001: Elapsed real time in ns
0x10002: Elapsed apparent time in ns

For more info refer to:
https://www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf

VMware allows access to these Pseduo-PMCs even when read via RDPMC
in Ring3 and CR4.PCE=0. Therefore, commit modifies x86 emulator
to allow access to these PMCs in this situation. In addition,
emulation of these PMCs were added to kvm_pmu_rdpmc().

Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 arch/x86/kvm/emulate.c |  8 ++++++++
 arch/x86/kvm/pmu.c     | 37 +++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/pmu.h     |  6 ++++++
 arch/x86/kvm/x86.c     | 39 ++++++++++++++++++++++-----------------
 4 files changed, 73 insertions(+), 17 deletions(-)

Comments

Radim Krčmář March 16, 2018, 3:41 p.m. UTC | #1
2018-03-12 13:12+0200, Liran Alon:
> From: Arbel Moshe <arbel.moshe@oracle.com>
> 
> VMware exposes the following Pseudo PMCs:
> 0x10000: Physical host TSC
> 0x10001: Elapsed real time in ns
> 0x10002: Elapsed apparent time in ns
> 
> For more info refer to:
> https://www.vmware.com/files/pdf/techpaper/Timekeeping-In-VirtualMachines.pdf
> 
> VMware allows access to these Pseduo-PMCs even when read via RDPMC
> in Ring3 and CR4.PCE=0. Therefore, commit modifies x86 emulator
> to allow access to these PMCs in this situation. In addition,
> emulation of these PMCs were added to kvm_pmu_rdpmc().
> 
> Signed-off-by: Arbel Moshe <arbel.moshe@oracle.com>
> Reviewed-by: Liran Alon <liran.alon@oracle.com>
> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> ---
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> @@ -5887,23 +5887,28 @@ static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
>  
>  static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)
>  {
> -	if (ctxt->opcode_len != 1)
> -		return false;
> -
> -	switch (ctxt->b) {
> -	case 0xe4:	/* IN */
> -	case 0xe5:
> -	case 0xec:
> -	case 0xed:
> -	case 0xe6:	/* OUT */
> -	case 0xe7:
> -	case 0xee:
> -	case 0xef:
> -	case 0x6c:	/* INS */
> -	case 0x6d:
> -	case 0x6e:	/* OUTS */
> -	case 0x6f:
> -		return true;
> +	switch (ctxt->opcode_len) {
> +	case 1:
> +		switch (ctxt->b) {
> +		case 0xe4:	/* IN */
> +		case 0xe5:
> +		case 0xec:
> +		case 0xed:
> +		case 0xe6:	/* OUT */
> +		case 0xe7:
> +		case 0xee:
> +		case 0xef:
> +		case 0x6c:	/* INS */
> +		case 0x6d:
> +		case 0x6e:	/* OUTS */
> +		case 0x6f:
> +			return true;
> +		}

We fall through and return true for 0x33 with opcode_len == 1,
plase add a break.

> +	case 2:
> +		switch (ctxt->b) {
> +		case 0x33:	/* RDPMC */
> +			return true;
> +		}
>  	}
>  
>  	return false;
> -- 
> 1.9.1
>
diff mbox

Patch

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 821f6335cbcb..dd88158a0eed 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -30,6 +30,7 @@ 
 #include "x86.h"
 #include "tss.h"
 #include "mmu.h"
+#include "pmu.h"
 
 /*
  * Operand types
@@ -4293,6 +4294,13 @@  static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
 	u64 cr4 = ctxt->ops->get_cr(ctxt, 4);
 	u64 rcx = reg_read(ctxt, VCPU_REGS_RCX);
 
+	/*
+	 * VMware allows access to these Pseduo-PMCs even when read via RDPMC
+	 * in Ring3 when CR4.PCE=0.
+	 */
+	if (enable_vmware_backdoor && is_vmware_backdoor_pmc(rcx))
+		return X86EMUL_CONTINUE;
+
 	if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) ||
 	    ctxt->ops->check_pmc(ctxt, rcx))
 		return emulate_gp(ctxt, 0);
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 026db42a86c3..58ead7db71a3 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -244,12 +244,49 @@  int kvm_pmu_is_valid_msr_idx(struct kvm_vcpu *vcpu, unsigned idx)
 	return kvm_x86_ops->pmu_ops->is_valid_msr_idx(vcpu, idx);
 }
 
+bool is_vmware_backdoor_pmc(u32 pmc_idx)
+{
+	switch (pmc_idx) {
+	case VMWARE_BACKDOOR_PMC_HOST_TSC:
+	case VMWARE_BACKDOOR_PMC_REAL_TIME:
+	case VMWARE_BACKDOOR_PMC_APPARENT_TIME:
+		return true;
+	}
+	return false;
+}
+
+static int kvm_pmu_rdpmc_vmware(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
+{
+	u64 ctr_val;
+
+	switch (idx) {
+	case VMWARE_BACKDOOR_PMC_HOST_TSC:
+		ctr_val = rdtsc();
+		break;
+	case VMWARE_BACKDOOR_PMC_REAL_TIME:
+		ctr_val = ktime_get_boot_ns();
+		break;
+	case VMWARE_BACKDOOR_PMC_APPARENT_TIME:
+		ctr_val = ktime_get_boot_ns() +
+			vcpu->kvm->arch.kvmclock_offset;
+		break;
+	default:
+		return 1;
+	}
+
+	*data = ctr_val;
+	return 0;
+}
+
 int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
 {
 	bool fast_mode = idx & (1u << 31);
 	struct kvm_pmc *pmc;
 	u64 ctr_val;
 
+	if (is_vmware_backdoor_pmc(idx))
+		return kvm_pmu_rdpmc_vmware(vcpu, idx, data);
+
 	pmc = kvm_x86_ops->pmu_ops->msr_idx_to_pmc(vcpu, idx);
 	if (!pmc)
 		return 1;
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index a9a62b9a73e2..ba8898e1a854 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -9,6 +9,10 @@ 
 /* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */
 #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
 
+#define VMWARE_BACKDOOR_PMC_HOST_TSC		0x10000
+#define VMWARE_BACKDOOR_PMC_REAL_TIME		0x10001
+#define VMWARE_BACKDOOR_PMC_APPARENT_TIME	0x10002
+
 struct kvm_event_hw_type_mapping {
 	u8 eventsel;
 	u8 unit_mask;
@@ -114,6 +118,8 @@  static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
 void kvm_pmu_init(struct kvm_vcpu *vcpu);
 void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
 
+bool is_vmware_backdoor_pmc(u32 pmc_idx);
+
 extern struct kvm_pmu_ops intel_pmu_ops;
 extern struct kvm_pmu_ops amd_pmu_ops;
 #endif /* __KVM_X86_PMU_H */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 8288500acd93..2154d20a6874 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5887,23 +5887,28 @@  static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
 
 static bool is_vmware_backdoor_opcode(struct x86_emulate_ctxt *ctxt)
 {
-	if (ctxt->opcode_len != 1)
-		return false;
-
-	switch (ctxt->b) {
-	case 0xe4:	/* IN */
-	case 0xe5:
-	case 0xec:
-	case 0xed:
-	case 0xe6:	/* OUT */
-	case 0xe7:
-	case 0xee:
-	case 0xef:
-	case 0x6c:	/* INS */
-	case 0x6d:
-	case 0x6e:	/* OUTS */
-	case 0x6f:
-		return true;
+	switch (ctxt->opcode_len) {
+	case 1:
+		switch (ctxt->b) {
+		case 0xe4:	/* IN */
+		case 0xe5:
+		case 0xec:
+		case 0xed:
+		case 0xe6:	/* OUT */
+		case 0xe7:
+		case 0xee:
+		case 0xef:
+		case 0x6c:	/* INS */
+		case 0x6d:
+		case 0x6e:	/* OUTS */
+		case 0x6f:
+			return true;
+		}
+	case 2:
+		switch (ctxt->b) {
+		case 0x33:	/* RDPMC */
+			return true;
+		}
 	}
 
 	return false;