xend: add support for tsc timer

Support native, emulate, and paravirt modes of tsc timer for
both PV and HVM domains.

bsc#1026236
Index: libvirt-1.2.5/src/xenxs/xen_sxpr.c
===================================================================
--- libvirt-1.2.5.orig/src/xenxs/xen_sxpr.c
+++ libvirt-1.2.5/src/xenxs/xen_sxpr.c
@@ -1172,6 +1172,7 @@ xenParseSxpr(const struct sexpr *root,
              const char *cpus, char *tty, int vncport)
 {
     const char *tmp;
+    const char *value;
     virDomainDefPtr def;
     int hvm = 0, vmlocaltime;
 
@@ -1303,7 +1304,7 @@ xenParseSxpr(const struct sexpr *root,
     /* 12aaf4a2486b (3.0.3) added a second low-priority 'localtime' setting */
     vmlocaltime = sexpr_int(root, "domain/localtime");
     if (hvm) {
-        const char *value = sexpr_node(root, "domain/image/hvm/localtime");
+        value = sexpr_node(root, "domain/image/hvm/localtime");
         if (value) {
             if (virStrToLong_i(value, NULL, 0, &vmlocaltime) < 0) {
                 virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1331,19 +1332,43 @@ xenParseSxpr(const struct sexpr *root,
         if (sexpr_lookup(root, "domain/image/hvm/hpet")) {
             virDomainTimerDefPtr timer;
 
-            if (VIR_ALLOC_N(def->clock.timers, 1) < 0 ||
+            if (VIR_EXPAND_N(def->clock.timers, def->clock.ntimers, 1) < 0 ||
                 VIR_ALLOC(timer) < 0)
                 goto error;
 
             timer->name = VIR_DOMAIN_TIMER_NAME_HPET;
             timer->present = sexpr_int(root, "domain/image/hvm/hpet");
             timer->tickpolicy = -1;
+            timer->mode = -1;
+            timer->track = -1;
 
-            def->clock.ntimers = 1;
-            def->clock.timers[0] = timer;
+            def->clock.timers[def->clock.ntimers - 1] = timer;
+        }
+
+        /* tsc timer for HVM */
+        if ((value = sexpr_node(root, "domain/image/hvm/tsc_mode"))) {
+            virDomainTimerDefPtr timer;
+
+            if (VIR_EXPAND_N(def->clock.timers, def->clock.ntimers, 1) < 0 ||
+                VIR_ALLOC(timer) < 0)
+                goto error;
+
+            timer->name = VIR_DOMAIN_TIMER_NAME_TSC;
+            timer->present = 1;
+            timer->tickpolicy = -1;
+            timer->mode = VIR_DOMAIN_TIMER_MODE_AUTO;
+            timer->track = -1;
+            if (STREQ(value, "1"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_EMULATE;
+            else if (STREQ(value, "2"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_NATIVE;
+            else if (STREQ(value, "3"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_PARAVIRT;
+
+            def->clock.timers[def->clock.ntimers - 1] = timer;
         }
     } else {
-        const char *value = sexpr_node(root, "domain/image/linux/localtime");
+        value = sexpr_node(root, "domain/image/linux/localtime");
         if (value) {
             if (virStrToLong_i(value, NULL, 0, &vmlocaltime) < 0) {
                 virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1357,8 +1382,32 @@ xenParseSxpr(const struct sexpr *root,
         else
             def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
         def->clock.data.utc_reset = true;
+
+        /* tsc timer for PV */
+        if ((value = sexpr_node(root, "domain/image/linux/tsc_mode"))) {
+            virDomainTimerDefPtr timer;
+
+            if (VIR_EXPAND_N(def->clock.timers, def->clock.ntimers, 1) < 0 ||
+                VIR_ALLOC(timer) < 0)
+                goto error;
+
+            timer->name = VIR_DOMAIN_TIMER_NAME_TSC;
+            timer->present = 1;
+            timer->tickpolicy = -1;
+            timer->mode = VIR_DOMAIN_TIMER_MODE_AUTO;
+            timer->track = -1;
+            if (STREQ(value, "1"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_EMULATE;
+            else if (STREQ(value, "2"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_NATIVE;
+            else if (STREQ(value, "3"))
+                timer->mode = VIR_DOMAIN_TIMER_MODE_PARAVIRT;
+
+            def->clock.timers[def->clock.ntimers - 1] = timer;
+        }
     } /* !hvm */
 
+
     if (sexpr_node_copy(root, hvm ?
                         "domain/image/hvm/device_model" :
                         "domain/image/linux/device_model",
@@ -2508,16 +2557,6 @@ xenFormatSxpr(virConnectPtr conn,
         if (def->emulator && (hvm || xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4))
             virBufferEscapeSexpr(&buf, "(device_model '%s')", def->emulator);
 
-        /* look for HPET in order to override the hypervisor/xend default */
-        for (i = 0; i < def->clock.ntimers; i++) {
-            if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_HPET &&
-                def->clock.timers[i]->present != -1) {
-                virBufferAsprintf(&buf, "(hpet %d)",
-                                  def->clock.timers[i]->present);
-                break;
-            }
-        }
-
         /* PV graphics for xen <= 3.0.4, or HVM graphics */
         if (hvm || (xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
             if ((def->ngraphics == 1) &&
@@ -2533,6 +2572,33 @@ xenFormatSxpr(virConnectPtr conn,
         }
     } /* os.bootloader */
 
+    /* look for HPET and TSC timers */
+    for (i = 0; i < def->clock.ntimers; i++) {
+        if (hvm) {
+            if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_HPET &&
+                def->clock.timers[i]->present != -1) {
+                virBufferAsprintf(&buf, "(hpet %d)",
+                                  def->clock.timers[i]->present);
+            }
+        }
+
+        if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_TSC) {
+            switch (def->clock.timers[i]->mode) {
+                case VIR_DOMAIN_TIMER_MODE_EMULATE:
+                    virBufferAddLit(&buf, "(tsc_mode 1)");
+                    break;
+                case VIR_DOMAIN_TIMER_MODE_NATIVE:
+                    virBufferAddLit(&buf, "(tsc_mode 2)");
+                    break;
+                case VIR_DOMAIN_TIMER_MODE_PARAVIRT:
+                    virBufferAddLit(&buf, "(tsc_mode 3)");
+                    break;
+                default:
+                    virBufferAddLit(&buf, "(tsc_mode 0)");
+                    break;
+            }
+        }
+    }
 
     if (xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
         /* <3.1: UTC and LOCALTIME */
