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