Patchwork KVM: emulate lapic tsc deadline timer for guest

login
register
mail settings
Submitter Liu, Jinsong
Date Sept. 22, 2011, 8:55 a.m.
Message ID <BC00F5384FCFC9499AF06F92E8B78A9E262C8E2554@shsmsx502.ccr.corp.intel.com>
Download mbox | patch
Permalink /patch/115908/
State New
Headers show

Comments

Liu, Jinsong - Sept. 22, 2011, 8:55 a.m.
From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00 2001
From: Liu, Jinsong <jinsong.liu@intel.com>
Date: Thu, 22 Sep 2011 14:00:08 +0800
Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest

This patch emulate lapic tsc deadline timer for guest:
Enumerate tsc deadline timer capability by CPUID;
Enable tsc deadline timer mode by lapic MMIO;
Start tsc deadline timer by WRMSR;

Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
---
 arch/x86/include/asm/kvm_host.h |    2 +
 arch/x86/kvm/kvm_timer.h        |    2 +
 arch/x86/kvm/lapic.c            |  123 ++++++++++++++++++++++++++++++++-------
 arch/x86/kvm/lapic.h            |    3 +
 arch/x86/kvm/x86.c              |   16 +++++-
 5 files changed, 123 insertions(+), 23 deletions(-)
Marcelo Tosatti - Sept. 22, 2011, 2:48 p.m.
On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
> >From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00 2001
> From: Liu, Jinsong <jinsong.liu@intel.com>
> Date: Thu, 22 Sep 2011 14:00:08 +0800
> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest
> 
> This patch emulate lapic tsc deadline timer for guest:
> Enumerate tsc deadline timer capability by CPUID;
> Enable tsc deadline timer mode by lapic MMIO;
> Start tsc deadline timer by WRMSR;
> 
> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com>
> ---
>  arch/x86/include/asm/kvm_host.h |    2 +
>  arch/x86/kvm/kvm_timer.h        |    2 +
>  arch/x86/kvm/lapic.c            |  123 ++++++++++++++++++++++++++++++++-------
>  arch/x86/kvm/lapic.h            |    3 +
>  arch/x86/kvm/x86.c              |   16 +++++-
>  5 files changed, 123 insertions(+), 23 deletions(-)

Looks good, please rebase against branch master of

git://github.com/avikivity/kvm.git
Liu, Jinsong - Sept. 22, 2011, 3:22 p.m.
Marcelo Tosatti wrote:
> On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
>>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
>>> 2001 
>> From: Liu, Jinsong <jinsong.liu@intel.com>
>> Date: Thu, 22 Sep 2011 14:00:08 +0800
>> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest
>> 
>> This patch emulate lapic tsc deadline timer for guest:
>> Enumerate tsc deadline timer capability by CPUID;
>> Enable tsc deadline timer mode by lapic MMIO;
>> Start tsc deadline timer by WRMSR;
>> 
>> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
>>  arch/x86/include/asm/kvm_host.h |    2 +
>>  arch/x86/kvm/kvm_timer.h        |    2 +
>>  arch/x86/kvm/lapic.c            |  123
>>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h       
>>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
>>  5 files changed, 123 insertions(+), 23 deletions(-)
> 
> Looks good, please rebase against branch master of
> 
> git://github.com/avikivity/kvm.git

Thanks!

And, for qemu patch rebase, I guess below address, which one is right?
git://github.com/avikivity/qemu-kvm.git   or
git://github.com/avikivity/qemu.git
Marcelo Tosatti - Sept. 22, 2011, 9:31 p.m.
On Thu, Sep 22, 2011 at 11:22:02PM +0800, Liu, Jinsong wrote:
> Marcelo Tosatti wrote:
> > On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
> >>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
> >>> 2001 
> >> From: Liu, Jinsong <jinsong.liu@intel.com>
> >> Date: Thu, 22 Sep 2011 14:00:08 +0800
> >> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest
> >> 
> >> This patch emulate lapic tsc deadline timer for guest:
> >> Enumerate tsc deadline timer capability by CPUID;
> >> Enable tsc deadline timer mode by lapic MMIO;
> >> Start tsc deadline timer by WRMSR;
> >> 
> >> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
> >>  arch/x86/include/asm/kvm_host.h |    2 +
> >>  arch/x86/kvm/kvm_timer.h        |    2 +
> >>  arch/x86/kvm/lapic.c            |  123
> >>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h       
> >>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
> >>  5 files changed, 123 insertions(+), 23 deletions(-)
> > 
> > Looks good, please rebase against branch master of
> > 
> > git://github.com/avikivity/kvm.git
> 
> Thanks!
> 
> And, for qemu patch rebase, I guess below address, which one is right?
> git://github.com/avikivity/qemu-kvm.git   or
> git://github.com/avikivity/qemu.git

qemu.git.
Liu, Jinsong - Sept. 23, 2011, 8:25 a.m.
Marcelo Tosatti wrote:
> On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
>>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
>>> 2001 
>> From: Liu, Jinsong <jinsong.liu@intel.com>
>> Date: Thu, 22 Sep 2011 14:00:08 +0800
>> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest
>> 
>> This patch emulate lapic tsc deadline timer for guest:
>> Enumerate tsc deadline timer capability by CPUID;
>> Enable tsc deadline timer mode by lapic MMIO;
>> Start tsc deadline timer by WRMSR;
>> 
>> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
>>  arch/x86/include/asm/kvm_host.h |    2 +
>>  arch/x86/kvm/kvm_timer.h        |    2 +
>>  arch/x86/kvm/lapic.c            |  123
>>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h       
>>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
>>  5 files changed, 123 insertions(+), 23 deletions(-)
> 
> Looks good, please rebase against branch master of
> 
> git://github.com/avikivity/kvm.git

Rebased as attached.

Thanks,
Jinsong
Marcelo Tosatti - Sept. 23, 2011, 1:08 p.m.
On Fri, Sep 23, 2011 at 04:25:51PM +0800, Liu, Jinsong wrote:
> Marcelo Tosatti wrote:
> > On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
> >>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
> >>> 2001 
> >> From: Liu, Jinsong <jinsong.liu@intel.com>
> >> Date: Thu, 22 Sep 2011 14:00:08 +0800
> >> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for guest
> >> 
> >> This patch emulate lapic tsc deadline timer for guest:
> >> Enumerate tsc deadline timer capability by CPUID;
> >> Enable tsc deadline timer mode by lapic MMIO;
> >> Start tsc deadline timer by WRMSR;
> >> 
> >> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
> >>  arch/x86/include/asm/kvm_host.h |    2 +
> >>  arch/x86/kvm/kvm_timer.h        |    2 +
> >>  arch/x86/kvm/lapic.c            |  123
> >>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h       
> >>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
> >>  5 files changed, 123 insertions(+), 23 deletions(-)
> > 
> > Looks good, please rebase against branch master of
> > 
> > git://github.com/avikivity/kvm.git
> 
> Rebased as attached.
> 
> Thanks,
> Jinsong

Please write a simple test case to arm a lapic timer via wrmsr (see
https://github.com/avikivity/kvm-unit-tests).

Kernel patches have been applied, thanks.
Liu, Jinsong - Sept. 25, 2011, 2:47 p.m.
Marcelo Tosatti wrote:
> On Fri, Sep 23, 2011 at 04:25:51PM +0800, Liu, Jinsong wrote:
>> Marcelo Tosatti wrote:
>>> On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
>>>>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
>>>>> 2001
>>>> From: Liu, Jinsong <jinsong.liu@intel.com>
>>>> Date: Thu, 22 Sep 2011 14:00:08 +0800
>>>> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for
>>>> guest 
>>>> 
>>>> This patch emulate lapic tsc deadline timer for guest:
>>>> Enumerate tsc deadline timer capability by CPUID;
>>>> Enable tsc deadline timer mode by lapic MMIO;
>>>> Start tsc deadline timer by WRMSR;
>>>> 
>>>> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
>>>>  arch/x86/include/asm/kvm_host.h |    2 +
>>>>  arch/x86/kvm/kvm_timer.h        |    2 +
>>>>  arch/x86/kvm/lapic.c            |  123
>>>>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h
>>>>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
>>>>  5 files changed, 123 insertions(+), 23 deletions(-)
>>> 
>>> Looks good, please rebase against branch master of
>>> 
>>> git://github.com/avikivity/kvm.git
>> 
>> Rebased as attached.
>> 
>> Thanks,
>> Jinsong
> 
> Please write a simple test case to arm a lapic timer via wrmsr (see
> https://github.com/avikivity/kvm-unit-tests).
> 
> Kernel patches have been applied, thanks.

Marcelo,

I'm not quite clear the purpose and usage of test case of the kvm-unit-tests.
Can you give me some hint?

Thanks,
Jinsong
Marcelo Tosatti - Oct. 3, 2011, 4:36 p.m.
On Sun, Sep 25, 2011 at 10:47:46PM +0800, Liu, Jinsong wrote:
> Marcelo Tosatti wrote:
> > On Fri, Sep 23, 2011 at 04:25:51PM +0800, Liu, Jinsong wrote:
> >> Marcelo Tosatti wrote:
> >>> On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
> >>>>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17 00:00:00
> >>>>> 2001
> >>>> From: Liu, Jinsong <jinsong.liu@intel.com>
> >>>> Date: Thu, 22 Sep 2011 14:00:08 +0800
> >>>> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for
> >>>> guest 
> >>>> 
> >>>> This patch emulate lapic tsc deadline timer for guest:
> >>>> Enumerate tsc deadline timer capability by CPUID;
> >>>> Enable tsc deadline timer mode by lapic MMIO;
> >>>> Start tsc deadline timer by WRMSR;
> >>>> 
> >>>> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
> >>>>  arch/x86/include/asm/kvm_host.h |    2 +
> >>>>  arch/x86/kvm/kvm_timer.h        |    2 +
> >>>>  arch/x86/kvm/lapic.c            |  123
> >>>>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h
> >>>>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
> >>>>  5 files changed, 123 insertions(+), 23 deletions(-)
> >>> 
> >>> Looks good, please rebase against branch master of
> >>> 
> >>> git://github.com/avikivity/kvm.git
> >> 
> >> Rebased as attached.
> >> 
> >> Thanks,
> >> Jinsong
> > 
> > Please write a simple test case to arm a lapic timer via wrmsr (see
> > https://github.com/avikivity/kvm-unit-tests).
> > 
> > Kernel patches have been applied, thanks.
> 
> Marcelo,
> 
> I'm not quite clear the purpose and usage of test case of the kvm-unit-tests.
> Can you give me some hint?

The purpose is to add unit tests for new features (such as lapic
deadline timer). There are examples that make it relatively easy to
construct new test case (or modify existing ones to accomodate new
tests).

Please add a new test case for lapic deadline timer, thanks.
Liu, Jinsong - Oct. 5, 2011, 5:18 p.m.
Marcelo Tosatti wrote:
> On Sun, Sep 25, 2011 at 10:47:46PM +0800, Liu, Jinsong wrote:
>> Marcelo Tosatti wrote:
>>> On Fri, Sep 23, 2011 at 04:25:51PM +0800, Liu, Jinsong wrote:
>>>> Marcelo Tosatti wrote:
>>>>> On Thu, Sep 22, 2011 at 04:55:52PM +0800, Liu, Jinsong wrote:
>>>>>>> From 4d5b83aba40ce0d421add9a41a6c591a8590a32e Mon Sep 17
>>>>>>> 00:00:00 2001
>>>>>> From: Liu, Jinsong <jinsong.liu@intel.com>
>>>>>> Date: Thu, 22 Sep 2011 14:00:08 +0800
>>>>>> Subject: [PATCH 2/2] KVM: emulate lapic tsc deadline timer for
>>>>>> guest 
>>>>>> 
>>>>>> This patch emulate lapic tsc deadline timer for guest:
>>>>>> Enumerate tsc deadline timer capability by CPUID;
>>>>>> Enable tsc deadline timer mode by lapic MMIO;
>>>>>> Start tsc deadline timer by WRMSR;
>>>>>> 
>>>>>> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> ---
>>>>>>  arch/x86/include/asm/kvm_host.h |    2 +
>>>>>>  arch/x86/kvm/kvm_timer.h        |    2 +
>>>>>>  arch/x86/kvm/lapic.c            |  123
>>>>>>  ++++++++++++++++++++++++++++++++------- arch/x86/kvm/lapic.h
>>>>>>  |    3 + arch/x86/kvm/x86.c              |   16 +++++-
>>>>>>  5 files changed, 123 insertions(+), 23 deletions(-)
>>>>> 
>>>>> Looks good, please rebase against branch master of
>>>>> 
>>>>> git://github.com/avikivity/kvm.git
>>>> 
>>>> Rebased as attached.
>>>> 
>>>> Thanks,
>>>> Jinsong
>>> 
>>> Please write a simple test case to arm a lapic timer via wrmsr (see
>>> https://github.com/avikivity/kvm-unit-tests).
>>> 
>>> Kernel patches have been applied, thanks.
>> 
>> Marcelo,
>> 
>> I'm not quite clear the purpose and usage of test case of the
>> kvm-unit-tests. Can you give me some hint?
> 
> The purpose is to add unit tests for new features (such as lapic
> deadline timer). There are examples that make it relatively easy to
> construct new test case (or modify existing ones to accomodate new
> tests).
> 
> Please add a new test case for lapic deadline timer, thanks.


Thanks Marcelo. I will add the test case. Sorry for slow email reply because of holiday.

Regards,
Jinsong

Patch

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6ab4241..b9d4291 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -673,6 +673,8 @@  u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
 
 extern bool tdp_enabled;
 
+u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
+
 /* control of guest tsc rate supported? */
 extern bool kvm_has_tsc_control;
 /* minimum supported tsc_khz for guests */
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
index 64bc6ea..497dbaa 100644
--- a/arch/x86/kvm/kvm_timer.h
+++ b/arch/x86/kvm/kvm_timer.h
@@ -2,6 +2,8 @@ 
 struct kvm_timer {
 	struct hrtimer timer;
 	s64 period; 				/* unit: ns */
+	u32 timer_mode_mask;
+	u64 tscdeadline;
 	atomic_t pending;			/* accumulated triggered timers */
 	bool reinject;
 	struct kvm_timer_ops *t_ops;
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 57dcbd4..66b64b8 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -135,9 +135,23 @@  static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
 	return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
 }
 
+static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
+{
+	return ((apic_get_reg(apic, APIC_LVTT) &
+		apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT);
+}
+
 static inline int apic_lvtt_period(struct kvm_lapic *apic)
 {
-	return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
+	return ((apic_get_reg(apic, APIC_LVTT) &
+		apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC);
+}
+
+static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic)
+{
+	return ((apic_get_reg(apic, APIC_LVTT) &
+		apic->lapic_timer.timer_mode_mask) ==
+			APIC_LVT_TIMER_TSCDEADLINE);
 }
 
 static inline int apic_lvt_nmi_mode(u32 lvt_val)
@@ -166,7 +180,7 @@  static inline int apic_x2apic_mode(struct kvm_lapic *apic)
 }
 
 static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
-	LVT_MASK | APIC_LVT_TIMER_PERIODIC,	/* LVTT */
+	LVT_MASK ,      /* part LVTT mask, timer mode mask added at runtime */
 	LVT_MASK | APIC_MODE_MASK,	/* LVTTHMR */
 	LVT_MASK | APIC_MODE_MASK,	/* LVTPC */
 	LINT_MASK, LINT_MASK,	/* LVT0-1 */
@@ -570,6 +584,9 @@  static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
 		break;
 
 	case APIC_TMCCT:	/* Timer CCR */
+		if (apic_lvtt_tscdeadline(apic))
+			return 0;
+
 		val = apic_get_tmcct(apic);
 		break;
 
@@ -664,29 +681,32 @@  static void update_divide_count(struct kvm_lapic *apic)
 
 static void start_apic_timer(struct kvm_lapic *apic)
 {
-	ktime_t now = apic->lapic_timer.timer.base->get_time();
-
-	apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) *
-		    APIC_BUS_CYCLE_NS * apic->divide_count;
+	ktime_t now;
 	atomic_set(&apic->lapic_timer.pending, 0);
 
-	if (!apic->lapic_timer.period)
-		return;
-	/*
-	 * Do not allow the guest to program periodic timers with small
-	 * interval, since the hrtimers are not throttled by the host
-	 * scheduler.
-	 */
-	if (apic_lvtt_period(apic)) {
-		if (apic->lapic_timer.period < NSEC_PER_MSEC/2)
-			apic->lapic_timer.period = NSEC_PER_MSEC/2;
-	}
+	if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
+		/* lapic timer in oneshot or peroidic mode */
+		now = apic->lapic_timer.timer.base->get_time();
+		apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT)
+			    * APIC_BUS_CYCLE_NS * apic->divide_count;
+
+		if (!apic->lapic_timer.period)
+			return;
+		/*
+		 * Do not allow the guest to program periodic timers with small
+		 * interval, since the hrtimers are not throttled by the host
+		 * scheduler.
+		 */
+		if (apic_lvtt_period(apic)) {
+			if (apic->lapic_timer.period < NSEC_PER_MSEC/2)
+				apic->lapic_timer.period = NSEC_PER_MSEC/2;
+		}
 
-	hrtimer_start(&apic->lapic_timer.timer,
-		      ktime_add_ns(now, apic->lapic_timer.period),
-		      HRTIMER_MODE_ABS);
+		hrtimer_start(&apic->lapic_timer.timer,
+			      ktime_add_ns(now, apic->lapic_timer.period),
+			      HRTIMER_MODE_ABS);
 
-	apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+		apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
 			   PRIx64 ", "
 			   "timer initial count 0x%x, period %lldns, "
 			   "expire @ 0x%016" PRIx64 ".\n", __func__,
@@ -695,6 +715,29 @@  static void start_apic_timer(struct kvm_lapic *apic)
 			   apic->lapic_timer.period,
 			   ktime_to_ns(ktime_add_ns(now,
 					apic->lapic_timer.period)));
+	} else if (apic_lvtt_tscdeadline(apic)) {
+		/* lapic timer in tsc deadline mode */
+		u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
+		u64 ns = 0;
+		struct kvm_vcpu *vcpu = apic->vcpu;
+		unsigned long this_tsc_khz = vcpu_tsc_khz(vcpu);
+		unsigned long flags;
+
+		if (unlikely(!tscdeadline || !this_tsc_khz))
+			return;
+
+		local_irq_save(flags);
+
+		now = apic->lapic_timer.timer.base->get_time();
+		guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu);
+		if (likely(tscdeadline > guest_tsc))
+			ns = (tscdeadline - guest_tsc)
+				* 1000000L / this_tsc_khz;
+		hrtimer_start(&apic->lapic_timer.timer,
+			ktime_add_ns(now, ns), HRTIMER_MODE_ABS);
+
+		local_irq_restore(flags);
+	}
 }
 
 static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
@@ -782,7 +825,6 @@  static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
 	case APIC_LVT0:
 		apic_manage_nmi_watchdog(apic, val);
-	case APIC_LVTT:
 	case APIC_LVTTHMR:
 	case APIC_LVTPC:
 	case APIC_LVT1:
@@ -796,7 +838,22 @@  static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
 		break;
 
+	case APIC_LVTT:
+		if ((apic_get_reg(apic, APIC_LVTT) &
+		    apic->lapic_timer.timer_mode_mask) !=
+		   (val & apic->lapic_timer.timer_mode_mask))
+		       hrtimer_cancel(&apic->lapic_timer.timer);
+
+		if (!apic_sw_enabled(apic))
+		       val |= APIC_LVT_MASKED;
+		val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
+		apic_set_reg(apic, APIC_LVTT, val);
+		break;
+
 	case APIC_TMICT:
+		if (apic_lvtt_tscdeadline(apic))
+			break;
+
 		hrtimer_cancel(&apic->lapic_timer.timer);
 		apic_set_reg(apic, APIC_TMICT, val);
 		start_apic_timer(apic);
@@ -883,6 +940,28 @@  void kvm_free_lapic(struct kvm_vcpu *vcpu)
  *----------------------------------------------------------------------
  */
 
+u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
+{
+	struct kvm_lapic *apic = vcpu->arch.apic;
+
+	if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+		return 0;
+
+	return apic->lapic_timer.tscdeadline;
+}
+
+void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data)
+{
+	struct kvm_lapic *apic = vcpu->arch.apic;
+
+	if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+		return;
+
+	hrtimer_cancel(&apic->lapic_timer.timer);
+	apic->lapic_timer.tscdeadline = data;
+	start_apic_timer(apic);
+}
+
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 52c9e6b..10c6ee6 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -41,6 +41,9 @@  int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
 bool kvm_apic_present(struct kvm_vcpu *vcpu);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
+u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
+void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
+
 void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
 void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6b37f18..382c0b8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -610,6 +610,13 @@  static void update_cpuid(struct kvm_vcpu *vcpu)
 		if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE))
 			best->ecx |= bit(X86_FEATURE_OSXSAVE);
 	}
+
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+		best->function == 0x1) {
+		best->ecx |= bit(X86_FEATURE_TSC_DEADLINE_TIMER);
+		vcpu->arch.apic->lapic_timer.timer_mode_mask = (3 << 17);
+	} else
+		vcpu->arch.apic->lapic_timer.timer_mode_mask = (1 << 17);
 }
 
 int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -825,6 +832,7 @@  static u32 msrs_to_save[] = {
 static unsigned num_msrs_to_save;
 
 static u32 emulated_msrs[] = {
+	MSR_IA32_TSCDEADLINE,
 	MSR_IA32_MISC_ENABLE,
 	MSR_IA32_MCG_STATUS,
 	MSR_IA32_MCG_CTL,
@@ -1000,7 +1008,7 @@  static inline int kvm_tsc_changes_freq(void)
 	return ret;
 }
 
-static u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
+u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
 {
 	if (vcpu->arch.virtual_tsc_khz)
 		return vcpu->arch.virtual_tsc_khz;
@@ -1564,6 +1572,9 @@  int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		break;
 	case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
 		return kvm_x2apic_msr_write(vcpu, msr, data);
+	case MSR_IA32_TSCDEADLINE:
+		kvm_set_lapic_tscdeadline_msr(vcpu, data);
+		break;
 	case MSR_IA32_MISC_ENABLE:
 		vcpu->arch.ia32_misc_enable_msr = data;
 		break;
@@ -1893,6 +1904,9 @@  int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
 	case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
 		return kvm_x2apic_msr_read(vcpu, msr, pdata);
 		break;
+	case MSR_IA32_TSCDEADLINE:
+		data = kvm_get_lapic_tscdeadline_msr(vcpu);
+		break;
 	case MSR_IA32_MISC_ENABLE:
 		data = vcpu->arch.ia32_misc_enable_msr;
 		break;