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