From: Ben Chalmers Date: Tue, 31 Dec 2013 11:13:15 +0000 (+0000) Subject: [CAR-1423] Port UTC hostime / timezone support to lite agent X-Git-Tag: 8.1.0-rc1~20^2~2 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=4f27f3c0744998558f83ed7da84f9b53f976a064;p=pvdrivers%2Fwin%2Fxeniface.git [CAR-1423] Port UTC hostime / timezone support to lite agent --- diff --git a/src/win32stubagent/XSAccessor.cpp b/src/win32stubagent/XSAccessor.cpp index da730ae..cdf1d4a 100644 --- a/src/win32stubagent/XSAccessor.cpp +++ b/src/win32stubagent/XSAccessor.cpp @@ -186,6 +186,21 @@ XenstoreRead(const char* path, char** value) return -1; } + +bool XenstoreReadDword(const char *path, DWORD *value) { + char* buffer; + size_t len; + len = XenstoreRead(path, &buffer); + if (len <= 0) { + return false; + } + *value = atoi(buffer); + + XsFree(buffer); + + return true; +} + void * XenstoreWatch(const char *path, HANDLE event, HANDLE errorevent) { diff --git a/src/win32stubagent/XSAccessor.h b/src/win32stubagent/XSAccessor.h index 64a6e63..2ed41b0 100644 --- a/src/win32stubagent/XSAccessor.h +++ b/src/win32stubagent/XSAccessor.h @@ -62,6 +62,7 @@ void XsLog(const char *fmt, ...); void XenstoreFree(void *tofree); void *XsAlloc(size_t size); void XsFree(const void *buf); +bool XenstoreReadDword(const char * path, DWORD *value); #if DBG diff --git a/src/win32stubagent/XService.cpp b/src/win32stubagent/XService.cpp index f15889e..d49d25b 100644 --- a/src/win32stubagent/XService.cpp +++ b/src/win32stubagent/XService.cpp @@ -137,6 +137,19 @@ static void FreeString(const char *string) free((void *)string); } +static char* PrintfString(const char *fmt, ...){ + va_list l; + va_start(l, fmt); + int numchars = _vscprintf(fmt, l); + char *outputstring = (char *)calloc(numchars + 1, sizeof(char)); + + if (outputstring == NULL) + return NULL; + + _vsnprintf(outputstring, numchars, fmt, l); + return outputstring; +} + static struct watch_event * EstablishWatch(const char *path, HANDLE errorevent) { @@ -518,21 +531,139 @@ out: return true; } -/* We need to resync the clock when we recover from suspend/resume. */ +static bool registryMatchString(HKEY hKey, + LPCTSTR lpValueName, + LPCTSTR comparestring, + bool matchcase) +{ + bool result = false; + LONG buffersize = sizeof(TCHAR)*256; + TCHAR *outstring = NULL; + DWORD outstringsize; + LONG status; + do { + outstringsize = buffersize; + outstring = (TCHAR *)realloc(outstring, outstringsize); + + status = RegQueryValueEx(hKey, + lpValueName, + NULL, + NULL, + (LPBYTE) outstring, + &outstringsize); + buffersize *= 2; + } while (status == ERROR_MORE_DATA); + + if (status == ERROR_FILE_NOT_FOUND) + goto done; + + if (matchcase) { + if (_tcsncmp(comparestring, outstring, outstringsize)) + goto done; + } + else { + if (_tcsnicoll(comparestring, outstring, outstringsize)) + goto done; + } + + result = true; + +done: + free(outstring); + + return result; +} + +static bool +adjustXenTimeToUTC(FILETIME *now) +{ + DWORD timeoffset; + char *vm; + char *rtckey; + ULARGE_INTEGER longoffset; + ULARGE_INTEGER longnow; + size_t vmlen; + + // XenTime is assumed to be in UTC, so we need to remove any + // offsets that are applied to it + + vmlen = XenstoreRead("vm", &vm); + if (vmlen <= 0) + goto fail_readvm; + + rtckey = PrintfString("%s/rtc/timeoffset", vm); + if (rtckey == NULL) + goto fail_rtckey; + + if (!XenstoreReadDword(rtckey, &timeoffset)) { + if (!XenstoreReadDword("platform/timeoffset", &timeoffset)) + goto fail_platformtimeoffset; + } + + //Convert offset from seconds to nanoseconds + longoffset.QuadPart = timeoffset; + longoffset.QuadPart = longoffset.QuadPart * 10000000; + + // Subtract nanosecond timeoffset from now + longnow.LowPart = now->dwLowDateTime; + longnow.HighPart = now->dwHighDateTime; + longnow.QuadPart -= longoffset.QuadPart; + now->dwLowDateTime = longnow.LowPart; + now->dwHighDateTime = longnow.HighPart; + + FreeString(rtckey); + XsFree(vm); + + return true; + +fail_platformtimeoffset: + XsLog("%s: Read platform time offset", __FUNCTION__); + + FreeString(rtckey); + +fail_rtckey: + XsLog("%s: Read RTC Key", __FUNCTION__); + + XsFree(vm); + +fail_readvm: + XsLog("%s: Read VM Key", __FUNCTION__); + + return false; +} + static void -finishSuspend(void) +setTimeToXenTime(void) { - FILETIME now = {0}; - SYSTEMTIME sys_time; - SYSTEMTIME current_time; + FILETIME now = {0}; + SYSTEMTIME sys_time; + SYSTEMTIME current_time; + HKEY InstallRegKey; + bool utc=false; + XsLog("Set time to XenTime"); - DBGPRINT(("Coming back from suspend.\n")); GetXenTime(&now); if ((now.dwLowDateTime == 0) && (now.dwHighDateTime == 0)) { XsLog("Cannot set system time to xentime, unable to contact WMI"); - return; + goto fail_readtime; } - XsLog("Xen time is %I64x", now); + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + XENTOOLS_INSTALL_REG_KEY, + 0, + KEY_ALL_ACCESS, + &InstallRegKey) != ERROR_SUCCESS) + goto fail_registrykey; + + if (registryMatchString(InstallRegKey, "HostTime", "UTC", false)) + { + XsLog("Try UTC"); + if (!adjustXenTimeToUTC(&now)) + goto fail_adjusttime; + utc=true; + } + + if (!FileTimeToSystemTime(&now, &sys_time)) { PrintError("FileTimeToSystemTime()"); DBGPRINT(("FileTimeToSystemTime(%x.%x)\n", @@ -547,9 +678,34 @@ finishSuspend(void) current_time.wYear, current_time.wMonth, current_time.wDay, current_time.wHour, current_time.wMinute, current_time.wSecond, current_time.wMilliseconds); - if (!SetLocalTime(&sys_time)) - PrintError("SetSystemTime()"); + if (utc) { + if (!SetSystemTime(&sys_time)) + PrintError("SetSystemTime()"); + } + else { + if (!SetLocalTime(&sys_time)) + PrintError("SetLocalTime()"); + } } + + return; + +fail_adjusttime: + XsLog("%s: Adjust time", __FUNCTION__); + RegCloseKey(InstallRegKey); + +fail_registrykey: + XsLog("%s: Open Registry Key", __FUNCTION__); +fail_readtime: + XsLog("%s: ReadTime", __FUNCTION__); +} + +/* We need to resync the clock when we recover from suspend/resume. */ +static void +finishSuspend(void) +{ + DBGPRINT(("Coming back from suspend.\n")); + setTimeToXenTime(); } @@ -585,6 +741,8 @@ BOOL Run() } XsLog("Guest agent lite main loop starting"); + setTimeToXenTime(); + memset(&features, 0, sizeof(features)); HANDLE wmierrorEvent = CreateEvent(NULL, FALSE, FALSE, NULL);