[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH] Wallclock Time Calculation Checks Update Versions For Consistency
Checking the shared_info update versions is necessary to get a consistent set of values. The version is incremented once when the update starts, and then incremented again after the update has completed. To verify that a set of values obtained from shared_info is consistent, the version must not only look at equality of versions, but the version must also be even. Data can only be safely be captured within the version check loop. There is no need to use a hypercall to get the system time, since this is alredy captured in the shared_info struct. A cached version of the time since boot is stored in structures for each vcpu, but this has to be combined with the timestamp counter and some scaling factors to get the actual current time since boot. Clock synchronization can also occur, and the dom0 will ensure that the values in the shared_info and vcpu_time_info structs are kept current to reflect this. Signed-off-by: Eric Mackay <mackayem@xxxxxxxxxx> --- src/xenbus/shared_info.c | 65 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/xenbus/shared_info.c b/src/xenbus/shared_info.c index d6babcf..2666f76 100644 --- a/src/xenbus/shared_info.c +++ b/src/xenbus/shared_info.c @@ -329,6 +329,10 @@ SharedInfoEvtchnUnmask( return SharedInfoTestBit(&Shared->evtchn_pending[SelectorBit], PortBit); } +#ifndef BooleanFlagOn +#define BooleanFlagOn(F,SF) ((BOOLEAN)(((F) & (SF)) != 0)) +#endif + static LARGE_INTEGER SharedInfoGetTime( IN PINTERFACE Interface @@ -336,51 +340,80 @@ SharedInfoGetTime( { PXENBUS_SHARED_INFO_CONTEXT Context = Interface->Context; shared_info_t *Shared; - ULONG Version; + ULONG WcVersion; + ULONG TimeVersion; ULONGLONG Seconds; ULONGLONG NanoSeconds; + ULONGLONG Timestamp; + ULONGLONG Tsc; + ULONGLONG SystemTime; + ULONG TscSystemMul; + CHAR TscShift; LARGE_INTEGER Now; TIME_FIELDS Time; KIRQL Irql; - NTSTATUS status; // Make sure we don't suspend - KeRaiseIrql(DISPATCH_LEVEL, &Irql); + KeRaiseIrql(DISPATCH_LEVEL, &Irql); Shared = Context->Shared; + // Loop until we can read a consistent set of values from the same update do { - Version = Shared->wc_version; + WcVersion = Shared->wc_version; + TimeVersion = Shared->vcpu_info[0].time.version; KeMemoryBarrier(); + // Wallclock time at system time zero (guest boot or resume) Seconds = Shared->wc_sec; NanoSeconds = Shared->wc_nsec; + + // Cached time in nanoseconds since guest boot + SystemTime = Shared->vcpu_info[0].time.system_time; + + // Timestamp counter value when these time values were last updated + Timestamp = Shared->vcpu_info[0].time.tsc_timestamp; + + // Timestamp modifiers + TscShift = Shared->vcpu_info[0].time.tsc_shift; + TscSystemMul = Shared->vcpu_info[0].time.tsc_to_system_mul; KeMemoryBarrier(); - } while (Shared->wc_version != Version); - // Get the number of nanoseconds since boot - status = HvmGetTime(&Now); - if (!NT_SUCCESS(status)) - Now.QuadPart = Shared->vcpu_info[0].time.system_time; + // Version is incremented to indicate update in progress + // LSB of version is set if update in progress + // Version is incremented again once update has completed + } while (Shared->wc_version != WcVersion || + Shared->vcpu_info[0].time.version != TimeVersion || + BooleanFlagOn(WcVersion, 0x1) || + BooleanFlagOn(TimeVersion, 0x1)); + + // Read counter ticks + Tsc = ReadTimeStampCounter(); KeLowerIrql(Irql); - Trace("WALLCLOCK: Seconds = %llu NanoSeconds = %llu\n", + // Number of elapsed ticks since timestamp was captured + Tsc -= Timestamp; + + // Time in nanoseconds since boot + SystemTime += ((Tsc << TscShift) * TscSystemMul) >> 32; + + Trace("WALLCLOCK TIME AT BOOT: Seconds = %llu NanoSeconds = %llu\n", Seconds, NanoSeconds); - Trace("BOOT: Seconds = %llu NanoSeconds = %llu\n", - Now.QuadPart / 1000000000ull, - Now.QuadPart % 1000000000ull); + Trace("TIME SINCE BOOT: Seconds = %llu NanoSeconds = %llu\n", + SystemTime / 1000000000ull, + SystemTime % 1000000000ull); // Convert wallclock from Unix epoch (1970) to Windows epoch (1601) Seconds += 11644473600ull; // Add in time since host boot - Seconds += Now.QuadPart / 1000000000ull; - NanoSeconds += Now.QuadPart % 1000000000ull; + Seconds += SystemTime / 1000000000ull; + NanoSeconds += SystemTime % 1000000000ull; - // Converto to system time format + // Convert to system time format Now.QuadPart = (Seconds * 10000000ull) + (NanoSeconds / 100ull); RtlTimeToTimeFields(&Now, &Time); -- 2.10.1.windows.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |