On 3/24/22 10:48, Paolo Bonzini wrote: > Some versions of Windows hang on reboot if their TSC value is greater > than 2^54. The workaround is to reset the TSC to a small value. Add > to the domain configuration an attribute for this. It can be used > by QEMU and in principle also by ESXi, which has a property called > monitor_control.enable_softResetClearTSC as well. > > Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> > --- > docs/formatdomain.rst | 4 ++++ > src/conf/domain_conf.c | 22 ++++++++++++++++++++++ > src/conf/domain_conf.h | 10 ++++++++++ > src/conf/schemas/domaincommon.rng | 9 +++++++++ > 4 files changed, 45 insertions(+) > > diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst > index d188de4858..c9319e42ac 100644 > --- a/docs/formatdomain.rst > +++ b/docs/formatdomain.rst > @@ -2241,6 +2241,10 @@ Windows, however, expects it to be in so called 'localtime'. > ``frequency`` > The ``frequency`` attribute is an unsigned integer specifying the > frequency at which ``name="tsc"`` runs. > + ``on_reboot`` > + The ``on_reboot`` attribute controls how the ``name="tsc"`` timer behaves > + when the VM is reset, and can be "default", "clear" or "keep". The reset > + behavior of other timers is hardcoded, and depends on the type of timer. > ``mode`` > The ``mode`` attribute controls how the ``name="tsc"`` timer is managed, > and can be "auto", "native", "emulate", "paravirt", or "smpsafe". Other > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 153954a0b0..1893b8bbca 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -1217,6 +1217,13 @@ VIR_ENUM_IMPL(virDomainTimerMode, > "smpsafe", > ); > > +VIR_ENUM_IMPL(virDomainTimerRebootMode, > + VIR_DOMAIN_TIMER_REBOOT_MODE_LAST, > + "default", > + "keep", > + "clear", > +); > + > VIR_ENUM_IMPL(virDomainStartupPolicy, > VIR_DOMAIN_STARTUP_POLICY_LAST, > "default", > @@ -12022,6 +12029,7 @@ virDomainTimerDefParseXML(xmlNodePtr node, > g_autofree char *tickpolicy = NULL; > g_autofree char *track = NULL; > g_autofree char *mode = NULL; > + g_autofree char *reboot = NULL; > > def = g_new0(virDomainTimerDef, 1); > > @@ -12080,6 +12088,15 @@ virDomainTimerDefParseXML(xmlNodePtr node, > } > } > > + reboot = virXMLPropString(node, "on_reboot"); > + if (reboot != NULL) { > + if ((def->reboot = virDomainTimerRebootModeTypeFromString(reboot)) <= 0) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("unknown timer reboot mode '%s'"), reboot); > + goto error; > + } > + } I know you just mimicked what is done for @mode attribute, but we have this nice brand new virXMLPropEnum() which fits perfectly here as it encapsulates these lines. > + > catchup = virXPathNode("./catchup", ctxt); > if (catchup != NULL) { > ret = virXPathULong("string(./catchup/@threshold)", ctxt, > @@ -26151,6 +26168,11 @@ virDomainTimerDefFormat(virBuffer *buf, > virBufferAsprintf(&timerAttr, " mode='%s'", > virDomainTimerModeTypeToString(def->mode)); > } > + > + if (def->reboot) { > + virBufferAsprintf(&timerAttr, " on_reboot='%s'", > + virDomainTimerRebootModeTypeToString(def->mode)); > + } > } > > if (def->catchup.threshold > 0) > diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h > index b69abfa270..3618410f6c 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -2408,6 +2408,14 @@ typedef enum { > VIR_DOMAIN_TIMER_MODE_LAST > } virDomainTimerModeType; > > +typedef enum { > + VIR_DOMAIN_TIMER_REBOOT_MODE_DEFAULT = 0, > + VIR_DOMAIN_TIMER_REBOOT_MODE_KEEP, > + VIR_DOMAIN_TIMER_REBOOT_MODE_CLEAR, > + > + VIR_DOMAIN_TIMER_REBOOT_MODE_LAST > +} virDomainTimerRebootModeType; > + > typedef enum { > VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC = 0, > VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO, > @@ -2439,6 +2447,7 @@ struct _virDomainTimerDef { > /* frequency & mode are only valid for name='tsc' */ > unsigned long long frequency; /* in Hz, unspecified = 0 */ > int mode; /* enum virDomainTimerModeType */ > + int reboot; /* enum virDomainTimerRebootModeType */ This can be then the actual enum instead of int. > }; > > typedef enum { > @@ -4032,6 +4041,7 @@ VIR_ENUM_DECL(virDomainClockBasis); > VIR_ENUM_DECL(virDomainTimerName); > VIR_ENUM_DECL(virDomainTimerTrack); > VIR_ENUM_DECL(virDomainTimerTickpolicy); > +VIR_ENUM_DECL(virDomainTimerRebootMode); > VIR_ENUM_DECL(virDomainTimerMode); > VIR_ENUM_DECL(virDomainCpuPlacementMode); > > diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng > index 9c1b64a644..10d0404889 100644 > --- a/src/conf/schemas/domaincommon.rng > +++ b/src/conf/schemas/domaincommon.rng > @@ -1285,6 +1285,15 @@ > <ref name="unsignedLong"/> > </attribute> > </optional> > + <optional> > + <attribute name="on_reboot"> > + <choice> > + <value>default</value> And "default" is not accepted (because _DEFAULT = 0 and parser checks <= 0). > + <value>clear</value> > + <value>keep</value> > + </choice> > + </attribute> > + </optional> > <optional> > <attribute name="mode"> > <choice> Michal