* [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR
2011-03-15 9:36 [PATCH 0/6] TSC scaling support for KVM v2 Joerg Roedel
@ 2011-03-15 9:36 ` Joerg Roedel
0 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-15 9:36 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch enhances the kvm_amd module with functions to
support the TSC_RATE_MSR which can be used to set a given
tsc frequency for the guest vcpu.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kvm/svm.c | 44 +++++++++++++++++++++++++++++++++++++-
2 files changed, 44 insertions(+), 1 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 5bfafb6..fdac548 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -106,6 +106,7 @@
complete list. */
#define MSR_AMD64_PATCH_LEVEL 0x0000008b
+#define MSR_AMD64_TSC_RATIO 0xc0000104
#define MSR_AMD64_NB_CFG 0xc001001f
#define MSR_AMD64_PATCH_LOADER 0xc0010020
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 6bb15d5..72373b6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -63,6 +63,8 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+#define TSC_RATIO_RSVD 0xffffff0000000000ULL
+
static bool erratum_383_found __read_mostly;
static const u32 host_save_user_msrs[] = {
@@ -144,6 +146,12 @@ struct vcpu_svm {
unsigned int3_injected;
unsigned long int3_rip;
u32 apf_reason;
+
+ struct {
+ bool enabled;
+ u64 ratio;
+ } tsc_scale;
+
};
#define MSR_INVALID 0xffffffffU
@@ -854,6 +862,32 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
+static u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+ u64 mult, frac, _tsc;
+
+ mult = ratio >> 32;
+ frac = ratio & ((1ULL << 32) - 1);
+
+ _tsc = tsc;
+ _tsc *= mult;
+ _tsc += (tsc >> 32) * frac;
+ _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
+
+ return _tsc;
+}
+
+static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 _tsc = tsc;
+
+ if (svm->tsc_scale.enabled)
+ _tsc = __scale_tsc(svm->tsc_scale.ratio, tsc);
+
+ return _tsc;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1141,6 +1175,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && svm->tsc_scale.enabled)
+ wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale.ratio);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1161,6 +1198,9 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
#endif
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && svm->tsc_scale.enabled)
+ wrmsr(MSR_AMD64_TSC_RATIO, 0, 1);
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -2813,7 +2853,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
case MSR_IA32_TSC: {
struct vmcb *vmcb = get_host_vmcb(svm);
- *data = vmcb->control.tsc_offset + native_read_tsc();
+ *data = vmcb->control.tsc_offset +
+ svm_scale_tsc(vcpu, native_read_tsc());
+
break;
}
case MSR_STAR:
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 0/6][RESEND] TSC scaling support for KVM v2
@ 2011-03-24 7:40 Joerg Roedel
2011-03-24 7:40 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
` (5 more replies)
0 siblings, 6 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm
Hi,
this is version 2 of the TSC scaling patch-set. The main difference to
version 1 is that the scaling factor is not switched in the leightweight
exit path anymore. This is possible because production hardware will
apply the scaling factor only when the CPU is in guest mode.
Beside that change I addressed the comments that came up in the review
of the first version. An important change here is that I changed the
usage of the adjust_tsc_offset() function and calculate all adjustment
values only from the guest tsc. This change should make it suitable to
the changes Zachary wants to implement.
Comments on this patches appreciated.
Thanks,
Joerg
Diffstat:
Documentation/kvm/api.txt | 22 ++++++++
arch/x86/include/asm/kvm_host.h | 10 ++++
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kvm/svm.c | 110 +++++++++++++++++++++++++++++++++++++-
arch/x86/kvm/vmx.c | 12 ++++
arch/x86/kvm/x86.c | 87 +++++++++++++++++++++++++++---
include/linux/kvm.h | 5 ++
7 files changed, 237 insertions(+), 10 deletions(-)
Shortlog:
Joerg Roedel (6):
KVM: SVM: Implement infrastructure for TSC_RATE_MSR
KVM: X86: Let kvm-clock report the right tsc frequency
KVM: X86: Make tsc_delta calculation a function of guest tsc
KVM: SVM: Propagate requested TSC frequency on vcpu init
KVM: X86: Delegate tsc-offset calculation to architecture code
KVM: X86: Implement userspace interface to set virtual_tsc_khz
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 9:51 ` Avi Kivity
2011-03-24 7:40 ` [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency Joerg Roedel
` (4 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch enhances the kvm_amd module with functions to
support the TSC_RATE_MSR which can be used to set a given
tsc frequency for the guest vcpu.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kvm/svm.c | 44 +++++++++++++++++++++++++++++++++++++-
2 files changed, 44 insertions(+), 1 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index fd5a1f3..a7b3e40 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -114,6 +114,7 @@
complete list. */
#define MSR_AMD64_PATCH_LEVEL 0x0000008b
+#define MSR_AMD64_TSC_RATIO 0xc0000104
#define MSR_AMD64_NB_CFG 0xc001001f
#define MSR_AMD64_PATCH_LOADER 0xc0010020
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 2a19322..4e5da50 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -63,6 +63,8 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+#define TSC_RATIO_RSVD 0xffffff0000000000ULL
+
static bool erratum_383_found __read_mostly;
static const u32 host_save_user_msrs[] = {
@@ -144,6 +146,12 @@ struct vcpu_svm {
unsigned int3_injected;
unsigned long int3_rip;
u32 apf_reason;
+
+ struct {
+ bool enabled;
+ u64 ratio;
+ } tsc_scale;
+
};
#define MSR_INVALID 0xffffffffU
@@ -854,6 +862,32 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
+static u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+ u64 mult, frac, _tsc;
+
+ mult = ratio >> 32;
+ frac = ratio & ((1ULL << 32) - 1);
+
+ _tsc = tsc;
+ _tsc *= mult;
+ _tsc += (tsc >> 32) * frac;
+ _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
+
+ return _tsc;
+}
+
+static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 _tsc = tsc;
+
+ if (svm->tsc_scale.enabled)
+ _tsc = __scale_tsc(svm->tsc_scale.ratio, tsc);
+
+ return _tsc;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1141,6 +1175,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && svm->tsc_scale.enabled)
+ wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale.ratio);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1161,6 +1198,9 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
#endif
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && svm->tsc_scale.enabled)
+ wrmsr(MSR_AMD64_TSC_RATIO, 0, 1);
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -2813,7 +2853,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
case MSR_IA32_TSC: {
struct vmcb *vmcb = get_host_vmcb(svm);
- *data = vmcb->control.tsc_offset + native_read_tsc();
+ *data = vmcb->control.tsc_offset +
+ svm_scale_tsc(vcpu, native_read_tsc());
+
break;
}
case MSR_STAR:
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
2011-03-24 7:40 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 9:58 ` Avi Kivity
2011-03-24 7:40 ` [PATCH 3/6] KVM: X86: Make tsc_delta calculation a function of guest tsc Joerg Roedel
` (3 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch changes the kvm_guest_time_update function to use
TSC frequency the guest actually has for updating its clock.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_host.h | 2 ++
arch/x86/kvm/svm.c | 8 ++++++++
arch/x86/kvm/vmx.c | 6 ++++++
arch/x86/kvm/x86.c | 11 +++++++++--
4 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 35f81b1..16e7240 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -590,6 +590,8 @@ struct kvm_x86_ops {
void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+ bool (*use_virtual_tsc_khz)(struct kvm_vcpu *vcpu);
+
void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
const struct trace_print_flags *exit_reasons_str;
};
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 4e5da50..40ade85 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -914,6 +914,13 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
}
+static bool svm_use_virtual_tsc_khz(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ return svm->tsc_scale.enabled;
+}
+
static void init_vmcb(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3996,6 +4003,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.write_tsc_offset = svm_write_tsc_offset,
.adjust_tsc_offset = svm_adjust_tsc_offset,
+ .use_virtual_tsc_khz = svm_use_virtual_tsc_khz,
.set_tdp_cr3 = set_tdp_cr3,
};
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1bdb49d..e0a6d4a 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1174,6 +1174,11 @@ static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
vmcs_write64(TSC_OFFSET, offset + adjustment);
}
+static bool vmx_use_virtual_tsc_khz(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
/*
* Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise.
@@ -4498,6 +4503,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.write_tsc_offset = vmx_write_tsc_offset,
.adjust_tsc_offset = vmx_adjust_tsc_offset,
+ .use_virtual_tsc_khz = vmx_use_virtual_tsc_khz,
.set_tdp_cr3 = vmx_set_cr3,
};
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1b8b16a..7979da4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -982,6 +982,14 @@ static inline int kvm_tsc_changes_freq(void)
return ret;
}
+static u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
+{
+ if (kvm_x86_ops->use_virtual_tsc_khz(vcpu))
+ return vcpu->kvm->arch.virtual_tsc_khz;
+ else
+ return __this_cpu_read(cpu_tsc_khz);
+}
+
static inline u64 nsec_to_cycles(u64 nsec)
{
u64 ret;
@@ -1075,8 +1083,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
local_irq_save(flags);
kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
kernel_ns = get_kernel_ns();
- this_tsc_khz = __this_cpu_read(cpu_tsc_khz);
-
+ this_tsc_khz = vcpu_tsc_khz(v);
if (unlikely(this_tsc_khz == 0)) {
local_irq_restore(flags);
kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 3/6] KVM: X86: Make tsc_delta calculation a function of guest tsc
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
2011-03-24 7:40 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
2011-03-24 7:40 ` [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 7:40 ` [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init Joerg Roedel
` (2 subsequent siblings)
5 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
The calculation of the tsc_delta value to ensure a
forward-going tsc for the guest is a function of the
host-tsc. This works as long as the guests tsc_khz is equal
to the hosts tsc_khz. With tsc-scaling hardware support this
is not longer true and the tsc_delta needs to be calculated
using guest_tsc values.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/x86.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7979da4..4fae242 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2127,8 +2127,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_x86_ops->vcpu_load(vcpu, cpu);
if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
/* Make sure TSC doesn't go backwards */
- s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
- native_read_tsc() - vcpu->arch.last_host_tsc;
+ s64 tsc_delta;
+ u64 tsc;
+
+ kvm_get_msr(vcpu, MSR_IA32_TSC, &tsc);
+ tsc_delta = !vcpu->arch.last_guest_tsc ? 0 :
+ tsc - vcpu->arch.last_guest_tsc;
+
if (tsc_delta < 0)
mark_tsc_unstable("KVM discovered backwards TSC");
if (check_tsc_unstable()) {
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
` (2 preceding siblings ...)
2011-03-24 7:40 ` [PATCH 3/6] KVM: X86: Make tsc_delta calculation a function of guest tsc Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 10:04 ` Avi Kivity
2011-03-24 7:40 ` [PATCH 5/6] KVM: X86: Delegate tsc-offset calculation to architecture code Joerg Roedel
2011-03-24 7:40 ` [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz Joerg Roedel
5 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch implements the propagation of the VM
virtual_tsc_khz into each vcpu data-structure to enable the
tsc-scaling feature.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/kvm/svm.c | 33 +++++++++++++++++++++++++++++++++
1 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 40ade85..d747db8 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -888,6 +888,36 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
return _tsc;
}
+static bool svm_vcpu_init_tsc(struct kvm *kvm, struct vcpu_svm *svm)
+{
+ u64 ratio;
+ u64 khz;
+
+ /* TSC scaling supported? */
+ if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+ return true;
+
+ /* Guest tsc same frequency as host tsc? */
+ if (kvm->arch.virtual_tsc_khz == tsc_khz)
+ return true;
+
+ khz = kvm->arch.virtual_tsc_khz;
+
+ if (khz == 0)
+ return false;
+
+ /* TSC scaling required - calculate ratio */
+ ratio = (u64)khz << 32;
+ do_div(ratio, tsc_khz);
+ if (ratio == 0 || ratio & TSC_RATIO_RSVD)
+ return false;
+
+ svm->tsc_scale.ratio = ratio;
+ svm->tsc_scale.enabled = true;
+
+ return true;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1093,6 +1123,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
if (err)
goto free_svm;
+ if (!svm_vcpu_init_tsc(kvm, svm))
+ goto uninit;
+
err = -ENOMEM;
page = alloc_page(GFP_KERNEL);
if (!page)
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 5/6] KVM: X86: Delegate tsc-offset calculation to architecture code
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
` (3 preceding siblings ...)
2011-03-24 7:40 ` [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 7:40 ` [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz Joerg Roedel
5 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
With TSC scaling in SVM the tsc-offset needs to be
calculated differently. This patch propagates this
calculation into the architecture specific modules so that
this complexity can be handled there.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/svm.c | 10 ++++++++++
arch/x86/kvm/vmx.c | 6 ++++++
arch/x86/kvm/x86.c | 10 +++++-----
4 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 16e7240..6fe1e84 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -591,6 +591,7 @@ struct kvm_x86_ops {
void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
bool (*use_virtual_tsc_khz)(struct kvm_vcpu *vcpu);
+ u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
const struct trace_print_flags *exit_reasons_str;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index d747db8..32d444f 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -951,6 +951,15 @@ static bool svm_use_virtual_tsc_khz(struct kvm_vcpu *vcpu)
return svm->tsc_scale.enabled;
}
+static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+ u64 tsc;
+
+ tsc = svm_scale_tsc(vcpu, native_read_tsc());
+
+ return target_tsc - tsc;
+}
+
static void init_vmcb(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -4037,6 +4046,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.write_tsc_offset = svm_write_tsc_offset,
.adjust_tsc_offset = svm_adjust_tsc_offset,
.use_virtual_tsc_khz = svm_use_virtual_tsc_khz,
+ .compute_tsc_offset = svm_compute_tsc_offset,
.set_tdp_cr3 = set_tdp_cr3,
};
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index e0a6d4a..097d213 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1179,6 +1179,11 @@ static bool vmx_use_virtual_tsc_khz(struct kvm_vcpu *vcpu)
return false;
}
+static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+ return target_tsc - native_read_tsc();
+}
+
/*
* Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise.
@@ -4504,6 +4509,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.write_tsc_offset = vmx_write_tsc_offset,
.adjust_tsc_offset = vmx_adjust_tsc_offset,
.use_virtual_tsc_khz = vmx_use_virtual_tsc_khz,
+ .compute_tsc_offset = vmx_compute_tsc_offset,
.set_tdp_cr3 = vmx_set_cr3,
};
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4fae242..7754079 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -990,7 +990,7 @@ static u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
return __this_cpu_read(cpu_tsc_khz);
}
-static inline u64 nsec_to_cycles(u64 nsec)
+static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
{
u64 ret;
@@ -998,7 +998,7 @@ static inline u64 nsec_to_cycles(u64 nsec)
if (kvm_tsc_changes_freq())
printk_once(KERN_WARNING
"kvm: unreliable cycle conversion on adjustable rate TSC\n");
- ret = nsec * __this_cpu_read(cpu_tsc_khz);
+ ret = nsec * vcpu_tsc_khz(vcpu);
do_div(ret, USEC_PER_SEC);
return ret;
}
@@ -1029,7 +1029,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
s64 sdiff;
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
- offset = data - native_read_tsc();
+ offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
ns = get_kernel_ns();
elapsed = ns - kvm->arch.last_tsc_nsec;
sdiff = data - kvm->arch.last_tsc_write;
@@ -1045,13 +1045,13 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
* In that case, for a reliable TSC, we can match TSC offsets,
* or make a best guest using elapsed value.
*/
- if (sdiff < nsec_to_cycles(5ULL * NSEC_PER_SEC) &&
+ if (sdiff < nsec_to_cycles(vcpu, 5ULL * NSEC_PER_SEC) &&
elapsed < 5ULL * NSEC_PER_SEC) {
if (!check_tsc_unstable()) {
offset = kvm->arch.last_tsc_offset;
pr_debug("kvm: matched tsc offset for %llu\n", data);
} else {
- u64 delta = nsec_to_cycles(elapsed);
+ u64 delta = nsec_to_cycles(vcpu, elapsed);
offset += delta;
pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
` (4 preceding siblings ...)
2011-03-24 7:40 ` [PATCH 5/6] KVM: X86: Delegate tsc-offset calculation to architecture code Joerg Roedel
@ 2011-03-24 7:40 ` Joerg Roedel
2011-03-24 10:14 ` Avi Kivity
5 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 7:40 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch implements two new vm-ioctls to get and set the
virtual_tsc_khz if the machine supports tsc-scaling. Setting
the tsc-frequency is only possible before userspace creates
any vcpu.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
Documentation/kvm/api.txt | 22 +++++++++++++++
arch/x86/include/asm/kvm_host.h | 7 +++++
arch/x86/kvm/svm.c | 15 ++++++++++
arch/x86/kvm/x86.c | 57 +++++++++++++++++++++++++++++++++++++++
include/linux/kvm.h | 5 +++
5 files changed, 106 insertions(+), 0 deletions(-)
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index 9bef4e4..e4e4a44 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -1263,6 +1263,28 @@ struct kvm_assigned_msix_entry {
__u16 padding[3];
};
+4.54 KVM_SET_TSC_KHZ
+
+Capability: KVM_CAP_TSC_CONTROL
+Architectures: x86
+Type: vm ioctl
+Parameters: __u32 (in)
+Returns: 0 on success, -1 on error
+
+Specifies the tsc frequency for the virtual machine. This IOCTL must be
+used before any vcpu is created. The unit of the frequency is KHz.
+
+4.55 KVM_GET_TSC_KHZ
+
+Capability: KVM_CAP_GET_TSC_KHZ
+Architectures: x86
+Type: vm ioctl
+Parameters: __u32 (out)
+Returns: 0 on success, -1 on error
+
+Returns the tsc frequency of the guest. The unit of the return value is
+KHz. If the host has unstable tsc this ioctl return an error.
+
5. The kvm_run structure
Application code obtains a pointer to the kvm_run structure by
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6fe1e84..5b96b76 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -632,6 +632,13 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
extern bool tdp_enabled;
+/* control of guest tsc rate supported? */
+extern bool kvm_has_tsc_control;
+/* minimum supported tsc_khz for guests */
+extern u32 kvm_min_guest_tsc_khz;
+/* maximum supported tsc_khz for guests */
+extern u32 kvm_max_guest_tsc_khz;
+
enum emulation_result {
EMULATE_DONE, /* no further processing */
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 32d444f..368577b 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -64,6 +64,8 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
#define TSC_RATIO_RSVD 0xffffff0000000000ULL
+#define TSC_RATIO_MIN 0x0000000000000001ULL
+#define TSC_RATIO_MAX 0x000000ffffffffffULL
static bool erratum_383_found __read_mostly;
@@ -198,6 +200,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm);
static int nested_svm_vmexit(struct vcpu_svm *svm);
static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
bool has_error_code, u32 error_code);
+static u64 __scale_tsc(u64 ratio, u64 tsc);
enum {
VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
@@ -799,6 +802,18 @@ static __init int svm_hardware_setup(void)
if (boot_cpu_has(X86_FEATURE_FXSR_OPT))
kvm_enable_efer_bits(EFER_FFXSR);
+ if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+ u64 min, max;
+
+ kvm_has_tsc_control = true;
+
+ min = max(1ULL, __scale_tsc(tsc_khz, TSC_RATIO_MIN));
+ max = min(0xffffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
+
+ kvm_min_guest_tsc_khz = min;
+ kvm_max_guest_tsc_khz = max;
+ }
+
if (nested) {
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7754079..416b016 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -100,6 +100,13 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops);
int ignore_msrs = 0;
module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
+bool kvm_has_tsc_control;
+EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
+u32 kvm_min_guest_tsc_khz;
+EXPORT_SYMBOL_GPL(kvm_min_guest_tsc_khz);
+u32 kvm_max_guest_tsc_khz;
+EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
+
#define KVM_NR_SHARED_MSRS 16
struct kvm_shared_msrs_global {
@@ -2000,6 +2007,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_X86_ROBUST_SINGLESTEP:
case KVM_CAP_XSAVE:
case KVM_CAP_ASYNC_PF:
+ case KVM_CAP_GET_TSC_KHZ:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -2026,6 +2034,9 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_XCRS:
r = cpu_has_xsave;
break;
+ case KVM_CAP_TSC_CONTROL:
+ r = kvm_has_tsc_control;
+ break;
default:
r = 0;
break;
@@ -3580,6 +3591,52 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_SET_TSC_KHZ: {
+ u32 user_tsc_khz;
+
+ if (!kvm_has_tsc_control)
+ break;
+
+ r = -EFAULT;
+ if (copy_from_user(&user_tsc_khz, argp, sizeof(__u32)))
+ goto out;
+
+ r = -EINVAL;
+ if (user_tsc_khz < kvm_min_guest_tsc_khz ||
+ user_tsc_khz > kvm_max_guest_tsc_khz)
+ goto out;
+
+ mutex_lock(&kvm->lock);
+ /*
+ * We force the tsc frequency to be set before any
+ * vcpu is created
+ */
+ if (atomic_read(&kvm->online_vcpus) > 0) {
+ mutex_unlock(&kvm->lock);
+ goto out;
+ }
+
+ kvm_arch_set_tsc_khz(kvm, user_tsc_khz);
+
+ mutex_unlock(&kvm->lock);
+
+ r = 0;
+ goto out;
+ }
+ case KVM_GET_TSC_KHZ: {
+ u32 vtsc_khz = kvm->arch.virtual_tsc_khz;
+
+ r = -EIO;
+ if (check_tsc_unstable())
+ goto out;
+
+ r = -EFAULT;
+ if (copy_to_user(argp, &vtsc_khz, sizeof(__u32)))
+ goto out;
+
+ r = 0;
+ goto out;
+ }
default:
;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index ea2dc1a..ea16c57 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -541,6 +541,8 @@ struct kvm_ppc_pvinfo {
#define KVM_CAP_PPC_GET_PVINFO 57
#define KVM_CAP_PPC_IRQ_LEVEL 58
#define KVM_CAP_ASYNC_PF 59
+#define KVM_CAP_TSC_CONTROL 60
+#define KVM_CAP_GET_TSC_KHZ 61
#ifdef KVM_CAP_IRQ_ROUTING
@@ -677,6 +679,9 @@ struct kvm_clock_data {
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
/* Available with KVM_CAP_PPC_GET_PVINFO */
#define KVM_PPC_GET_PVINFO _IOW(KVMIO, 0xa1, struct kvm_ppc_pvinfo)
+/* Available with KVM_CAP_TSC_CONTROL */
+#define KVM_SET_TSC_KHZ _IOW(KVMIO, 0xa2, __u32)
+#define KVM_GET_TSC_KHZ _IOR(KVMIO, 0xa2, __u32)
/*
* ioctls for vcpu fds
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR
2011-03-24 7:40 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
@ 2011-03-24 9:51 ` Avi Kivity
2011-03-24 9:58 ` Joerg Roedel
0 siblings, 1 reply; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 9:51 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 09:40 AM, Joerg Roedel wrote:
> This patch enhances the kvm_amd module with functions to
> support the TSC_RATE_MSR which can be used to set a given
> tsc frequency for the guest vcpu.
>
>
> @@ -1141,6 +1175,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>
> for (i = 0; i< NR_HOST_SAVE_USER_MSRS; i++)
> rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
> +
> + if (static_cpu_has(X86_FEATURE_TSCRATEMSR)&& svm->tsc_scale.enabled)
> + wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale.ratio);
> }
>
> static void svm_vcpu_put(struct kvm_vcpu *vcpu)
> @@ -1161,6 +1198,9 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
> #endif
> for (i = 0; i< NR_HOST_SAVE_USER_MSRS; i++)
> wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
> +
> + if (static_cpu_has(X86_FEATURE_TSCRATEMSR)&& svm->tsc_scale.enabled)
> + wrmsr(MSR_AMD64_TSC_RATIO, 0, 1);
> }
This is a bit suboptimal. We could do something like
static DEFINE_PER_CPU(u64, current_tsc_scale);
static void svm_vcpu_load(...)
{
...
if (svm->tsc_scale != __get_cpu_var(current_tsc_scale)) {
__get_cpu_var(current_tsc_scale) = svm->tsc_scale;
wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale);
}
}
with no changes to svm_vcpu_put() (note no tsc_scale.enabled either,
just put the unity value for disabled).
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency
2011-03-24 7:40 ` [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency Joerg Roedel
@ 2011-03-24 9:58 ` Avi Kivity
0 siblings, 0 replies; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 9:58 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 09:40 AM, Joerg Roedel wrote:
> This patch changes the kvm_guest_time_update function to use
> TSC frequency the guest actually has for updating its clock.
>
>
>
> + bool (*use_virtual_tsc_khz)(struct kvm_vcpu *vcpu);
Just put virtual_tsc_khz into vcpu->arch. If nonzero, consider it enabled.
(we could even set it if we have a constant_tsc; to the real tsc frequency).
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR
2011-03-24 9:51 ` Avi Kivity
@ 2011-03-24 9:58 ` Joerg Roedel
0 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 9:58 UTC (permalink / raw)
To: Avi Kivity; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On Thu, Mar 24, 2011 at 11:51:59AM +0200, Avi Kivity wrote:
> On 03/24/2011 09:40 AM, Joerg Roedel wrote:
>> This patch enhances the kvm_amd module with functions to
>> support the TSC_RATE_MSR which can be used to set a given
>> tsc frequency for the guest vcpu.
>>
>>
>> @@ -1141,6 +1175,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>>
>> for (i = 0; i< NR_HOST_SAVE_USER_MSRS; i++)
>> rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
>> +
>> + if (static_cpu_has(X86_FEATURE_TSCRATEMSR)&& svm->tsc_scale.enabled)
>> + wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale.ratio);
>> }
>>
>> static void svm_vcpu_put(struct kvm_vcpu *vcpu)
>> @@ -1161,6 +1198,9 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
>> #endif
>> for (i = 0; i< NR_HOST_SAVE_USER_MSRS; i++)
>> wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
>> +
>> + if (static_cpu_has(X86_FEATURE_TSCRATEMSR)&& svm->tsc_scale.enabled)
>> + wrmsr(MSR_AMD64_TSC_RATIO, 0, 1);
>> }
>
> This is a bit suboptimal. We could do something like
>
> static DEFINE_PER_CPU(u64, current_tsc_scale);
>
> static void svm_vcpu_load(...)
> {
> ...
> if (svm->tsc_scale != __get_cpu_var(current_tsc_scale)) {
> __get_cpu_var(current_tsc_scale) = svm->tsc_scale;
> wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_scale);
> }
> }
>
> with no changes to svm_vcpu_put() (note no tsc_scale.enabled either,
> just put the unity value for disabled).
Right, this is a good optimization. Thanks for the hint, I'll change it.
Regards,
Joerg
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init
2011-03-24 7:40 ` [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init Joerg Roedel
@ 2011-03-24 10:04 ` Avi Kivity
2011-03-24 10:21 ` Joerg Roedel
0 siblings, 1 reply; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 10:04 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 09:40 AM, Joerg Roedel wrote:
> This patch implements the propagation of the VM
> virtual_tsc_khz into each vcpu data-structure to enable the
> tsc-scaling feature.
> static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
> @@ -1093,6 +1123,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
> if (err)
> goto free_svm;
>
> + if (!svm_vcpu_init_tsc(kvm, svm))
> + goto uninit;
> +
Need to set err.
I'm not really happy about failing on vcpu creation. Prefer to fail
when setting the frequency.
Another issue is that we fail when the frequency is out of range, but
not when it's wierd enough so we lose a lot of accuracy. I guess it
won't matter in practice.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz
2011-03-24 7:40 ` [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz Joerg Roedel
@ 2011-03-24 10:14 ` Avi Kivity
2011-03-24 10:41 ` Joerg Roedel
0 siblings, 1 reply; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 10:14 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 09:40 AM, Joerg Roedel wrote:
> This patch implements two new vm-ioctls to get and set the
> virtual_tsc_khz if the machine supports tsc-scaling. Setting
> the tsc-frequency is only possible before userspace creates
> any vcpu.
>
>
> +4.54 KVM_SET_TSC_KHZ
> +
> +Capability: KVM_CAP_TSC_CONTROL
> +Architectures: x86
> +Type: vm ioctl
> +Parameters: __u32 (in)
> +Returns: 0 on success, -1 on error
> +
> +Specifies the tsc frequency for the virtual machine. This IOCTL must be
> +used before any vcpu is created. The unit of the frequency is KHz.
Should it not be a vcpu ioctl?
KVM_CAP_TSC_CONTROL depends on both kvm and the underlying cpu. I guess
it's okay.
Need to return an error if the frequency cannot be accommodated. In
theory we need to provide the range of supported frequencies, but we can
live without it (and it will be very difficult to provide if we take
accuracy into account).
> +
> +4.55 KVM_GET_TSC_KHZ
> +
> +Capability: KVM_CAP_GET_TSC_KHZ
> +Architectures: x86
> +Type: vm ioctl
> +Parameters: __u32 (out)
> +Returns: 0 on success, -1 on error
> +
> +Returns the tsc frequency of the guest. The unit of the return value is
> +KHz. If the host has unstable tsc this ioctl return an error.
Which error?
(it's important since this is an expected error, unlike most others)
> @@ -3580,6 +3591,52 @@ long kvm_arch_vm_ioctl(struct file *filp,
> r = 0;
> break;
> }
> + case KVM_SET_TSC_KHZ: {
> + u32 user_tsc_khz;
> +
> + if (!kvm_has_tsc_control)
> + break;
> +
> + r = -EFAULT;
> + if (copy_from_user(&user_tsc_khz, argp, sizeof(__u32)))
> + goto out;
Can just use the input value (arg) instead of copy_from_user().
> +
> + r = -EINVAL;
> + if (user_tsc_khz< kvm_min_guest_tsc_khz ||
> + user_tsc_khz> kvm_max_guest_tsc_khz)
<= and >= are probably safer.
> + goto out;
> +
> + mutex_lock(&kvm->lock);
> + /*
> + * We force the tsc frequency to be set before any
> + * vcpu is created
> + */
> + if (atomic_read(&kvm->online_vcpus)> 0) {
> + mutex_unlock(&kvm->lock);
> + goto out;
> + }
> +
> + kvm_arch_set_tsc_khz(kvm, user_tsc_khz);
> +
> + mutex_unlock(&kvm->lock);
Making these vcpu ioctls will remove the locking.
> +
> + r = 0;
> + goto out;
> + }
> + case KVM_GET_TSC_KHZ: {
> + u32 vtsc_khz = kvm->arch.virtual_tsc_khz;
> +
> + r = -EIO;
> + if (check_tsc_unstable())
> + goto out;
> +
> + r = -EFAULT;
> + if (copy_to_user(argp,&vtsc_khz, sizeof(__u32)))
> + goto out;
And an ordinary return here.
> +
> + r = 0;
> + goto out;
> + }
>
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init
2011-03-24 10:04 ` Avi Kivity
@ 2011-03-24 10:21 ` Joerg Roedel
2011-03-24 10:30 ` Avi Kivity
0 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 10:21 UTC (permalink / raw)
To: Avi Kivity; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On Thu, Mar 24, 2011 at 12:04:13PM +0200, Avi Kivity wrote:
> On 03/24/2011 09:40 AM, Joerg Roedel wrote:
>> This patch implements the propagation of the VM
>> virtual_tsc_khz into each vcpu data-structure to enable the
>> tsc-scaling feature.
>> static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
>> {
>> struct vcpu_svm *svm = to_svm(vcpu);
>> @@ -1093,6 +1123,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
>> if (err)
>> goto free_svm;
>>
>> + if (!svm_vcpu_init_tsc(kvm, svm))
>> + goto uninit;
>> +
>
> Need to set err.
>
> I'm not really happy about failing on vcpu creation. Prefer to fail
> when setting the frequency.
Yes, in theory this shouldn't happen anyway because wrong frequencies
are catched when setting them via the ioctl. This is just another check,
but it should probably be turned into a BUG_ON in svm_vcpu_init_tsc()
because it is a bug that userspace could set an invalid khz value.
Joerg
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init
2011-03-24 10:21 ` Joerg Roedel
@ 2011-03-24 10:30 ` Avi Kivity
0 siblings, 0 replies; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 10:30 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 12:21 PM, Joerg Roedel wrote:
> On Thu, Mar 24, 2011 at 12:04:13PM +0200, Avi Kivity wrote:
> > On 03/24/2011 09:40 AM, Joerg Roedel wrote:
> >> This patch implements the propagation of the VM
> >> virtual_tsc_khz into each vcpu data-structure to enable the
> >> tsc-scaling feature.
> >> static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
> >> {
> >> struct vcpu_svm *svm = to_svm(vcpu);
> >> @@ -1093,6 +1123,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
> >> if (err)
> >> goto free_svm;
> >>
> >> + if (!svm_vcpu_init_tsc(kvm, svm))
> >> + goto uninit;
> >> +
> >
> > Need to set err.
> >
> > I'm not really happy about failing on vcpu creation. Prefer to fail
> > when setting the frequency.
>
> Yes, in theory this shouldn't happen anyway because wrong frequencies
> are catched when setting them via the ioctl. This is just another check,
> but it should probably be turned into a BUG_ON in svm_vcpu_init_tsc()
> because it is a bug that userspace could set an invalid khz value.
Yes, I saw later. But BUG_ON() is too dangerous - if the checks don't
exactly match a malicious user could cause a DOS.
We can just avoid setting the scale and run with the host tsc frequency.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz
2011-03-24 10:14 ` Avi Kivity
@ 2011-03-24 10:41 ` Joerg Roedel
2011-03-24 10:44 ` Avi Kivity
0 siblings, 1 reply; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 10:41 UTC (permalink / raw)
To: Avi Kivity; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On Thu, Mar 24, 2011 at 12:14:36PM +0200, Avi Kivity wrote:
> On 03/24/2011 09:40 AM, Joerg Roedel wrote:
>> This patch implements two new vm-ioctls to get and set the
>> virtual_tsc_khz if the machine supports tsc-scaling. Setting
>> the tsc-frequency is only possible before userspace creates
>> any vcpu.
>>
>>
>> +4.54 KVM_SET_TSC_KHZ
>> +
>> +Capability: KVM_CAP_TSC_CONTROL
>> +Architectures: x86
>> +Type: vm ioctl
>> +Parameters: __u32 (in)
>> +Returns: 0 on success, -1 on error
>> +
>> +Specifies the tsc frequency for the virtual machine. This IOCTL must be
>> +used before any vcpu is created. The unit of the frequency is KHz.
>
> Should it not be a vcpu ioctl?
The idea was that a vm ioctl will make sure that all vcpus in one vm
have the same tsc frequency. With a vm ioctl we force this. So the tsc
fequency is basically a vm capability which is mirrored into each vcpu
data structure for performance reasons.
> Need to return an error if the frequency cannot be accommodated. In
> theory we need to provide the range of supported frequencies, but we can
> live without it (and it will be very difficult to provide if we take
> accuracy into account).
Yes, -EINVAL is reported if the frequency can not be accomodated. But
userspace can't find out the lower or upper bounds of the valid range.
>
>> +
>> +4.55 KVM_GET_TSC_KHZ
>> +
>> +Capability: KVM_CAP_GET_TSC_KHZ
>> +Architectures: x86
>> +Type: vm ioctl
>> +Parameters: __u32 (out)
>> +Returns: 0 on success, -1 on error
>> +
>> +Returns the tsc frequency of the guest. The unit of the return value is
>> +KHz. If the host has unstable tsc this ioctl return an error.
>
> Which error?
>
> (it's important since this is an expected error, unlike most others)
>
>> @@ -3580,6 +3591,52 @@ long kvm_arch_vm_ioctl(struct file *filp,
>> r = 0;
>> break;
>> }
>> + case KVM_SET_TSC_KHZ: {
>> + u32 user_tsc_khz;
>> +
>> + if (!kvm_has_tsc_control)
>> + break;
>> +
>> + r = -EFAULT;
>> + if (copy_from_user(&user_tsc_khz, argp, sizeof(__u32)))
>> + goto out;
>
> Can just use the input value (arg) instead of copy_from_user().
>
>> +
>> + r = -EINVAL;
>> + if (user_tsc_khz< kvm_min_guest_tsc_khz ||
>> + user_tsc_khz> kvm_max_guest_tsc_khz)
>
> <= and >= are probably safer.
Right, I'll change it.
>
>> + goto out;
>> +
>> + mutex_lock(&kvm->lock);
>> + /*
>> + * We force the tsc frequency to be set before any
>> + * vcpu is created
>> + */
>> + if (atomic_read(&kvm->online_vcpus)> 0) {
>> + mutex_unlock(&kvm->lock);
>> + goto out;
>> + }
>> +
>> + kvm_arch_set_tsc_khz(kvm, user_tsc_khz);
>> +
>> + mutex_unlock(&kvm->lock);
>
> Making these vcpu ioctls will remove the locking.
>
>> +
>> + r = 0;
>> + goto out;
>> + }
>> + case KVM_GET_TSC_KHZ: {
>> + u32 vtsc_khz = kvm->arch.virtual_tsc_khz;
>> +
>> + r = -EIO;
>> + if (check_tsc_unstable())
>> + goto out;
>> +
>> + r = -EFAULT;
>> + if (copy_to_user(argp,&vtsc_khz, sizeof(__u32)))
>> + goto out;
>
> And an ordinary return here.
Okay, I'll change that. But I would prefer to keep this as a vm ioctl. A
vcpu ioctl might be more flexible but I doubt anybody has a use-case for
different tsc_khz values in one VM.
Joerg
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz
2011-03-24 10:41 ` Joerg Roedel
@ 2011-03-24 10:44 ` Avi Kivity
2011-03-24 10:47 ` Joerg Roedel
0 siblings, 1 reply; 19+ messages in thread
From: Avi Kivity @ 2011-03-24 10:44 UTC (permalink / raw)
To: Joerg Roedel; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On 03/24/2011 12:41 PM, Joerg Roedel wrote:
> >>
> >> +4.54 KVM_SET_TSC_KHZ
> >> +
> >> +Capability: KVM_CAP_TSC_CONTROL
> >> +Architectures: x86
> >> +Type: vm ioctl
> >> +Parameters: __u32 (in)
> >> +Returns: 0 on success, -1 on error
> >> +
> >> +Specifies the tsc frequency for the virtual machine. This IOCTL must be
> >> +used before any vcpu is created. The unit of the frequency is KHz.
> >
> > Should it not be a vcpu ioctl?
>
> The idea was that a vm ioctl will make sure that all vcpus in one vm
> have the same tsc frequency. With a vm ioctl we force this. So the tsc
> fequency is basically a vm capability which is mirrored into each vcpu
> data structure for performance reasons.
>
Yes - it doesn't make sense to have each vcpu run with a different tsc.
But we do the same with cpuid, and since the tsc really is a per-cpu
thing, then if it simplifies the code I think it's okay to make
userspace call it per-cpu.
> >> +
> >> + r = 0;
> >> + goto out;
> >> + }
> >> + case KVM_GET_TSC_KHZ: {
> >> + u32 vtsc_khz = kvm->arch.virtual_tsc_khz;
> >> +
> >> + r = -EIO;
> >> + if (check_tsc_unstable())
> >> + goto out;
> >> +
> >> + r = -EFAULT;
> >> + if (copy_to_user(argp,&vtsc_khz, sizeof(__u32)))
> >> + goto out;
> >
> > And an ordinary return here.
>
> Okay, I'll change that. But I would prefer to keep this as a vm ioctl. A
> vcpu ioctl might be more flexible but I doubt anybody has a use-case for
> different tsc_khz values in one VM.
My motivation is simplification.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz
2011-03-24 10:44 ` Avi Kivity
@ 2011-03-24 10:47 ` Joerg Roedel
0 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-24 10:47 UTC (permalink / raw)
To: Avi Kivity; +Cc: Joerg Roedel, Marcelo Tosatti, Zachary Amsden, kvm
On Thu, Mar 24, 2011 at 12:44:59PM +0200, Avi Kivity wrote:
> On 03/24/2011 12:41 PM, Joerg Roedel wrote:
>> Okay, I'll change that. But I would prefer to keep this as a vm ioctl. A
>> vcpu ioctl might be more flexible but I doubt anybody has a use-case for
>> different tsc_khz values in one VM.
>
> My motivation is simplification.
Okay, so I'll change that too. Thanks for your feedback.
Joerg
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR
2011-03-25 8:44 [PATCH 0/6] TSC scaling support for KVM v3 Joerg Roedel
@ 2011-03-25 8:44 ` Joerg Roedel
0 siblings, 0 replies; 19+ messages in thread
From: Joerg Roedel @ 2011-03-25 8:44 UTC (permalink / raw)
To: Avi Kivity, Marcelo Tosatti; +Cc: Zachary Amsden, kvm, Joerg Roedel
This patch enhances the kvm_amd module with functions to
support the TSC_RATE_MSR which can be used to set a given
tsc frequency for the guest vcpu.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
arch/x86/include/asm/msr-index.h | 1 +
arch/x86/kvm/svm.c | 54 +++++++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 1 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index fd5a1f3..a7b3e40 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -114,6 +114,7 @@
complete list. */
#define MSR_AMD64_PATCH_LEVEL 0x0000008b
+#define MSR_AMD64_TSC_RATIO 0xc0000104
#define MSR_AMD64_NB_CFG 0xc001001f
#define MSR_AMD64_PATCH_LOADER 0xc0010020
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 2a19322..2ce734c 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -63,6 +63,8 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+#define TSC_RATIO_RSVD 0xffffff0000000000ULL
+
static bool erratum_383_found __read_mostly;
static const u32 host_save_user_msrs[] = {
@@ -144,8 +146,13 @@ struct vcpu_svm {
unsigned int3_injected;
unsigned long int3_rip;
u32 apf_reason;
+
+ u64 tsc_ratio;
};
+static DEFINE_PER_CPU(u64, current_tsc_ratio);
+#define TSC_RATIO_DEFAULT 0x0100000000ULL
+
#define MSR_INVALID 0xffffffffU
static struct svm_direct_access_msrs {
@@ -569,6 +576,10 @@ static int has_svm(void)
static void svm_hardware_disable(void *garbage)
{
+ /* Make sure we clean up behind us */
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR))
+ wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);
+
cpu_svm_disable();
}
@@ -610,6 +621,11 @@ static int svm_hardware_enable(void *garbage)
wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT);
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+ wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);
+ __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT;
+ }
+
svm_init_erratum_383();
return 0;
@@ -854,6 +870,32 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
+static u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+ u64 mult, frac, _tsc;
+
+ mult = ratio >> 32;
+ frac = ratio & ((1ULL << 32) - 1);
+
+ _tsc = tsc;
+ _tsc *= mult;
+ _tsc += (tsc >> 32) * frac;
+ _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
+
+ return _tsc;
+}
+
+static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 _tsc = tsc;
+
+ if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
+ _tsc = __scale_tsc(svm->tsc_ratio, tsc);
+
+ return _tsc;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1048,6 +1090,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
goto out;
}
+ svm->tsc_ratio = TSC_RATIO_DEFAULT;
+
err = kvm_vcpu_init(&svm->vcpu, kvm, id);
if (err)
goto free_svm;
@@ -1141,6 +1185,12 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) &&
+ svm->tsc_ratio != __get_cpu_var(current_tsc_ratio)) {
+ __get_cpu_var(current_tsc_ratio) = svm->tsc_ratio;
+ wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio);
+ }
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -2813,7 +2863,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
case MSR_IA32_TSC: {
struct vmcb *vmcb = get_host_vmcb(svm);
- *data = vmcb->control.tsc_offset + native_read_tsc();
+ *data = vmcb->control.tsc_offset +
+ svm_scale_tsc(vcpu, native_read_tsc());
+
break;
}
case MSR_STAR:
--
1.7.1
^ permalink raw reply related [flat|nested] 19+ messages in thread
end of thread, other threads:[~2011-03-25 8:45 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-24 7:40 [PATCH 0/6][RESEND] TSC scaling support for KVM v2 Joerg Roedel
2011-03-24 7:40 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
2011-03-24 9:51 ` Avi Kivity
2011-03-24 9:58 ` Joerg Roedel
2011-03-24 7:40 ` [PATCH 2/6] KVM: X86: Let kvm-clock report the right tsc frequency Joerg Roedel
2011-03-24 9:58 ` Avi Kivity
2011-03-24 7:40 ` [PATCH 3/6] KVM: X86: Make tsc_delta calculation a function of guest tsc Joerg Roedel
2011-03-24 7:40 ` [PATCH 4/6] KVM: SVM: Propagate requested TSC frequency on vcpu init Joerg Roedel
2011-03-24 10:04 ` Avi Kivity
2011-03-24 10:21 ` Joerg Roedel
2011-03-24 10:30 ` Avi Kivity
2011-03-24 7:40 ` [PATCH 5/6] KVM: X86: Delegate tsc-offset calculation to architecture code Joerg Roedel
2011-03-24 7:40 ` [PATCH 6/6] KVM: X86: Implement userspace interface to set virtual_tsc_khz Joerg Roedel
2011-03-24 10:14 ` Avi Kivity
2011-03-24 10:41 ` Joerg Roedel
2011-03-24 10:44 ` Avi Kivity
2011-03-24 10:47 ` Joerg Roedel
-- strict thread matches above, loose matches on Subject: below --
2011-03-25 8:44 [PATCH 0/6] TSC scaling support for KVM v3 Joerg Roedel
2011-03-25 8:44 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
2011-03-15 9:36 [PATCH 0/6] TSC scaling support for KVM v2 Joerg Roedel
2011-03-15 9:36 ` [PATCH 1/6] KVM: SVM: Implement infrastructure for TSC_RATE_MSR Joerg Roedel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).