FreeRDP
sysinfo.c
1 
21 #include <winpr/config.h>
22 
23 #include <winpr/sysinfo.h>
24 #include <winpr/platform.h>
25 
26 #if defined(ANDROID)
27 #include "cpufeatures/cpu-features.h"
28 #endif
29 
30 #if defined(__linux__)
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #endif
35 
36 #if !defined(_WIN32)
37 #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
38 #include <time.h>
39 #elif !defined(__APPLE__)
40 #include <sys/time.h>
41 #include <sys/sysinfo.h>
42 #endif
43 #endif
44 
45 #include "../log.h"
46 #define TAG WINPR_TAG("sysinfo")
47 
48 #define FILETIME_TO_UNIX_OFFSET_S 11644473600UL
49 
50 #if defined(__MACH__) && defined(__APPLE__)
51 
52 #include <mach/mach_time.h>
53 
54 static UINT64 scaleHighPrecision(UINT64 i, UINT32 numer, UINT32 denom)
55 {
56  UINT64 high = (i >> 32) * numer;
57  UINT64 low = (i & 0xffffffffull) * numer / denom;
58  UINT64 highRem = ((high % denom) << 32) / denom;
59  high /= denom;
60  return (high << 32) + highRem + low;
61 }
62 
63 static UINT64 mac_get_time_ns(void)
64 {
65  mach_timebase_info_data_t timebase = { 0 };
66  mach_timebase_info(&timebase);
67  UINT64 t = mach_absolute_time();
68  return scaleHighPrecision(t, timebase.numer, timebase.denom);
69 }
70 
71 #endif
72 
93 #ifndef _WIN32
94 
95 #include <time.h>
96 #include <sys/time.h>
97 
98 #ifdef WINPR_HAVE_UNISTD_H
99 #include <unistd.h>
100 #endif
101 
102 #include <winpr/crt.h>
103 #include <winpr/platform.h>
104 
105 #if defined(__MACOSX__) || defined(__IOS__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
106  defined(__OpenBSD__) || defined(__DragonFly__)
107 #include <sys/sysctl.h>
108 #endif
109 
110 static WORD GetProcessorArchitecture(void)
111 {
112  WORD cpuArch = PROCESSOR_ARCHITECTURE_UNKNOWN;
113 #if defined(ANDROID)
114  AndroidCpuFamily family = android_getCpuFamily();
115 
116  switch (family)
117  {
118  case ANDROID_CPU_FAMILY_ARM:
119  return PROCESSOR_ARCHITECTURE_ARM;
120 
121  case ANDROID_CPU_FAMILY_X86:
122  return PROCESSOR_ARCHITECTURE_INTEL;
123 
124  case ANDROID_CPU_FAMILY_MIPS:
125  return PROCESSOR_ARCHITECTURE_MIPS;
126 
127  case ANDROID_CPU_FAMILY_ARM64:
128  return PROCESSOR_ARCHITECTURE_ARM64;
129 
130  case ANDROID_CPU_FAMILY_X86_64:
131  return PROCESSOR_ARCHITECTURE_AMD64;
132 
133  case ANDROID_CPU_FAMILY_MIPS64:
134  return PROCESSOR_ARCHITECTURE_MIPS64;
135 
136  default:
137  return PROCESSOR_ARCHITECTURE_UNKNOWN;
138  }
139 
140 #elif defined(_M_ARM)
141  cpuArch = PROCESSOR_ARCHITECTURE_ARM;
142 #elif defined(_M_IX86)
143  cpuArch = PROCESSOR_ARCHITECTURE_INTEL;
144 #elif defined(_M_MIPS64)
145  /* Needs to be before __mips__ since the compiler defines both */
146  cpuArch = PROCESSOR_ARCHITECTURE_MIPS64;
147 #elif defined(_M_MIPS)
148  cpuArch = PROCESSOR_ARCHITECTURE_MIPS;
149 #elif defined(_M_ARM64)
150  cpuArch = PROCESSOR_ARCHITECTURE_ARM64;
151 #elif defined(_M_AMD64)
152  cpuArch = PROCESSOR_ARCHITECTURE_AMD64;
153 #elif defined(_M_PPC)
154  cpuArch = PROCESSOR_ARCHITECTURE_PPC;
155 #elif defined(_M_ALPHA)
156  cpuArch = PROCESSOR_ARCHITECTURE_ALPHA;
157 #elif defined(_M_E2K)
158  cpuArch = PROCESSOR_ARCHITECTURE_E2K;
159 #endif
160  return cpuArch;
161 }
162 
163 static DWORD GetNumberOfProcessors(void)
164 {
165  DWORD numCPUs = 1;
166 #if defined(ANDROID)
167  return android_getCpuCount();
168  /* TODO: iOS */
169 #elif defined(__linux__) || defined(__sun) || defined(_AIX)
170  numCPUs = (DWORD)sysconf(_SC_NPROCESSORS_ONLN);
171 #elif defined(__MACOSX__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
172  defined(__OpenBSD__) || defined(__DragonFly__)
173  {
174  int mib[4];
175  size_t length = sizeof(numCPUs);
176  mib[0] = CTL_HW;
177 #if defined(__FreeBSD__) || defined(__OpenBSD__)
178  mib[1] = HW_NCPU;
179 #else
180  mib[1] = HW_AVAILCPU;
181 #endif
182  sysctl(mib, 2, &numCPUs, &length, NULL, 0);
183 
184  if (numCPUs < 1)
185  {
186  mib[1] = HW_NCPU;
187  sysctl(mib, 2, &numCPUs, &length, NULL, 0);
188 
189  if (numCPUs < 1)
190  numCPUs = 1;
191  }
192  }
193 #elif defined(__hpux)
194  numCPUs = (DWORD)mpctl(MPC_GETNUMSPUS, NULL, NULL);
195 #elif defined(__sgi)
196  numCPUs = (DWORD)sysconf(_SC_NPROC_ONLN);
197 #endif
198  return numCPUs;
199 }
200 
201 static DWORD GetSystemPageSize(void)
202 {
203  DWORD dwPageSize = 0;
204  long sc_page_size = -1;
205 #if defined(_SC_PAGESIZE)
206 
207  if (sc_page_size < 0)
208  sc_page_size = sysconf(_SC_PAGESIZE);
209 
210 #endif
211 #if defined(_SC_PAGE_SIZE)
212 
213  if (sc_page_size < 0)
214  sc_page_size = sysconf(_SC_PAGE_SIZE);
215 
216 #endif
217 
218  if (sc_page_size > 0)
219  dwPageSize = (DWORD)sc_page_size;
220 
221  if (dwPageSize < 4096)
222  dwPageSize = 4096;
223 
224  return dwPageSize;
225 }
226 
227 void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
228 {
229  lpSystemInfo->wProcessorArchitecture = GetProcessorArchitecture();
230  lpSystemInfo->wReserved = 0;
231  lpSystemInfo->dwPageSize = GetSystemPageSize();
232  lpSystemInfo->lpMinimumApplicationAddress = NULL;
233  lpSystemInfo->lpMaximumApplicationAddress = NULL;
234  lpSystemInfo->dwActiveProcessorMask = 0;
235  lpSystemInfo->dwNumberOfProcessors = GetNumberOfProcessors();
236  lpSystemInfo->dwProcessorType = 0;
237  lpSystemInfo->dwAllocationGranularity = 0;
238  lpSystemInfo->wProcessorLevel = 0;
239  lpSystemInfo->wProcessorRevision = 0;
240 }
241 
242 void GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
243 {
244  GetSystemInfo(lpSystemInfo);
245 }
246 
247 void GetSystemTime(LPSYSTEMTIME lpSystemTime)
248 {
249  time_t ct = 0;
250  struct tm tres;
251  struct tm* stm = NULL;
252  WORD wMilliseconds = 0;
253  ct = time(NULL);
254  wMilliseconds = (WORD)(GetTickCount() % 1000);
255  stm = gmtime_r(&ct, &tres);
256  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
257 
258  if (stm)
259  {
260  lpSystemTime->wYear = (WORD)(stm->tm_year + 1900);
261  lpSystemTime->wMonth = (WORD)(stm->tm_mon + 1);
262  lpSystemTime->wDayOfWeek = (WORD)stm->tm_wday;
263  lpSystemTime->wDay = (WORD)stm->tm_mday;
264  lpSystemTime->wHour = (WORD)stm->tm_hour;
265  lpSystemTime->wMinute = (WORD)stm->tm_min;
266  lpSystemTime->wSecond = (WORD)stm->tm_sec;
267  lpSystemTime->wMilliseconds = wMilliseconds;
268  }
269 }
270 
271 BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime)
272 {
273  /* TODO: Implement */
274  return FALSE;
275 }
276 
277 VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
278 {
279  time_t ct = 0;
280  struct tm tres;
281  struct tm* ltm = NULL;
282  WORD wMilliseconds = 0;
283  ct = time(NULL);
284  wMilliseconds = (WORD)(GetTickCount() % 1000);
285  ltm = localtime_r(&ct, &tres);
286  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
287 
288  if (ltm)
289  {
290  lpSystemTime->wYear = (WORD)(ltm->tm_year + 1900);
291  lpSystemTime->wMonth = (WORD)(ltm->tm_mon + 1);
292  lpSystemTime->wDayOfWeek = (WORD)ltm->tm_wday;
293  lpSystemTime->wDay = (WORD)ltm->tm_mday;
294  lpSystemTime->wHour = (WORD)ltm->tm_hour;
295  lpSystemTime->wMinute = (WORD)ltm->tm_min;
296  lpSystemTime->wSecond = (WORD)ltm->tm_sec;
297  lpSystemTime->wMilliseconds = wMilliseconds;
298  }
299 }
300 
301 BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime)
302 {
303  /* TODO: Implement */
304  return FALSE;
305 }
306 
307 VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
308 {
309  union
310  {
311  UINT64 u64;
312  FILETIME ft;
313  } t;
314 
315  t.u64 = (winpr_GetUnixTimeNS() / 100ull) + FILETIME_TO_UNIX_OFFSET_S * 10000000ull;
316  *lpSystemTimeAsFileTime = t.ft;
317 }
318 
319 BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement,
320  PBOOL lpTimeAdjustmentDisabled)
321 {
322  /* TODO: Implement */
323  return FALSE;
324 }
325 
326 #ifndef CLOCK_MONOTONIC_RAW
327 #define CLOCK_MONOTONIC_RAW 4
328 #endif
329 
330 DWORD GetTickCount(void)
331 {
332  return (DWORD)GetTickCount64();
333 }
334 #endif // _WIN32
335 
336 #if !defined(_WIN32) || defined(_UWP)
337 
338 #if defined(WITH_WINPR_DEPRECATED)
339 /* OSVERSIONINFOEX Structure:
340  * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724833
341  */
342 
343 BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
344 {
345 #ifdef _UWP
346 
347  /* Windows 10 Version Info */
348  if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
349  (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
350  {
351  lpVersionInformation->dwMajorVersion = 10;
352  lpVersionInformation->dwMinorVersion = 0;
353  lpVersionInformation->dwBuildNumber = 0;
354  lpVersionInformation->dwPlatformId = VER_PLATFORM_WIN32_NT;
355  ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
356 
357  if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
358  {
359  LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
360  lpVersionInformationEx->wServicePackMajor = 0;
361  lpVersionInformationEx->wServicePackMinor = 0;
362  lpVersionInformationEx->wSuiteMask = 0;
363  lpVersionInformationEx->wProductType = VER_NT_WORKSTATION;
364  lpVersionInformationEx->wReserved = 0;
365  }
366 
367  return TRUE;
368  }
369 
370 #else
371 
372  /* Windows 7 SP1 Version Info */
373  if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
374  (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
375  {
376  lpVersionInformation->dwMajorVersion = 6;
377  lpVersionInformation->dwMinorVersion = 1;
378  lpVersionInformation->dwBuildNumber = 7601;
379  lpVersionInformation->dwPlatformId = VER_PLATFORM_WIN32_NT;
380  ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
381 
382  if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
383  {
384  LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
385  lpVersionInformationEx->wServicePackMajor = 1;
386  lpVersionInformationEx->wServicePackMinor = 0;
387  lpVersionInformationEx->wSuiteMask = 0;
388  lpVersionInformationEx->wProductType = VER_NT_WORKSTATION;
389  lpVersionInformationEx->wReserved = 0;
390  }
391 
392  return TRUE;
393  }
394 
395 #endif
396  return FALSE;
397 }
398 
399 BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation)
400 {
401  ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
402  return GetVersionExA((LPOSVERSIONINFOA)lpVersionInformation);
403 }
404 
405 #endif
406 
407 #endif
408 
409 #if !defined(_WIN32) || defined(_UWP)
410 
411 BOOL GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
412 {
413  BOOL rc = 0;
414  LPSTR buffer = NULL;
415  if (!lpnSize || (*lpnSize > INT_MAX))
416  return FALSE;
417 
418  if (*lpnSize > 0)
419  {
420  buffer = malloc(*lpnSize);
421  if (!buffer)
422  return FALSE;
423  }
424  rc = GetComputerNameA(buffer, lpnSize);
425 
426  if (rc && (*lpnSize > 0))
427  {
428  const SSIZE_T res = ConvertUtf8NToWChar(buffer, *lpnSize, lpBuffer, *lpnSize);
429  rc = res > 0;
430  }
431 
432  free(buffer);
433 
434  return rc;
435 }
436 
437 BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize)
438 {
439  char* dot = NULL;
440  size_t length = 0;
441  char hostname[256] = { 0 };
442 
443  if (!lpnSize)
444  {
445  SetLastError(ERROR_BAD_ARGUMENTS);
446  return FALSE;
447  }
448 
449  if (gethostname(hostname, sizeof(hostname)) == -1)
450  return FALSE;
451 
452  length = strnlen(hostname, sizeof(hostname));
453  dot = strchr(hostname, '.');
454 
455  if (dot)
456  length = (dot - hostname);
457 
458  if ((*lpnSize <= (DWORD)length) || !lpBuffer)
459  {
460  SetLastError(ERROR_BUFFER_OVERFLOW);
461  *lpnSize = (DWORD)(length + 1);
462  return FALSE;
463  }
464 
465  CopyMemory(lpBuffer, hostname, length);
466  lpBuffer[length] = '\0';
467  *lpnSize = (DWORD)length;
468  return TRUE;
469 }
470 
471 BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD lpnSize)
472 {
473  size_t length = 0;
474  char hostname[256] = { 0 };
475 
476  if (!lpnSize)
477  {
478  SetLastError(ERROR_BAD_ARGUMENTS);
479  return FALSE;
480  }
481 
482  if ((NameType == ComputerNameNetBIOS) || (NameType == ComputerNamePhysicalNetBIOS))
483  {
484  BOOL rc = GetComputerNameA(lpBuffer, lpnSize);
485 
486  if (!rc)
487  {
488  if (GetLastError() == ERROR_BUFFER_OVERFLOW)
489  SetLastError(ERROR_MORE_DATA);
490  }
491 
492  return rc;
493  }
494 
495  if (gethostname(hostname, sizeof(hostname)) == -1)
496  return FALSE;
497 
498  length = strnlen(hostname, sizeof(hostname));
499 
500  switch (NameType)
501  {
502  case ComputerNameDnsHostname:
503  case ComputerNameDnsDomain:
504  case ComputerNameDnsFullyQualified:
505  case ComputerNamePhysicalDnsHostname:
506  case ComputerNamePhysicalDnsDomain:
507  case ComputerNamePhysicalDnsFullyQualified:
508  if ((*lpnSize <= (DWORD)length) || !lpBuffer)
509  {
510  *lpnSize = (DWORD)(length + 1);
511  SetLastError(ERROR_MORE_DATA);
512  return FALSE;
513  }
514 
515  CopyMemory(lpBuffer, hostname, length);
516  lpBuffer[length] = '\0';
517  *lpnSize = (DWORD)length;
518  break;
519 
520  default:
521  return FALSE;
522  }
523 
524  return TRUE;
525 }
526 
527 BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD lpnSize)
528 {
529  BOOL rc = 0;
530  LPSTR lpABuffer = NULL;
531 
532  if (!lpnSize)
533  {
534  SetLastError(ERROR_BAD_ARGUMENTS);
535  return FALSE;
536  }
537 
538  if (*lpnSize > 0)
539  {
540  lpABuffer = calloc(*lpnSize, sizeof(CHAR));
541 
542  if (!lpABuffer)
543  return FALSE;
544  }
545 
546  rc = GetComputerNameExA(NameType, lpABuffer, lpnSize);
547 
548  if (rc && (*lpnSize > 0))
549  {
550  const SSIZE_T res = ConvertUtf8NToWChar(lpABuffer, *lpnSize, lpBuffer, *lpnSize);
551  rc = res > 0;
552  }
553 
554  free(lpABuffer);
555  return rc;
556 }
557 
558 #endif
559 
560 #if defined(_UWP)
561 
562 DWORD GetTickCount(void)
563 {
564  return (DWORD)GetTickCount64();
565 }
566 
567 #endif
568 
569 #if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600))
570 
571 ULONGLONG winpr_GetTickCount64(void)
572 {
573  const UINT64 ns = winpr_GetTickCount64NS();
574  return WINPR_TIME_NS_TO_MS(ns);
575 }
576 
577 #endif
578 
579 UINT64 winpr_GetTickCount64NS(void)
580 {
581  UINT64 ticks = 0;
582 #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
583  struct timespec ts = { 0 };
584 
585  if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == 0)
586  ticks = (ts.tv_sec * 1000000000ull) + ts.tv_nsec;
587 #elif defined(__MACH__) && defined(__APPLE__)
588  ticks = mac_get_time_ns();
589 #elif defined(_WIN32)
590  LARGE_INTEGER li = { 0 };
591  LARGE_INTEGER freq = { 0 };
592  if (QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&li))
593  ticks = li.QuadPart * 1000000000ull / freq.QuadPart;
594 #else
595  struct timeval tv = { 0 };
596 
597  if (gettimeofday(&tv, NULL) == 0)
598  ticks = (tv.tv_sec * 1000000000ull) + (tv.tv_usec * 1000ull);
599 
600  /* We need to trick here:
601  * this function should return the system uptime, but we need higher resolution.
602  * so on first call get the actual timestamp along with the system uptime.
603  *
604  * return the uptime measured from now on (e.g. current measure - first measure + uptime at
605  * first measure)
606  */
607  static UINT64 first = 0;
608  static UINT64 uptime = 0;
609  if (first == 0)
610  {
611  struct sysinfo info = { 0 };
612  if (sysinfo(&info) == 0)
613  {
614  first = ticks;
615  uptime = 1000000000ull * info.uptime;
616  }
617  }
618 
619  ticks = ticks - first + uptime;
620 #endif
621  return ticks;
622 }
623 
624 UINT64 winpr_GetUnixTimeNS(void)
625 {
626 #if defined(_WIN32)
627 
628  union
629  {
630  UINT64 u64;
631  FILETIME ft;
632  } t = { 0 };
633  GetSystemTimeAsFileTime(&t.ft);
634  return (t.u64 - FILETIME_TO_UNIX_OFFSET_S * 10000000ull) * 100ull;
635 #elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
636  struct timespec ts = { 0 };
637  if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
638  return 0;
639  return ts.tv_sec * 1000000000ull + ts.tv_nsec;
640 #else
641  struct timeval tv = { 0 };
642  if (gettimeofday(&tv, NULL) != 0)
643  return 0;
644  return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ull;
645 #endif
646 }
647 
648 /* If x86 */
649 #ifdef _M_IX86_AMD64
650 
651 #if defined(__GNUC__)
652 #define xgetbv(_func_, _lo_, _hi_) \
653  __asm__ __volatile__("xgetbv" : "=a"(_lo_), "=d"(_hi_) : "c"(_func_))
654 #elif defined(_MSC_VER)
655 #define xgetbv(_func_, _lo_, _hi_) \
656  { \
657  unsigned __int64 val = _xgetbv(_func_); \
658  _lo_ = val & 0xFFFFFFFF; \
659  _hi_ = (val >> 32); \
660  }
661 #endif
662 
663 #define B_BIT_AVX2 (1 << 5)
664 #define B_BIT_AVX512F (1 << 16)
665 #define D_BIT_MMX (1 << 23)
666 #define D_BIT_SSE (1 << 25)
667 #define D_BIT_SSE2 (1 << 26)
668 #define D_BIT_3DN (1 << 30)
669 #define C_BIT_SSE3 (1 << 0)
670 #define C_BIT_PCLMULQDQ (1 << 1)
671 #define C81_BIT_LZCNT (1 << 5)
672 #define C_BIT_3DNP (1 << 8)
673 #define C_BIT_3DNP (1 << 8)
674 #define C_BIT_SSSE3 (1 << 9)
675 #define C_BIT_SSE41 (1 << 19)
676 #define C_BIT_SSE42 (1 << 20)
677 #define C_BIT_FMA (1 << 12)
678 #define C_BIT_AES (1 << 25)
679 #define C_BIT_XGETBV (1 << 27)
680 #define C_BIT_AVX (1 << 28)
681 #define E_BIT_XMM (1 << 1)
682 #define E_BIT_YMM (1 << 2)
683 #define E_BITS_AVX (E_BIT_XMM | E_BIT_YMM)
684 
685 static void cpuid(unsigned info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx)
686 {
687 #ifdef __GNUC__
688  *eax = *ebx = *ecx = *edx = 0;
689  __asm volatile(
690  /* The EBX (or RBX register on x86_64) is used for the PIC base address
691  * and must not be corrupted by our inline assembly.
692  */
693 #ifdef _M_IX86
694  "mov %%ebx, %%esi;"
695  "cpuid;"
696  "xchg %%ebx, %%esi;"
697 #else
698  "mov %%rbx, %%rsi;"
699  "cpuid;"
700  "xchg %%rbx, %%rsi;"
701 #endif
702  : "=a"(*eax), "=S"(*ebx), "=c"(*ecx), "=d"(*edx)
703  : "a"(info), "c"(0));
704 #elif defined(_MSC_VER)
705  int a[4];
706  __cpuid(a, info);
707  *eax = a[0];
708  *ebx = a[1];
709  *ecx = a[2];
710  *edx = a[3];
711 #endif
712 }
713 #elif defined(_M_ARM) || defined(_M_ARM64)
714 #if defined(__linux__)
715 // HWCAP flags from linux kernel - uapi/asm/hwcap.h
716 #define HWCAP_SWP (1 << 0)
717 #define HWCAP_HALF (1 << 1)
718 #define HWCAP_THUMB (1 << 2)
719 #define HWCAP_26BIT (1 << 3) /* Play it safe */
720 #define HWCAP_FAST_MULT (1 << 4)
721 #define HWCAP_FPA (1 << 5)
722 #define HWCAP_VFP (1 << 6)
723 #define HWCAP_EDSP (1 << 7)
724 #define HWCAP_JAVA (1 << 8)
725 #define HWCAP_IWMMXT (1 << 9)
726 #define HWCAP_CRUNCH (1 << 10)
727 #define HWCAP_THUMBEE (1 << 11)
728 #define HWCAP_NEON (1 << 12)
729 #define HWCAP_VFPv3 (1 << 13)
730 #define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
731 #define HWCAP_TLS (1 << 15)
732 #define HWCAP_VFPv4 (1 << 16)
733 #define HWCAP_IDIVA (1 << 17)
734 #define HWCAP_IDIVT (1 << 18)
735 #define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
736 #define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
737 
738 // From linux kernel uapi/linux/auxvec.h
739 #define AT_HWCAP 16
740 
741 static unsigned GetARMCPUCaps(void)
742 {
743  unsigned caps = 0;
744  int fd = open("/proc/self/auxv", O_RDONLY);
745 
746  if (fd == -1)
747  return 0;
748 
749  static struct
750  {
751  unsigned a_type; /* Entry type */
752  unsigned a_val; /* Integer value */
753  } auxvec;
754 
755  while (1)
756  {
757  int num;
758  num = read(fd, (char*)&auxvec, sizeof(auxvec));
759 
760  if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0))
761  break;
762 
763  if (auxvec.a_type == AT_HWCAP)
764  {
765  caps = auxvec.a_val;
766  }
767  }
768 
769  close(fd);
770  return caps;
771 }
772 
773 #endif // defined(__linux__)
774 #endif // _M_IX86_AMD64
775 
776 #ifndef _WIN32
777 
778 #if defined(_M_ARM) || defined(_M_ARM64)
779 #ifdef __linux__
780 #include <sys/auxv.h>
781 #endif
782 #endif
783 
784 BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
785 {
786  BOOL ret = FALSE;
787 #if defined(ANDROID)
788  const uint64_t features = android_getCpuFeatures();
789 
790  switch (ProcessorFeature)
791  {
792  case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
793  case PF_ARM_NEON:
794  return features & ANDROID_CPU_ARM_FEATURE_NEON;
795 
796  default:
797  WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
798  return FALSE;
799  }
800 
801 #elif defined(_M_ARM) || defined(_M_ARM64)
802 #ifdef __linux__
803  const unsigned long caps = getauxval(AT_HWCAP);
804 
805  switch (ProcessorFeature)
806  {
807  case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
808  case PF_ARM_NEON:
809 
810  if (caps & HWCAP_NEON)
811  ret = TRUE;
812 
813  break;
814 
815  case PF_ARM_THUMB:
816  if (caps & HWCAP_THUMB)
817  ret = TRUE;
818 
819  case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
820  if (caps & HWCAP_VFPD32)
821  ret = TRUE;
822 
823  case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
824  if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
825  ret = TRUE;
826 
827  case PF_ARM_VFP3:
828  if (caps & HWCAP_VFPv3)
829  ret = TRUE;
830 
831  break;
832 
833  case PF_ARM_JAZELLE:
834  if (caps & HWCAP_JAVA)
835  ret = TRUE;
836 
837  break;
838 
839  case PF_ARM_DSP:
840  if (caps & HWCAP_EDSP)
841  ret = TRUE;
842 
843  break;
844 
845  case PF_ARM_MPU:
846  if (caps & HWCAP_EDSP)
847  ret = TRUE;
848 
849  break;
850 
851  case PF_ARM_THUMB2:
852  if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
853  ret = TRUE;
854 
855  break;
856 
857  case PF_ARM_T2EE:
858  if (caps & HWCAP_THUMBEE)
859  ret = TRUE;
860 
861  break;
862 
863  case PF_ARM_INTEL_WMMX:
864  if (caps & HWCAP_IWMMXT)
865  ret = TRUE;
866 
867  break;
868  case PF_ARM_V8_INSTRUCTIONS_AVAILABLE:
869  case PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE:
870  case PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE:
871  case PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE:
872  case PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE:
873  case PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE:
874  case PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE:
875  default:
876  WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
877  break;
878  }
879 
880 #else // __linux__
881 
882  switch (ProcessorFeature)
883  {
884  case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
885  case PF_ARM_NEON:
886 #ifdef __ARM_NEON
887  ret = TRUE;
888 #endif
889  break;
890  case PF_ARM_V8_INSTRUCTIONS_AVAILABLE:
891  case PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE:
892  case PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE:
893  case PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE:
894  case PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE:
895  case PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE:
896  case PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE:
897  default:
898  WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
899  break;
900  }
901 
902 #endif // __linux__
903 #endif
904 
905 #if defined(_M_IX86_AMD64)
906 #ifdef __GNUC__
907  unsigned a = 0;
908  unsigned b = 0;
909  unsigned c = 0;
910  unsigned d = 0;
911  cpuid(1, &a, &b, &c, &d);
912 
913  switch (ProcessorFeature)
914  {
915  case PF_MMX_INSTRUCTIONS_AVAILABLE:
916  if (d & D_BIT_MMX)
917  ret = TRUE;
918 
919  break;
920 
921  case PF_XMMI_INSTRUCTIONS_AVAILABLE:
922  if (d & D_BIT_SSE)
923  ret = TRUE;
924 
925  break;
926 
927  case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
928  if (d & D_BIT_SSE2)
929  ret = TRUE;
930 
931  break;
932 
933  case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
934  if (d & D_BIT_3DN)
935  ret = TRUE;
936 
937  break;
938 
939  case PF_SSE3_INSTRUCTIONS_AVAILABLE:
940  ret = __builtin_cpu_supports("sse3");
941  break;
942 
943  case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
944  ret = __builtin_cpu_supports("ssse3");
945  break;
946  case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
947  ret = __builtin_cpu_supports("sse4.1");
948  break;
949  case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
950  ret = __builtin_cpu_supports("sse4.2");
951  break;
952  case PF_AVX_INSTRUCTIONS_AVAILABLE:
953  ret = __builtin_cpu_supports("avx");
954  break;
955  case PF_AVX2_INSTRUCTIONS_AVAILABLE:
956  ret = __builtin_cpu_supports("avx2");
957  break;
958  case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
959  ret = __builtin_cpu_supports("avx512f");
960  break;
961  default:
962  WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
963  break;
964  }
965 
966 #endif // __GNUC__
967 #endif
968 
969 #if defined(_M_E2K)
970  /* compiler flags on e2k arch determine CPU features */
971  switch (ProcessorFeature)
972  {
973  case PF_MMX_INSTRUCTIONS_AVAILABLE:
974 #ifdef __MMX__
975  ret = TRUE;
976 #endif
977  break;
978 
979  case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
980 #ifdef __3dNOW__
981  ret = TRUE;
982 #endif
983  break;
984 
985  case PF_SSE3_INSTRUCTIONS_AVAILABLE:
986 #ifdef __SSE3__
987  ret = TRUE;
988 #endif
989  break;
990 
991  default:
992  break;
993  }
994 
995 #endif
996  return ret;
997 }
998 
999 #endif //_WIN32
1000 
1001 DWORD GetTickCountPrecise(void)
1002 {
1003 #ifdef _WIN32
1004  LARGE_INTEGER freq = { 0 };
1005  LARGE_INTEGER current = { 0 };
1006  QueryPerformanceFrequency(&freq);
1007  QueryPerformanceCounter(&current);
1008  return (DWORD)(current.QuadPart * 1000LL / freq.QuadPart);
1009 #else
1010  return GetTickCount();
1011 #endif
1012 }
1013 
1014 BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
1015 {
1016  BOOL ret = FALSE;
1017 #if defined(_M_ARM) || defined(_M_ARM64)
1018 #ifdef __linux__
1019  unsigned caps;
1020  caps = GetARMCPUCaps();
1021 
1022  switch (ProcessorFeature)
1023  {
1024  case PF_EX_ARM_VFP1:
1025  if (caps & HWCAP_VFP)
1026  ret = TRUE;
1027 
1028  break;
1029 
1030  case PF_EX_ARM_VFP3D16:
1031  if (caps & HWCAP_VFPv3D16)
1032  ret = TRUE;
1033 
1034  break;
1035 
1036  case PF_EX_ARM_VFP4:
1037  if (caps & HWCAP_VFPv4)
1038  ret = TRUE;
1039 
1040  break;
1041 
1042  case PF_EX_ARM_IDIVA:
1043  if (caps & HWCAP_IDIVA)
1044  ret = TRUE;
1045 
1046  break;
1047 
1048  case PF_EX_ARM_IDIVT:
1049  if (caps & HWCAP_IDIVT)
1050  ret = TRUE;
1051 
1052  break;
1053  }
1054 
1055 #endif // __linux__
1056 #elif defined(_M_IX86_AMD64)
1057  unsigned a = 0;
1058  unsigned b = 0;
1059  unsigned c = 0;
1060  unsigned d = 0;
1061  cpuid(1, &a, &b, &c, &d);
1062 
1063  switch (ProcessorFeature)
1064  {
1065  case PF_EX_LZCNT:
1066  {
1067  unsigned a81 = 0;
1068  unsigned b81 = 0;
1069  unsigned c81 = 0;
1070  unsigned d81 = 0;
1071  cpuid(0x80000001, &a81, &b81, &c81, &d81);
1072 
1073  if (c81 & C81_BIT_LZCNT)
1074  ret = TRUE;
1075  }
1076  break;
1077 
1078  case PF_EX_3DNOW_PREFETCH:
1079  if (c & C_BIT_3DNP)
1080  ret = TRUE;
1081 
1082  break;
1083 
1084  case PF_EX_SSSE3:
1085  if (c & C_BIT_SSSE3)
1086  ret = TRUE;
1087 
1088  break;
1089 
1090  case PF_EX_SSE41:
1091  if (c & C_BIT_SSE41)
1092  ret = TRUE;
1093 
1094  break;
1095 
1096  case PF_EX_SSE42:
1097  if (c & C_BIT_SSE42)
1098  ret = TRUE;
1099 
1100  break;
1101 #if defined(__GNUC__) || defined(_MSC_VER)
1102 
1103  case PF_EX_AVX:
1104  case PF_EX_AVX2:
1105  case PF_EX_AVX512F:
1106  case PF_EX_FMA:
1107  case PF_EX_AVX_AES:
1108  case PF_EX_AVX_PCLMULQDQ:
1109  {
1110  /* Check for general AVX support */
1111  if (!(c & C_BIT_AVX))
1112  break;
1113 
1114  /* Check for xgetbv support */
1115  if (!(c & C_BIT_XGETBV))
1116  break;
1117 
1118  int e = 0;
1119  int f = 0;
1120  xgetbv(0, e, f);
1121 
1122  /* XGETBV enabled for applications and XMM/YMM states enabled */
1123  if ((e & E_BITS_AVX) == E_BITS_AVX)
1124  {
1125  switch (ProcessorFeature)
1126  {
1127  case PF_EX_AVX:
1128  ret = TRUE;
1129  break;
1130 
1131  case PF_EX_AVX2:
1132  case PF_EX_AVX512F:
1133  cpuid(7, &a, &b, &c, &d);
1134  switch (ProcessorFeature)
1135  {
1136  case PF_EX_AVX2:
1137  if (b & B_BIT_AVX2)
1138  ret = TRUE;
1139  break;
1140 
1141  case PF_EX_AVX512F:
1142  if (b & B_BIT_AVX512F)
1143  ret = TRUE;
1144  break;
1145 
1146  default:
1147  break;
1148  }
1149  break;
1150 
1151  case PF_EX_FMA:
1152  if (c & C_BIT_FMA)
1153  ret = TRUE;
1154 
1155  break;
1156 
1157  case PF_EX_AVX_AES:
1158  if (c & C_BIT_AES)
1159  ret = TRUE;
1160 
1161  break;
1162 
1163  case PF_EX_AVX_PCLMULQDQ:
1164  if (c & C_BIT_PCLMULQDQ)
1165  ret = TRUE;
1166 
1167  break;
1168  default:
1169  break;
1170  }
1171  }
1172  }
1173  break;
1174 #endif // __GNUC__ || _MSC_VER
1175 
1176  default:
1177  break;
1178  }
1179 #elif defined(_M_E2K)
1180  /* compiler flags on e2k arch determine CPU features */
1181  switch (ProcessorFeature)
1182  {
1183  case PF_EX_LZCNT:
1184 #ifdef __LZCNT__
1185  ret = TRUE;
1186 #endif
1187  break;
1188 
1189  case PF_EX_SSSE3:
1190 #ifdef __SSSE3__
1191  ret = TRUE;
1192 #endif
1193  break;
1194 
1195  case PF_EX_SSE41:
1196 #ifdef __SSE4_1__
1197  ret = TRUE;
1198 #endif
1199  break;
1200 
1201  case PF_EX_SSE42:
1202 #ifdef __SSE4_2__
1203  ret = TRUE;
1204 #endif
1205  break;
1206 
1207  case PF_EX_AVX:
1208 #ifdef __AVX__
1209  ret = TRUE;
1210 #endif
1211  break;
1212 
1213  case PF_EX_AVX2:
1214 #ifdef __AVX2__
1215  ret = TRUE;
1216 #endif
1217  break;
1218 
1219  case PF_EX_FMA:
1220 #ifdef __FMA__
1221  ret = TRUE;
1222 #endif
1223  break;
1224 
1225  default:
1226  break;
1227  }
1228 #endif
1229  return ret;
1230 }