*
* First, even between identical hosts the actual frequency of the underlying
* counter will change within the tolerances of its specification (typically
- * ±50PPM, or 4 seconds a day). The frequency also varies over time on the
+ * ±50PPM, or 4 seconds a day). This frequency also varies over time on the
* same host, but can be tracked by NTP as it generally varies slowly. With
* live migration there is a step change in the frequency, with no warning.
*
* of 1 ms per second would effectively tweak the counter period by 1000PPM
* at the start/end of the smearing period, while a sinusoidal smear would
* basically be impossible to represent.
+ *
+ * This structure is offered with the intent that it be adopted into the
+ * nascent virtio-rtc standard, as a virtio-rtc that does not address the live
+ * migration problem seems a little less than fit for purpose. For that
+ * reason, certain fields use precisely the same numeric definitions as in
+ * the virtio-rtc proposal. The structure can also be exposed through an ACPI
+ * device with the CID "VMCLOCK", modelled on the "VMGENID" device except for
+ * the fact that it uses a real _CRS to convey the address of the structure
+ * (which should be a full page, to allow for mapping directly to userspace).
*/
#ifndef __VMCLOCK_ABI_H__
#endif
struct vmclock_abi {
+ /* CONSTANT FIELDS */
uint32_t magic;
#define VMCLOCK_MAGIC 0x4b4c4356 /* "VCLK" */
- uint16_t size; /* Size of page containing this structure */
+ uint32_t size; /* Size of region containing this structure */
uint16_t version; /* 1 */
-
- /* Sequence lock. Low bit means an update is in progress. */
- uint32_t seq_count;
-
- uint32_t flags;
+ uint8_t counter_id; /* Matches VIRTIO_RTC_COUNTER_xxx except INVALID */
+#define VMCLOCK_COUNTER_ARM_VCNT 0
+#define VMCLOCK_COUNTER_X86_TSC 1
+#define VMCLOCK_COUNTER_INVALID 0xff
+ uint8_t time_type; /* Matches VIRTIO_RTC_TYPE_xxx */
+#define VMCLOCK_TIME_UTC 0 /* Since 1970-01-01 00:00:00z */
+#define VMCLOCK_TIME_TAI 1 /* Since 1970-01-01 00:00:00z */
+#define VMCLOCK_TIME_MONOTONIC 2 /* Since undefined epoch */
+#define VMCLOCK_TIME_INVALID_SMEARED 3 /* Not supported */
+#define VMCLOCK_TIME_INVALID_MAYBE_SMEARED 4 /* Not supported */
+
+ /* NON-CONSTANT FIELDS PROTECTED BY SEQCOUNT LOCK */
+ uint32_t seq_count; /* Low bit means an update is in progress */
+ /*
+ * This field changes to another non-repeating value when the CPU
+ * counter is disrupted, for example on live migration. This lets
+ * the guest know that it should discard any calibration it has
+ * performed of the counter against external sources (NTP/PTP/etc.).
+ */
+ uint64_t disruption_marker;
+ uint64_t flags;
/* Indicates that the tai_offset_sec field is valid */
#define VMCLOCK_FLAG_TAI_OFFSET_VALID (1 << 0)
/*
* Optionally used to notify guests of pending maintenance events.
- * A guest may wish to remove itself from service if an event is
- * coming up. Two flags indicate the rough imminence of the event.
+ * A guest which provides latency-sensitive services may wish to
+ * remove itself from service if an event is coming up. Two flags
+ * indicate the approximate imminence of the event.
*/
#define VMCLOCK_FLAG_DISRUPTION_SOON (1 << 1) /* About a day */
#define VMCLOCK_FLAG_DISRUPTION_IMMINENT (1 << 2) /* About an hour */
- /* Indicates that the utc_time_maxerror_picosec field is valid */
-#define VMCLOCK_FLAG_UTC_MAXERROR_VALID (1 << 3)
- /* Indicates counter_period_error_rate_frac_sec is valid */
-#define VMCLOCK_FLAG_PERIOD_ERROR_VALID (1 << 4)
-
+#define VMCLOCK_FLAG_PERIOD_ESTERROR_VALID (1 << 3)
+#define VMCLOCK_FLAG_PERIOD_MAXERROR_VALID (1 << 4)
+#define VMCLOCK_FLAG_TIME_ESTERROR_VALID (1 << 5)
+#define VMCLOCK_FLAG_TIME_MAXERROR_VALID (1 << 6)
/*
- * This field changes to another non-repeating value when the CPU
- * counter is disrupted, for example on live migration. This lets
- * the guest know that it should discard any calibration it has
- * performed of the counter against external sources (NTP/PTP/etc.).
+ * Even regardless of leap seconds, the time presented through this
+ * mechanism may not be strictly monotonic. If the counter slows down
+ * and the host adapts to this discovery, the time calculated from
+ * the value of the counter immediately after an update to this
+ * structure, may appear to be *earlier* than a calculation just
+ * before the update (while the counter was believed to be running
+ * faster than it now is). A guest operating system will typically
+ * *skew* its own system clock back towards the reference clock
+ * exposed here, rather than following this clock directly. If,
+ * however, this structure is being populated from such a system
+ * clock which is already handled in such a fashion and the results
+ * *are* guaranteed to be monotonic, such monotonicity can be
+ * advertised by setting this bit.
*/
- uint64_t disruption_marker;
+#define VMCLOCK_FLAG_TIME_MONOTONIC (1 << 7)
+ uint8_t pad[2];
uint8_t clock_status;
#define VMCLOCK_STATUS_UNKNOWN 0
#define VMCLOCK_STATUS_INITIALIZING 1
#define VMCLOCK_STATUS_FREERUNNING 3
#define VMCLOCK_STATUS_UNRELIABLE 4
- uint8_t counter_id; /* VIRTIO_RTC_COUNTER_xxx */
-#define VMCLOCK_COUNTER_ARM_VCNT 0
-#define VMCLOCK_COUNTER_X86_TSC 1
-#define VMCLOCK_COUNTER_X86_ART 2
-#define VMCLOCK_COUNTER_INVALID 0xff
-
/*
- * By providing the offset from UTC to TAI, the guest can know both
- * UTC and TAI reliably, whichever is indicated in the time_type
- * field. Valid if VMCLOCK_FLAG_TAI_OFFSET_VALID is set in flags.
+ * The time exposed through this device is never smeared. This field
+ * corresponds to the 'subtype' field in virtio-rtc, which indicates
+ * the smearing method. However in this case it provides a *hint* to
+ * the guest operating system, such that *if* the guest OS wants to
+ * provide its users with an alternative clock which does not follow
+ * the POSIX CLOCK_REALTIME standard, it may do so in a fashion
+ * consistent with the other systems in the nearby environment.
*/
+ uint8_t leap_second_smearing_hint; /* Matches VIRTIO_RTC_SUBTYPE_xxx */
+#define VMCLOCK_SMEARING_STRICT 0
+#define VMCLOCK_SMEARING_NOON_LINEAR 1
+#define VMCLOCK_SMEARING_UTC_SLS 2
int16_t tai_offset_sec;
-
- /*
- * The time exposed through this device is never smeaared; if it
- * claims to be VMCLOCK_TIME_UTC then it MUST be UTC. This field
- * provides a hint to the guest operating system, such that *if*
- * the guest OS wants to provide its users with an alternative
- * clock which does not follow the POSIX CLOCK_REALTIME standard,
- * it may do so in a fashion consistent with the other systems
- * in the nearby environment.
- */
- uint8_t leap_second_smearing_hint; /* Not quite VIRTIO_RTC_SUBTYPE_xxx */
- /* Provide true UTC to users, unsmeared. */;
-#define VMCLOCK_SMEARING_NONE 0
- /*
- * https://aws.amazon.com/blogs/aws/look-before-you-leap-the-coming-leap-second-and-aws/
- * https://developers.google.com/time/smear
- *
- * From noon on the day before to noon on the day after, smear the
- * clock by a linear 1/86400s per second.
- */
-#define VMCLOCK_SMEARING_NOON_LINEAR 2
- /*
- * draft-kuhn-leapsecond-00
- * For the 1000s leading up to the leap second, smear the clock by
- * clock by a linear 1ms per second.
- */
-#define VMCLOCK_SMEARING_UTC_SLS 4
-
+ uint8_t leap_indicator; /* Based on VIRTIO_RTC_LEAP_xxx */
+#define VMCLOCK_LEAP_NONE 0 /* No known nearby leap second */
+#define VMCLOCK_LEAP_PRE_POS 1 /* Leap second + at end of month */
+#define VMCLOCK_LEAP_PRE_NEG 2 /* Leap second - at end of month */
+#define VMCLOCK_LEAP_POS 3 /* Set during 23:59:60 second */
+#define VMCLOCK_LEAP_NEG 4 /* Not used in VMCLOCK */
/*
- * What time is exposed in the time_sec/time_frac_sec fields?
+ * These values are not (yet) in virtio-rtc. They indicate that a
+ * leap second *has* occurred at the start of the month. This allows
+ * a guest to generate a smeared clock from the accurate clock which
+ * this device provides, as smearing may need to continue for up to a
+ * period of time *after* the point of the leap second itself. Must
+ * be cleared by the 15th day of the month.
*/
- uint8_t time_type; /* VIRTIO_RTC_TYPE_xxx */
-#define VMCLOCK_TIME_UTC 0 /* Since 1970-01-01 00:00:00z */
-#define VMCLOCK_TIME_TAI 1 /* Since 1970-01-01 00:00:00z */
-#define VMCLOCK_TIME_MONOTONIC 2 /* Since undefined epoch */
-#define VMCLOCK_TIME_SMEARED_INVALID 3 /* UTC but with smeared leap seconds */
+#define VMCLOCK_LEAP_POST_POS 5
+#define VMCLOCK_LEAP_POST_NEG 6
/* Bit shift for counter_period_frac_sec and its error rate */
uint8_t counter_period_shift;
-
- /*
- * Unlike in NTP, this can indicate a leap second in the past. This
- * is needed to allow guests to derive an imprecise clock with
- * smeared leap seconds for themselves, as some modes of smearing
- * need the adjustments to continue even after the moment at which
- * the leap second should have occurred.
- */
- int8_t leapsecond_direction;
- uint64_t leapsecond_tai_sec; /* Since 1970-01-01 00:00:00z */
-
/*
* Paired values of counter and UTC at a given point in time.
*/
uint64_t counter_value;
- uint64_t time_sec;
- uint64_t time_frac_sec;
-
/*
* Counter frequency, and error margin. The unit of these fields is
* seconds >> (64 + counter_period_shift)
*/
uint64_t counter_period_frac_sec;
- uint64_t counter_period_error_rate_frac_sec;
+ uint64_t counter_period_esterror_rate_frac_sec;
+ uint64_t counter_period_maxerror_rate_frac_sec;
- /* Error margin of UTC reading above (± picoseconds) */
- uint64_t utc_time_maxerror_picosec;
+ /*
+ * Time according to time_type field above.
+ */
+ uint64_t time_sec; /* Seconds since time_type epoch */
+ uint64_t time_frac_sec; /* (seconds >> 64) */
+ uint64_t time_esterror_picosec; /* (± picoseconds) */
+ uint64_t time_maxerror_picosec; /* (± picoseconds) */
};
#endif /* __VMCLOCK_ABI_H__ */