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

[Xen-changelog] [xen-unstable] x86 hvm: Emulate MSR_IA32_TSC_DEADLINE



# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1292410919 0
# Node ID 255c074eca57e2b0964b666aecd744c06cfcdb87
# Parent  4e93a604dafef84b7fc0ee0c6d87b51810f6dccd
x86 hvm: Emulate MSR_IA32_TSC_DEADLINE

Accesses to MSR_IA32_TSC_DEADLINE are trapped, with value stored in a
new field vlapic->hw.tdt_msr. vlapic->pt is reused in one shot mode
for vtdt to trigger expire events.

For details, please refer to the Intel Architectures Software
Developer's Manual 3A, 10.5.4.1 TSC-Deadline Mode.

Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx>
---
 xen/arch/x86/hvm/hvm.c                 |    8 ++
 xen/arch/x86/hvm/vlapic.c              |  120 +++++++++++++++++++++++++++++++--
 xen/include/asm-x86/hvm/vlapic.h       |    2 
 xen/include/public/arch-x86/hvm/save.h |    1 
 4 files changed, 127 insertions(+), 4 deletions(-)

diff -r 4e93a604dafe -r 255c074eca57 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Dec 15 10:55:34 2010 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Wed Dec 15 11:01:59 2010 +0000
@@ -2235,6 +2235,10 @@ int hvm_msr_read_intercept(unsigned int 
             goto gp_fault;
         break;
 
+    case MSR_IA32_TSC_DEADLINE:
+        *msr_content = vlapic_tdt_msr_get(vcpu_vlapic(v));
+        break;
+
     case MSR_IA32_CR_PAT:
         *msr_content = v->arch.hvm_vcpu.pat_cr;
         break;
@@ -2340,6 +2344,10 @@ int hvm_msr_write_intercept(unsigned int
 
     case MSR_IA32_APICBASE:
         vlapic_msr_set(vcpu_vlapic(v), msr_content);
+        break;
+
+    case MSR_IA32_TSC_DEADLINE:
+        vlapic_tdt_msr_set(vcpu_vlapic(v), msr_content);
         break;
 
     case MSR_IA32_APICBASE_MSR ... MSR_IA32_APICBASE_MSR + 0x3ff:
diff -r 4e93a604dafe -r 255c074eca57 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Dec 15 10:55:34 2010 +0000
+++ b/xen/arch/x86/hvm/vlapic.c Wed Dec 15 11:01:59 2010 +0000
@@ -79,7 +79,16 @@ static unsigned int vlapic_lvt_mask[VLAP
     (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
 
 #define vlapic_lvtt_period(vlapic)                              \
-    (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_PERIODIC)
+    ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
+     == APIC_TIMER_MODE_PERIODIC)
+
+#define vlapic_lvtt_oneshot(vlapic)                             \
+    ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
+     == APIC_TIMER_MODE_ONESHOT)
+
+#define vlapic_lvtt_tdt(vlapic)                                 \
+    ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
+     == APIC_TIMER_MODE_TSC_DEADLINE)
 
 
 /*
@@ -481,9 +490,20 @@ static void vlapic_read_aligned(
         break;
 
     case APIC_TMCCT: /* Timer CCR */
+        if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
+        {
+            *result = 0;
+            break;
+        }
         *result = vlapic_get_tmcct(vlapic);
         break;
 
+    case APIC_TMICT: /* Timer ICR */
+        if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
+        {
+            *result = 0;
+            break;
+        }
     default:
         *result = vlapic_get_reg(vlapic, offset);
         break;
@@ -566,6 +586,12 @@ static void vlapic_pt_cb(struct vcpu *v,
     *(s_time_t *)data = hvm_get_guest_time(v);
 }
 
+static void vlapic_tdt_pt_cb(struct vcpu *v, void *data)
+{
+    *(s_time_t *)data = hvm_get_guest_time(v);
+    vcpu_vlapic(v)->hw.tdt_msr = 0;
+}
+
 static int vlapic_reg_write(struct vcpu *v,
                             unsigned int offset, unsigned long val)
 {
@@ -657,6 +683,14 @@ static int vlapic_reg_write(struct vcpu 
         break;
 
     case APIC_LVTT:         /* LVT Timer Reg */
+        if ( (vlapic_get_reg(vlapic, offset) & APIC_TIMER_MODE_MASK) !=
+             (val & APIC_TIMER_MODE_MASK) )
+        {
+            destroy_periodic_time(&vlapic->pt);
+            vlapic_set_reg(vlapic, APIC_TMICT, 0);
+            vlapic_set_reg(vlapic, APIC_TMCCT, 0);
+            vlapic->hw.tdt_msr = 0;
+        }
         vlapic->pt.irq = val & APIC_VECTOR_MASK;
     case APIC_LVTTHMR:      /* LVT Thermal Monitor */
     case APIC_LVTPC:        /* LVT Performance Counter */
@@ -680,6 +714,9 @@ static int vlapic_reg_write(struct vcpu 
     {
         uint64_t period;
 
+        if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
+            break;
+
         vlapic_set_reg(vlapic, APIC_TMICT, val);
         if ( val == 0 )
         {
@@ -842,6 +879,73 @@ void vlapic_msr_set(struct vlapic *vlapi
 
     HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
                 "apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr);
+}
+
+uint64_t  vlapic_tdt_msr_get(struct vlapic *vlapic)
+{
+    if ( !vlapic_lvtt_tdt(vlapic) )
+        return 0;
+
+    return vlapic->hw.tdt_msr;
+}
+
+void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value)
+{
+    uint64_t guest_tsc;
+    uint64_t guest_time;
+    struct vcpu *v = vlapic_vcpu(vlapic);
+
+    /* may need to exclude some other conditions like vlapic->hw.disabled */
+    if ( !vlapic_lvtt_tdt(vlapic) )
+    {
+        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "ignore tsc deadline msr write");
+        return;
+    }
+    
+    /* new_value = 0, >0 && <= now, > now */
+    guest_tsc = hvm_get_guest_tsc(v);
+    guest_time = hvm_get_guest_time(v);
+    if ( value > guest_tsc )
+    {
+        uint64_t delta = value - v->arch.hvm_vcpu.cache_tsc_offset;
+        delta = gtsc_to_gtime(v->domain, delta);
+        delta = max_t(s64, delta - guest_time, 0);
+
+        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "delta[0x%016"PRIx64"]", delta);
+
+        vlapic->hw.tdt_msr = value;
+        /* .... reprogram tdt timer */
+        create_periodic_time(v, &vlapic->pt, delta, 0,
+                             vlapic->pt.irq, vlapic_tdt_pt_cb,
+                             &vlapic->timer_last_update);
+        vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
+    }
+    else
+    {
+        vlapic->hw.tdt_msr = 0;
+
+        /* trigger a timer event if needed */
+        if ( value > 0 )
+        {
+            create_periodic_time(v, &vlapic->pt, 0, 0,
+                                 vlapic->pt.irq, vlapic_tdt_pt_cb,
+                                 &vlapic->timer_last_update);
+            vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
+        }
+        else
+        {
+            /* .... stop tdt timer */
+            destroy_periodic_time(&vlapic->pt);
+        }
+
+        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "value[0x%016"PRIx64"]", value);
+    }
+
+    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
+                "tdt_msr[0x%016"PRIx64"],"
+                " gtsc[0x%016"PRIx64"],"
+                " gtime[0x%016"PRIx64"]",
+                vlapic->hw.tdt_msr, guest_tsc, guest_time);
 }
 
 static int __vlapic_accept_pic_intr(struct vcpu *v)
@@ -959,10 +1063,18 @@ void vlapic_reset(struct vlapic *vlapic)
 /* rearm the actimer if needed, after a HVM restore */
 static void lapic_rearm(struct vlapic *s)
 {
-    unsigned long tmict = vlapic_get_reg(s, APIC_TMICT);
-    uint64_t period;
+    unsigned long tmict;
+    uint64_t period, tdt_msr;
 
     s->pt.irq = vlapic_get_reg(s, APIC_LVTT) & APIC_VECTOR_MASK;
+
+    if ( vlapic_lvtt_tdt(s) )
+    {
+        if ( (tdt_msr = vlapic_tdt_msr_get(s)) != 0 )
+            vlapic_tdt_msr_set(s, tdt_msr);
+        return;
+    }
+
     if ( (tmict = vlapic_get_reg(s, APIC_TMICT)) == 0 )
         return;
 
@@ -1023,7 +1135,7 @@ static int lapic_load_hidden(struct doma
     }
     s = vcpu_vlapic(v);
     
-    if ( hvm_load_entry(LAPIC, h, &s->hw) != 0 ) 
+    if ( hvm_load_entry_zeroextend(LAPIC, h, &s->hw) != 0 ) 
         return -EINVAL;
 
     vmx_vlapic_msr_changed(v);
diff -r 4e93a604dafe -r 255c074eca57 xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h  Wed Dec 15 10:55:34 2010 +0000
+++ b/xen/include/asm-x86/hvm/vlapic.h  Wed Dec 15 11:01:59 2010 +0000
@@ -92,6 +92,8 @@ void vlapic_reset(struct vlapic *vlapic)
 void vlapic_reset(struct vlapic *vlapic);
 
 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
+void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value);
+uint64_t vlapic_tdt_msr_get(struct vlapic *vlapic);
 
 int vlapic_accept_pic_intr(struct vcpu *v);
 
diff -r 4e93a604dafe -r 255c074eca57 xen/include/public/arch-x86/hvm/save.h
--- a/xen/include/public/arch-x86/hvm/save.h    Wed Dec 15 10:55:34 2010 +0000
+++ b/xen/include/public/arch-x86/hvm/save.h    Wed Dec 15 11:01:59 2010 +0000
@@ -265,6 +265,7 @@ struct hvm_hw_lapic {
     uint64_t             apic_base_msr;
     uint32_t             disabled; /* VLAPIC_xx_DISABLED */
     uint32_t             timer_divisor;
+    uint64_t             tdt_msr;
 };
 
 DECLARE_HVM_SAVE_TYPE(LAPIC, 5, struct hvm_hw_lapic);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.