hvm, x86: Allow virtual timer mode to be specified.
authorKeir Fraser <keir@xensource.com>
Fri, 26 Oct 2007 08:56:54 +0000 (09:56 +0100)
committerKeir Fraser <keir@xensource.com>
Fri, 26 Oct 2007 08:56:54 +0000 (09:56 +0100)
In HVM config file:
timer_mode=0 # Default: virtual time is delayed when timer ticks are
             # missed dur to preemption
timer_mode=1 # Virtual time always equals wall time, even while missed
             # ticks are pending

From: Haitao Shan <haitao.shan@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
12 files changed:
tools/python/xen/xend/XendConfig.py
tools/python/xen/xend/XendConstants.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xm/create.py
tools/python/xen/xm/xenapi_create.py
xen/arch/x86/domain.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vlapic.c
xen/arch/x86/hvm/vpt.c
xen/include/asm-x86/hvm/hvm.h
xen/include/asm-x86/hvm/vpt.h
xen/include/public/hvm/params.h

index 54b29ddc23715e3855ae40b8a21104747ee2f368..9debec185ef2afc555d9544ff12475cdb6427fc0 100644 (file)
@@ -127,7 +127,7 @@ XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display',
                         'fda', 'fdb', 'keymap', 'isa', 'localtime', 'monitor', 
                         'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl',
                         'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
-                        'vncconsole', 'vncdisplay', 'vnclisten',
+                        'vncconsole', 'vncdisplay', 'vnclisten', 'timer_mode',
                         'vncpasswd', 'vncunused', 'xauthority', 'pci', 'vhpt']
 
 # Xen API console 'other_config' keys.
index befabb4e16a08b5d53e2fea8060d663d96703ed9..ecf911c1415812648c853182fece4d06f6ba1b29 100644 (file)
@@ -46,6 +46,7 @@ HVM_PARAM_BUFIOREQ_PFN = 6
 HVM_PARAM_NVRAM_FD     = 7
 HVM_PARAM_VHPT_SIZE    = 8
 HVM_PARAM_BUFPIOREQ_PFN = 9
+HVM_PARAM_TIMER_MODE   = 10
 
 restart_modes = [
     "restart",
index d07926bb7de93cf11a4a91c0cea84dd56f3fe40c..d3a8623f6b8ba25e65bddcc970b9953d5e240a80 100644 (file)
@@ -1596,6 +1596,11 @@ class XendDomainInfo:
 
         self._recreateDom()
 
+        # Set timer configration of domain
+        if hvm:
+            xc.hvm_set_param(self.domid, HVM_PARAM_TIMER_MODE,
+                long(self.info["platform"].get("timer_mode")))
+
         # Set maximum number of vcpus in domain
         xc.domain_max_vcpus(self.domid, int(self.info['VCPUs_max']))
 
index b9bd16258d3c514a4edf37765fb899cf72a50425..b90e29d2862c7fc88fa1915dfdd15a53957f3964 100644 (file)
@@ -194,6 +194,11 @@ gopts.var('pae', val='PAE',
           fn=set_int, default=1,
           use="Disable or enable PAE of HVM domain.")
 
+gopts.var('timer_mode', val='TIMER_MODE',
+          fn=set_int, default=0,
+          use="""Timer mode (0=delay virtual time when ticks are missed;
+          1=virtual time is always wallclock time.""")
+
 gopts.var('acpi', val='ACPI',
           fn=set_int, default=1,
           use="Disable or enable ACPI of HVM domain.")
@@ -724,7 +729,7 @@ def configure_vifs(config_devs, vals):
 def configure_hvm(config_image, vals):
     """Create the config for HVM devices.
     """
-    args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb',
+    args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
              'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
              'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
              'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
index 8140ca35c56a7946ccedcaf086a00efd0efcad30..29ef6efb70876b9101cbbb5a30de297a1459356f 100644 (file)
@@ -818,7 +818,7 @@ class sxp2xml:
 
 
     def extract_platform(self, image, document):
-        platform_keys = ['acpi', 'apic', 'pae', 'vhpt']
+        platform_keys = ['acpi', 'apic', 'pae', 'vhpt', 'timer_mode']
 
         def extract_platform_key(key):
             platform = document.createElement("platform")
index 295ad771451e4cd70f967a1b955d1a8d42914ac4..e874ad7eb25c2b8cd7101bc6cd1fa59430574492 100644 (file)
@@ -1279,7 +1279,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
     local_irq_disable();
 
     if ( is_hvm_vcpu(prev) && !list_empty(&prev->arch.hvm_vcpu.tm_list) )
-        pt_freeze_time(prev);
+        pt_save_timer(prev);
 
     set_current(next);
 
index 908cd1c47f4590bfdebd033212bf059171862b65..84ede3fe82ccc4d9411c42fa9801a736514a4465 100644 (file)
@@ -89,17 +89,17 @@ void hvm_enable(struct hvm_function_table *fns)
     }
 }
 
-void hvm_set_guest_time(struct vcpu *v, u64 gtime)
+void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc)
 {
     u64 host_tsc;
 
     rdtscll(host_tsc);
 
-    v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
+    v->arch.hvm_vcpu.cache_tsc_offset = guest_tsc - host_tsc;
     hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
 }
 
-u64 hvm_get_guest_time(struct vcpu *v)
+u64 hvm_get_guest_tsc(struct vcpu *v)
 {
     u64 host_tsc;
 
@@ -121,7 +121,7 @@ void hvm_do_resume(struct vcpu *v)
     if ( !v->fpu_dirtied )
         hvm_funcs.stts(v);
 
-    pt_thaw_time(v);
+    pt_restore_timer(v);
 
     /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
     p = &get_ioreq(v)->vp_ioreq;
@@ -1843,6 +1843,12 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
                 hvm_set_callback_via(d, a.value);
                 hvm_latch_shinfo_size(d);
                 break;
+            case HVM_PARAM_TIMER_MODE:
+                rc = -EINVAL;
+                if ( (a.value != HVMPTM_delay_for_missed_ticks) &&
+                     (a.value != HVMPTM_no_delay_for_missed_ticks) )
+                    goto param_fail;
+                break;
             }
             d->arch.hvm_domain.params[a.index] = a.value;
             rc = 0;
index cc63c89df3e490610257ed0cc533472df8d541ae..fafc85f7c7cd42cd612ea4781fd94fef5d6afc31 100644 (file)
@@ -430,7 +430,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
     uint32_t tmcct, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
     uint64_t counter_passed;
 
-    counter_passed = (hvm_get_guest_time(v) - vlapic->pt.last_plt_gtime) // TSC
+    counter_passed = (hvm_get_guest_time(v) - vlapic->timer_last_update) // TSC
                      * 1000000000ULL / ticks_per_sec(v) // NS
                      / APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor;
     tmcct = tmict - counter_passed;
@@ -531,6 +531,11 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
     return 0;
 }
 
+void vlapic_pt_cb(struct vcpu *v, void *data)
+{
+    *(s_time_t *)data = hvm_get_guest_time(v);
+}
+
 static void vlapic_write(struct vcpu *v, unsigned long address,
                          unsigned long len, unsigned long val)
 {
@@ -660,7 +665,8 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
 
         vlapic_set_reg(vlapic, APIC_TMICT, val);
         create_periodic_time(current, &vlapic->pt, period, vlapic->pt.irq,
-                             !vlapic_lvtt_period(vlapic), NULL, vlapic);
+                             !vlapic_lvtt_period(vlapic), vlapic_pt_cb,
+                             &vlapic->timer_last_update);
 
         HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
                     "bus cycle is %uns, "
@@ -820,7 +826,8 @@ static void lapic_rearm(struct vlapic *s)
 
         s->pt.irq = lvtt & APIC_VECTOR_MASK;
         create_periodic_time(vlapic_vcpu(s), &s->pt, period, s->pt.irq,
-                             !vlapic_lvtt_period(s), NULL, s);
+                             !vlapic_lvtt_period(s), vlapic_pt_cb,
+                             &s->timer_last_update);
 
         printk("lapic_load to rearm the actimer:"
                     "bus cycle is %uns, "
index 743f19eaa0c76509b4941ffb56ac6d46478ce9d4..9ce899159468cb3bc09bed8b6a733a453ff4f053 100644 (file)
 #include <asm/hvm/vpt.h>
 #include <asm/event.h>
 
+static int pt_support_time_frozen(struct domain *d)
+{
+    return (d->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == 
+            HVMPTM_delay_for_missed_ticks);
+}
+
 static void pt_lock(struct periodic_time *pt)
 {
     struct vcpu *v;
@@ -67,7 +73,12 @@ static void missed_ticks(struct periodic_time *pt)
     pt->scheduled += missed_ticks * pt->period;
 }
 
-void pt_freeze_time(struct vcpu *v)
+static __inline__ void pt_freeze_time(struct vcpu *v)
+{
+    v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
+}
+
+void pt_save_timer(struct vcpu *v)
 {
     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
     struct periodic_time *pt;
@@ -77,33 +88,40 @@ void pt_freeze_time(struct vcpu *v)
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
-    v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
-
     list_for_each_entry ( pt, head, list )
         stop_timer(&pt->timer);
 
+    if ( pt_support_time_frozen(v->domain) )
+        pt_freeze_time(v);
+
     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
 }
 
-void pt_thaw_time(struct vcpu *v)
+static __inline__ void pt_thaw_time(struct vcpu *v)
+{
+    if ( v->arch.hvm_vcpu.guest_time )
+    {
+        hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
+        v->arch.hvm_vcpu.guest_time = 0;
+    }
+}
+
+void pt_restore_timer(struct vcpu *v)
 {
     struct list_head *head = &v->arch.hvm_vcpu.tm_list;
     struct periodic_time *pt;
 
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
-    if ( v->arch.hvm_vcpu.guest_time )
+    list_for_each_entry ( pt, head, list )
     {
-        hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
-        v->arch.hvm_vcpu.guest_time = 0;
-
-        list_for_each_entry ( pt, head, list )
-        {
-            missed_ticks(pt);
-            set_timer(&pt->timer, pt->scheduled);
-        }
+        missed_ticks(pt);
+        set_timer(&pt->timer, pt->scheduled);
     }
 
+    if ( pt_support_time_frozen(v->domain) )
+        pt_thaw_time(v);
+
     spin_unlock(&v->arch.hvm_vcpu.tm_lock);
 }
 
@@ -218,7 +236,8 @@ void pt_intr_post(struct vcpu *v, struct hvm_intack intack)
         pt->last_plt_gtime += pt->period_cycles;
     }
 
-    if ( hvm_get_guest_time(v) < pt->last_plt_gtime )
+    if ( pt_support_time_frozen(v->domain) &&
+            hvm_get_guest_time(v) < pt->last_plt_gtime )
         hvm_set_guest_time(v, pt->last_plt_gtime);
 
     cb = pt->cb;
index 52a59fc463bde2296e281e889a4dad9afbfa1d84..0a2983a850a7c6e75a0fb6a39fffd0d9ae5587ea 100644 (file)
@@ -175,8 +175,10 @@ void hvm_vcpu_reset(struct vcpu *vcpu);
 
 void hvm_send_assist_req(struct vcpu *v);
 
-void hvm_set_guest_time(struct vcpu *v, u64 gtime);
-u64 hvm_get_guest_time(struct vcpu *v);
+void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc);
+u64 hvm_get_guest_tsc(struct vcpu *v);
+#define hvm_set_guest_time(vcpu, gtime) hvm_set_guest_tsc(vcpu, gtime)
+#define hvm_get_guest_time(vcpu)        hvm_get_guest_tsc(vcpu)
 
 #define hvm_paging_enabled(v) \
     (!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG))
index 1327235c6cd943237cae9cfab46584790da6a2fb..4471fd990db3330da9a2f279fc904743399809b8 100644 (file)
@@ -133,8 +133,8 @@ struct pl_time {    /* platform time */
 
 #define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
 
-void pt_freeze_time(struct vcpu *v);
-void pt_thaw_time(struct vcpu *v);
+void pt_save_timer(struct vcpu *v);
+void pt_restore_timer(struct vcpu *v);
 void pt_update_irq(struct vcpu *v);
 void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
 void pt_reset(struct vcpu *v);
index 36dfdb2ee1889bbd5860830a5eafc41701cdb2e9..dbf2fb0b443ee64fbe2bd55afc62fb6bcc3d2345 100644 (file)
 #define HVM_PARAM_NVRAM_FD     7
 #define HVM_PARAM_VHPT_SIZE    8
 #define HVM_PARAM_BUFPIOREQ_PFN        9
-#define HVM_NR_PARAMS          10
-#else
-#define HVM_NR_PARAMS          7
 #endif
 
+/*
+ * Set mode for virtual timers (currently x86 only):
+ *  delay_for_missed_ticks (default):
+ *   Do not advance a vcpu's time beyond the correct delivery time for
+ *   interrupts that have been missed due to preemption. Deliver missed
+ *   interrupts when the vcpu is rescheduled and advance the vcpu's virtual
+ *   time stepwise for each one.
+ *  no_delay_for_missed_ticks:
+ *   As above, missed interrupts are delivered, but guest time always tracks
+ *   wallclock (i.e., real) time while doing so.
+ */
+#define HVM_PARAM_TIMER_MODE   10
+#define HVMPTM_delay_for_missed_ticks    0
+#define HVMPTM_no_delay_for_missed_ticks 1
+
+#define HVM_NR_PARAMS          11
+
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */