From 3b8723b1855ceba7bc2687a5c60d57ccc337550f Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Wed, 29 Jun 2016 16:24:40 +0100 Subject: [PATCH] Set VM's time based on host's time exposed by Xen Sets the VM's time when XenIface starts and on resume from suspend. Uses the underlying host's time, accessed via Xen. Provide an option for the guest to treat Xen's time as UTC or the current timezone. This option adds 2 new brandable variables that specify a partial registry path and value in the VM that determines how the time offset is modified. These values are REG_TOOLS_PATH and REG_UTC_NAME which should be specified in the build environment if the values need to be different. Signed-off-by: Owen Smith Changed REG_TOOLS_PATH to REG_KEY_NAME, which now defaults to 'Windows PV Drivers' (that being the official XenProject sub-project name), and use hard coded 'HostTime' key name instead of brandable REG_UTC_NAME. If we have a brandable parent registry key, then we don't really need to brand the value names under it. Signed-off-by: Paul Durrant --- build.py | 6 ++ src/xenagent/service.cpp | 119 +++++++++++++++++++++++++++++++++++++++ src/xenagent/service.h | 4 ++ 3 files changed, 129 insertions(+) diff --git a/build.py b/build.py index f49374c..1d587fa 100755 --- a/build.py +++ b/build.py @@ -70,6 +70,9 @@ def make_header(): file.write('#define DAY_STR\t\t\t"' + str(now.day) + '"\n') file.write('\n') + file.write('#define REG_KEY_NAME\t\t\t"' + os.environ['REG_KEY_NAME'] + '"\n') + file.write('\n') + file.close() @@ -426,6 +429,9 @@ if __name__ == '__main__': if 'OBJECT_PREFIX' not in os.environ.keys(): os.environ['OBJECT_PREFIX'] = 'XenProject' + if 'REG_KEY_NAME' not in os.environ.keys(): + os.environ['REG_KEY_NAME'] = 'Windows PV Drivers' + os.environ['MAJOR_VERSION'] = '8' os.environ['MINOR_VERSION'] = '2' os.environ['MICRO_VERSION'] = '0' diff --git a/src/xenagent/service.cpp b/src/xenagent/service.cpp index 2520c2c..2633809 100644 --- a/src/xenagent/service.cpp +++ b/src/xenagent/service.cpp @@ -218,6 +218,8 @@ CXenAgent::~CXenAgent() // suspend m_device->SuspendRegister(m_evt_suspend, &m_ctxt_suspend); + + SetXenTime(); } } @@ -317,6 +319,121 @@ void CXenAgent::EventLog(DWORD evt) } } +bool CXenAgent::IsHostTimeUTC() +{ +#ifdef _WIN64 + // Check SOFTWARE\Wow6432Node\$(VENDOR_NAME_STR)\$(REG_KEY_NAME) $(REG_UTC_NAME) == UTC + if (RegCheckIsUTC("SOFTWARE\\Wow6432Node")) + return true; +#endif + // Check SOFTWARE\$(VENDOR_NAME_STR)\$(REG_KEY_NAME) $(REG_UTC_NAME) == UTC + if (RegCheckIsUTC("SOFTWARE")) + return true; + + return false; +} + +void CXenAgent::AdjustXenTimeToUTC(FILETIME* now) +{ + std::string vm; + if (!m_device->StoreRead("vm", vm)) + return; + + std::string offs; + if (!m_device->StoreRead(vm + "/rtc/timeoffset", offs)) + return; + + long offset = (long)atoi(offs.c_str()); + + ULARGE_INTEGER lnow; + lnow.LowPart = now->dwLowDateTime; + lnow.HighPart = now->dwHighDateTime; + + lnow.QuadPart -= ((LONGLONG)offset * 1000000); + + now->dwLowDateTime = lnow.LowPart; + now->dwHighDateTime = lnow.HighPart; +} + +bool CXenAgent::RegCheckIsUTC(const char* rootpath) +{ + HKEY key; + LRESULT lr; + std::string path; + bool match = false; + + path = rootpath; + path += "\\"; + path += VENDOR_NAME_STR; + path += "\\"; + path += REG_KEY_NAME; + + lr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_READ, &key); + if (lr != ERROR_SUCCESS) + goto fail1; + + long size = 32; + DWORD length; + char* buffer = NULL; + + do { + length = size; + if (buffer) + delete [] buffer; + + buffer = new char[size]; + if (buffer == NULL) + goto fail2; + + lr = RegQueryValueEx(key, "HostTime", NULL, NULL, (LPBYTE)buffer, &length); + size *= 2; + } while (lr == ERROR_MORE_DATA); + if (lr != ERROR_SUCCESS) + goto fail3; + + if (!_strnicoll("UTC", buffer, length)) + match = true; + +fail3: + delete [] buffer; +fail2: + RegCloseKey(key); +fail1: + + return match; +} + +void CXenAgent::SetXenTime() +{ + // Set VM's time to Xen's time (adjust for UTC settings of VM and guest) + FILETIME now = { 0 }; + if (!m_device->SharedInfoGetTime(&now)) + return; + + bool IsUTC = IsHostTimeUTC(); + if (IsUTC) + AdjustXenTimeToUTC(&now); + + SYSTEMTIME sys = { 0 }; + if (!FileTimeToSystemTime(&now, &sys)) + return; + + SYSTEMTIME cur = { 0 }; + GetLocalTime(&cur); + + CXenAgent::Log("Time Now = %d/%d/%d %d:%02d:%02d.%d\n", + cur.wYear, cur.wMonth, cur.wDay, + cur.wHour, cur.wMinute, cur.wSecond, cur.wMilliseconds); + CXenAgent::Log("New Time = %d/%d/%d %d:%02d:%02d.%d\n", + sys.wYear, sys.wMonth, sys.wDay, + sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds); + + if (IsUTC) + SetSystemTime(&sys); + else + SetLocalTime(&sys); +} + void CXenAgent::OnShutdown() { CCritSec crit(&m_crit); @@ -379,6 +496,8 @@ void CXenAgent::OnSuspend() EventLog(EVENT_XENUSER_UNSUSPENDED); m_device->StoreWrite("control/feature-shutdown", "1"); + + SetXenTime(); } void CXenAgent::SetServiceStatus(DWORD state, DWORD exit /*= 0*/, DWORD hint /*= 0*/) diff --git a/src/xenagent/service.h b/src/xenagent/service.h index 97bd158..978e51b 100644 --- a/src/xenagent/service.h +++ b/src/xenagent/service.h @@ -71,6 +71,10 @@ private: // service events private: // helpers void AcquireShutdownPrivilege(); void EventLog(DWORD evt); + bool IsHostTimeUTC(); + void AdjustXenTimeToUTC(FILETIME* time); + bool RegCheckIsUTC(const char* path); + void SetXenTime(); void OnShutdown(); void OnSuspend(); -- 2.39.5