commit 8bf6799b091978ac7c5ccac395c562842ede364a
Author: Laine Stump <laine@laine.org>
Date:   Tue Mar 30 13:55:27 2010 +0200

    Implement the qemu-kvm backend of clock timer elements
    
    Since the timers are defined to cover all possible config cases for
    several different hypervisors, many of these possibilities generate an
    error on qemu. Here is what is currently supported:
    
    RTC: If the -rtc commandline option is available, allow setting
    "clock=host"
         or "clock=vm" based on the rtc timer clock='host|guest' value. Also
         add "driftfix=slew" if the tickpolicy is 'catchup', or add nothing
    if
         tickpolicy is 'delay'. (Other tickpolicies will raise an error).
    
         If -rtc isn't available, but -rtc-td-hack is, add that option
         if the tickpolicy is 'catchup', add -rtc-td-hack, if it is 'delay'
         add nothing, and if it's anything else, raise an error.
    
    PIT: If -no-kvm-pit-reinjection is available, and tickpolicy is
         'delay', add that option. if tickpolicy is 'catchup', do
         nothing. Anything else --> raise an error.
    
         If -no-kvm-pit-reinjection *isn't* available, but -tdf is, when
         tickpolicy is 'catchup' add -tdf. If it's 'delay', do
         nothing. Anything else --> raise an error.
    
         If neither of those commandline options is available, and
         tickpolicy is anything other than 'delay' (or unspecified), raise
         an error.
    
    HPET: If -no-hpet flag is available and present='no', add -no-hpet.
          If -no-hpet is not available, and present='yes', raise an error.
          If present is unspecified, the default is to do whatever this
          particular qemu does by default, so don't raise an error.
    
    All other timer types are unsupported by QEMU, so they will raise an
    error.
    
    * src/qemu/qemu_conf.c: extend qemuBuildClockArgStr() to generate the
      command line arguments for the new options

Index: libvirt-0.7.6/src/qemu/qemu_conf.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_conf.c
+++ libvirt-0.7.6/src/qemu/qemu_conf.c
@@ -3001,6 +3001,36 @@ qemuBuildClockArgStr(virDomainClockDefPt
         goto error;
     }
 
+    /* Look for an 'rtc' timer element, and add in appropriate clock= and driftfix= */
+    int i;
+    for (i = 0; i < def->ntimers; i++) {
+        if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
+            if (def->timers[i]->wallclock == VIR_DOMAIN_TIMER_WALLCLOCK_HOST) {
+                virBufferAddLit(&buf, ",clock=host");
+            } else if (def->timers[i]->wallclock == VIR_DOMAIN_TIMER_WALLCLOCK_GUEST) {
+                virBufferAddLit(&buf, ",clock=vm");
+            }
+            switch (def->timers[i]->tickpolicy) {
+            case -1:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                /* This is the default - missed ticks delivered when
+                   next scheduled, at normal rate */
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+                /* deliver ticks at a faster rate until caught up */
+                virBufferAddLit(&buf, ",driftfix=slew");
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                qemudReportError(NULL, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported rtc timer tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
+                goto error;
+            }
+            break; /* no need to check other timers - there is only one rtc */
+        }
+    }
+
     if (virBufferError(&buf)) {
         virReportOOMError(NULL);
         goto error;
@@ -3473,6 +3503,105 @@ int qemudBuildCommandLine(virConnectPtr
         ADD_ENV_PAIR("TZ", def->clock.data.timezone);
     }
 
+    for (i = 0; i < def->clock.ntimers; i++) {
+        switch (def->clock.timers[i]->name) {
+        default:
+        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+        case VIR_DOMAIN_TIMER_NAME_TSC:
+            qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("unsupported timer type (name) '%s'"),
+                            virDomainTimerNameTypeToString(def->clock.timers[i]->name));
+            goto error;
+
+        case VIR_DOMAIN_TIMER_NAME_RTC:
+            /* This has already been taken care of (in qemuBuildClockArgStr)
+               if QEMUD_CMD_FLAG_RTC is set (mutually exclusive with
+               QEMUD_FLAG_RTC_TD_HACK) */
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC_TD_HACK) {
+                switch (def->clock.timers[i]->tickpolicy) {
+                case -1:
+                case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                    /* the default - do nothing */
+                    break;
+                case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+                    ADD_ARG_LIT("-rtc-td-hack");
+                    break;
+                case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+                case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                    qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                    _("unsupported rtc tickpolicy '%s'"),
+                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+                }
+            } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_RTC)
+                       && (def->clock.timers[i]->tickpolicy
+                           != VIR_DOMAIN_TIMER_TICKPOLICY_DELAY)
+                       && (def->clock.timers[i]->tickpolicy != -1)) {
+                /* a non-default rtc policy was given, but there is no
+                   way to implement it in this version of qemu */
+                qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported rtc tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+            }
+            break;
+
+        case VIR_DOMAIN_TIMER_NAME_PIT:
+            switch (def->clock.timers[i]->tickpolicy) {
+            case -1:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                /* delay is the default if we don't have kernel
+                   (-no-kvm-pit), otherwise, the default is catchup. */
+                if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_KVM_PIT)
+                    ADD_ARG_LIT("-no-kvm-pit-reinjection");
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+                if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_KVM_PIT) {
+                    /* do nothing - this is default for kvm-pit */
+                } else if (qemuCmdFlags & QEMUD_CMD_FLAG_TDF) {
+                    /* -tdf switches to 'catchup' with userspace pit. */
+                    ADD_ARG_LIT("-tdf");
+                } else {
+                    /* can't catchup if we have neither pit mode */
+                    qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                    _("unsupported pit tickpolicy '%s'"),
+                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                    goto error;
+                }
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                /* no way to support these modes for pit in qemu */
+                qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported pit tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+            }
+            break;
+
+        case VIR_DOMAIN_TIMER_NAME_HPET:
+            /* the only meaningful attribute for hpet is "present". If
+             * present is -1, that means it wasn't specified, and
+             * should be left at the default for the
+             * hypervisor. "default" when -no-hpet exists is "yes",
+             * and when -no-hpet doesn't exist is "no". "confusing"?
+             * "yes"! */
+
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_HPET) {
+                if (def->clock.timers[i]->present == 0)
+                    ADD_ARG_LIT("-no-hpet");
+            } else {
+                /* no hpet timer available. The only possible action
+                   is to raise an error if present="yes" */
+                if (def->clock.timers[i]->present == 1) {
+                    qemudReportError(conn, NULL, NULL, VIR_ERR_CONFIG_UNSUPPORTED,
+                                    "%s", _("pit timer is not supported"));
+                }
+            }
+            break;
+        }
+    }
+
     if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
         def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
         ADD_ARG_LIT("-no-reboot");
