qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] KVM: emulate lapic tsc deadline timer for hvm


From: Avi Kivity
Subject: Re: [Qemu-devel] [PATCH] KVM: emulate lapic tsc deadline timer for hvm
Date: Mon, 22 Aug 2011 12:18:49 +0300
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20110707 Thunderbird/5.0

On 08/17/2011 07:19 AM, Liu, Jinsong wrote:
 From a9670ddff84080c56183e2d678189e100f891174 Mon Sep 17 00:00:00 2001
From: Liu, Jinsong<address@hidden>
Date: Wed, 17 Aug 2011 11:36:28 +0800
Subject: [PATCH] KVM: emulate lapic tsc deadline timer for hvm

kvm doesn't have hvm.

This patch emulate lapic tsc deadline timer for hvm:
Enumerate tsc deadline timer capacibility by CPUID;
Enable tsc deadline timer mode by LAPIC MMIO;
Start tsc deadline timer by MSR;

diff --git a/arch/x86/include/asm/cpufeature.h 
b/arch/x86/include/asm/cpufeature.h
index 4258aac..28bcf48 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -120,6 +120,7 @@
  #define X86_FEATURE_X2APIC    (4*32+21) /* x2APIC */
  #define X86_FEATURE_MOVBE     (4*32+22) /* MOVBE instruction */
  #define X86_FEATURE_POPCNT      (4*32+23) /* POPCNT instruction */
+#define X86_FEATURE_TSC_DEADLINE_TIMER    (4*32+24) /* Tsc deadline timer */
  #define X86_FEATURE_AES               (4*32+25) /* AES instructions */
  #define X86_FEATURE_XSAVE     (4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV */
  #define X86_FEATURE_OSXSAVE   (4*32+27) /* "" XSAVE enabled in the OS */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 307e3cf..28f7128 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -635,6 +635,7 @@ struct kvm_x86_ops {
        int (*check_intercept)(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage);
+       u64 (*guest_to_host_tsc)(u64 guest_tsc);
  };

Please put this near the other tsc functions. Add a comment explaining what value is returned under nested virtualization.

Please add the svm callback implementation.


--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -229,6 +229,8 @@
  #define MSR_IA32_APICBASE_ENABLE      (1<<11)
  #define MSR_IA32_APICBASE_BASE                (0xfffff<<12)

+#define MSR_IA32_TSCDEADLINE           0x000006e0
+
  #define MSR_IA32_UCODE_WRITE          0x00000079
  #define MSR_IA32_UCODE_REV            0x0000008b

Need to add to msrs_to_save so live migration works.


@@ -665,28 +682,30 @@ 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;
        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;
-       }
+       /* lapic timer in oneshot or peroidic mode */
+       if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
+               apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT)
+                           * APIC_BUS_CYCLE_NS * apic->divide_count;

-       hrtimer_start(&apic->lapic_timer.timer,
-                     ktime_add_ns(now, apic->lapic_timer.period),
-                     HRTIMER_MODE_ABS);
+               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;
+               }

-       apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+               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"
                           PRIx64 ", "
                           "timer initial count 0x%x, period %lldns, "
                           "expire @ 0x%016" PRIx64 ".\n", __func__,
@@ -695,6 +714,26 @@ static void start_apic_timer(struct kvm_lapic *apic)
                           apic->lapic_timer.period,
                           ktime_to_ns(ktime_add_ns(now,
                                        apic->lapic_timer.period)));
+       }
+
+       /* lapic timer in tsc deadline mode */
+       if (apic_lvtt_tscdeadline(apic)) {

'else if' is slightly better, since it shows the reader the options are mutually exclusive.

+               u64 tsc_now, tsc_target, tsc_delta, nsec;
+
+               if (!apic->lapic_timer.tscdeadline)
+                       return;
+
+               tsc_target = kvm_x86_ops->
+                       guest_to_host_tsc(apic->lapic_timer.tscdeadline);
+               rdtscll(tsc_now);
+               tsc_delta = tsc_target - tsc_now;

This only works if we have a constant tsc, that's not true for large multiboard machines. Need to do this with irqs disabled as well (reading both 'now' and 'tsc_now' in the same critical section).

+               if (tsc_delta<  0)
+                       tsc_delta = 0;
+
+               nsec = tsc_delta * 1000000L / tsc_khz;
+               hrtimer_start(&apic->lapic_timer.timer,
+                       ktime_add_ns(now, nsec), HRTIMER_MODE_ABS);
+       }
  }

@@ -883,6 +936,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;

Why?

+
+       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);

Shouldn't the msr value be updated even if we're outside tsc-deadline mode?

+}
+


  /*
   * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
   * ioctl. In this case the call-back should update internal vmx state to make
@@ -6270,6 +6278,16 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
                        }
                }
        }
+
+       /*
+        * Emulate Intel lapic tsc deadline timer even if host not support it.
+        * Open CPUID.1.ECX[24] and use bit17/18 as timer mode mask.
+        */
+       best = kvm_find_cpuid_entry(vcpu, 1, 0);
+       if (best) {
+               best->ecx |= bit(X86_FEATURE_TSC_DEADLINE_TIMER);
+               vcpu->arch.apic->lapic_timer.timer_mode_mask = (3<<  17);
+       }
  }

Should be in common code; there is nothing vmx specific about it (although it is Intel specific at present).


--
error compiling committee.c: too many arguments to function




reply via email to

[Prev in Thread] Current Thread [Next in Thread]