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#include <dirent.h>
36#include <limits.h>
37#endif
38
39#if defined(__MACOSX__)
40#include <CoreFoundation/CoreFoundation.h>
41#include <IOKit/ps/IOPowerSources.h>
42#include <IOKit/ps/IOPSKeys.h>
43#endif
44
45#if defined(__FreeBSD__)
46#include <sys/types.h>
47#include <sys/sysctl.h>
48#endif
49
50#if !defined(_WIN32)
51#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
52#include <time.h>
53#elif !defined(__APPLE__)
54#include <sys/time.h>
55#include <sys/sysinfo.h>
56#endif
57#endif
58
59#include "../log.h"
60#define TAG WINPR_TAG("sysinfo")
61
62#define FILETIME_TO_UNIX_OFFSET_S 11644473600UL
63
64#if defined(__MACH__) && defined(__APPLE__)
65
66#include <mach/mach_time.h>
67
68static UINT64 scaleHighPrecision(UINT64 i, UINT32 numer, UINT32 denom)
69{
70 UINT64 high = (i >> 32) * numer;
71 UINT64 low = (i & 0xffffffffull) * numer / denom;
72 UINT64 highRem = ((high % denom) << 32) / denom;
73 high /= denom;
74 return (high << 32) + highRem + low;
75}
76
77static UINT64 mac_get_time_ns(void)
78{
79 mach_timebase_info_data_t timebase = WINPR_C_ARRAY_INIT;
80 mach_timebase_info(&timebase);
81 UINT64 t = mach_absolute_time();
82 return scaleHighPrecision(t, timebase.numer, timebase.denom);
83}
84
85#endif
86
107#ifndef _WIN32
108
109#include <time.h>
110#include <sys/time.h>
111
112#ifdef WINPR_HAVE_UNISTD_H
113#include <unistd.h>
114#endif
115
116#include <winpr/crt.h>
117#include <winpr/platform.h>
118
119#if defined(__MACOSX__) || defined(__IOS__)
120#include <sys/sysctl.h>
121#endif
122
123static WORD GetProcessorArchitecture(void)
124{
125 WORD cpuArch = PROCESSOR_ARCHITECTURE_UNKNOWN;
126#if defined(ANDROID)
127 AndroidCpuFamily family = android_getCpuFamily();
128
129 switch (family)
130 {
131 case ANDROID_CPU_FAMILY_ARM:
132 return PROCESSOR_ARCHITECTURE_ARM;
133
134 case ANDROID_CPU_FAMILY_X86:
135 return PROCESSOR_ARCHITECTURE_INTEL;
136
137 case ANDROID_CPU_FAMILY_MIPS:
138 return PROCESSOR_ARCHITECTURE_MIPS;
139
140 case ANDROID_CPU_FAMILY_ARM64:
141 return PROCESSOR_ARCHITECTURE_ARM64;
142
143 case ANDROID_CPU_FAMILY_X86_64:
144 return PROCESSOR_ARCHITECTURE_AMD64;
145
146 case ANDROID_CPU_FAMILY_MIPS64:
147 return PROCESSOR_ARCHITECTURE_MIPS64;
148
149 default:
150 return PROCESSOR_ARCHITECTURE_UNKNOWN;
151 }
152#elif defined(__MACOSX__) || defined(__IOS__)
153 int32_t val = 0;
154 size_t len = sizeof(val);
155
156 const int rc = sysctlbyname("hw.cputype", &val, &len, nullptr, 0);
157 if (rc != 0)
158 return PROCESSOR_ARCHITECTURE_UNKNOWN;
159
160 switch (val)
161 {
162 case CPU_TYPE_X86:
163 return PROCESSOR_ARCHITECTURE_INTEL;
164 case CPU_TYPE_X86_64:
165 return PROCESSOR_ARCHITECTURE_AMD64;
166 case CPU_TYPE_ARM:
167 return PROCESSOR_ARCHITECTURE_ARM;
168#ifdef CPU_TYPE_ARM64
169 case CPU_TYPE_ARM64:
170 return PROCESSOR_ARCHITECTURE_ARM64;
171#endif
172#ifdef CPU_TYPE_ARM64_32
173 case CPU_TYPE_ARM64_32:
174 return PROCESSOR_ARCHITECTURE_ARM;
175#endif
176#ifdef CPU_TYPE_POWERPC
177 case CPU_TYPE_POWERPC:
178 return PROCESSOR_ARCHITECTURE_PPC;
179#endif
180#ifdef CPU_TYPE_POWERPC64
181 case CPU_TYPE_POWERPC64:
182 return PROCESSOR_ARCHITECTURE_PPC;
183#endif
184 default:
185 return PROCESSOR_ARCHITECTURE_UNKNOWN;
186 }
187
188#elif defined(_M_ARM)
189 cpuArch = PROCESSOR_ARCHITECTURE_ARM;
190#elif defined(_M_IX86)
191 cpuArch = PROCESSOR_ARCHITECTURE_INTEL;
192#elif defined(_M_MIPS64)
193 /* Needs to be before __mips__ since the compiler defines both */
194 cpuArch = PROCESSOR_ARCHITECTURE_MIPS64;
195#elif defined(_M_MIPS)
196 cpuArch = PROCESSOR_ARCHITECTURE_MIPS;
197#elif defined(_M_ARM64)
198 cpuArch = PROCESSOR_ARCHITECTURE_ARM64;
199#elif defined(_M_AMD64)
200 cpuArch = PROCESSOR_ARCHITECTURE_AMD64;
201#elif defined(_M_PPC)
202 cpuArch = PROCESSOR_ARCHITECTURE_PPC;
203#elif defined(_M_ALPHA)
204 cpuArch = PROCESSOR_ARCHITECTURE_ALPHA;
205#elif defined(_M_E2K)
206 cpuArch = PROCESSOR_ARCHITECTURE_E2K;
207#endif
208 return cpuArch;
209}
210
211static DWORD GetNumberOfProcessors(void)
212{
213 DWORD numCPUs = 1;
214#if defined(ANDROID)
215 return android_getCpuCount();
216#elif defined(__MACOSX__) || defined(__IOS__)
217 int32_t val = 0;
218 size_t len = sizeof(val);
219 const int rc = sysctlbyname("hw.logicalcpu", &val, &len, nullptr, 0);
220 if (rc == 0)
221 numCPUs = WINPR_ASSERTING_INT_CAST(DWORD, val);
222#elif defined(__hpux)
223 numCPUs = (DWORD)mpctl(MPC_GETNUMSPUS, nullptr, nullptr);
224#elif defined(__sgi)
225 numCPUs = (DWORD)sysconf(_SC_NPROC_ONLN);
226#elif defined(_SC_NPROCESSORS_ONLN)
227 numCPUs = (DWORD)sysconf(_SC_NPROCESSORS_ONLN);
228#endif
229 return numCPUs;
230}
231
232static DWORD GetSystemPageSize(void)
233{
234 DWORD dwPageSize = 0;
235 long sc_page_size = -1;
236#if defined(_SC_PAGESIZE)
237
238 if (sc_page_size < 0)
239 sc_page_size = sysconf(_SC_PAGESIZE);
240
241#endif
242#if defined(_SC_PAGE_SIZE)
243
244 if (sc_page_size < 0)
245 sc_page_size = sysconf(_SC_PAGE_SIZE);
246
247#endif
248
249 if (sc_page_size > 0)
250 dwPageSize = (DWORD)sc_page_size;
251
252 if (dwPageSize < 4096)
253 dwPageSize = 4096;
254
255 return dwPageSize;
256}
257
258void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
259{
260 const SYSTEM_INFO empty = WINPR_C_ARRAY_INIT;
261 WINPR_ASSERT(lpSystemInfo);
262
263 *lpSystemInfo = empty;
264 lpSystemInfo->DUMMYUNIONNAME.DUMMYSTRUCTNAME.wProcessorArchitecture =
265 GetProcessorArchitecture();
266 lpSystemInfo->dwPageSize = GetSystemPageSize();
267 lpSystemInfo->dwNumberOfProcessors = GetNumberOfProcessors();
268}
269
270void GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
271{
272 GetSystemInfo(lpSystemInfo);
273}
274
275void GetSystemTime(LPSYSTEMTIME lpSystemTime)
276{
277 time_t ct = 0;
278 struct tm tres;
279 struct tm* stm = nullptr;
280 WORD wMilliseconds = 0;
281 UINT64 now = winpr_GetUnixTimeNS();
282 ct = WINPR_TIME_NS_TO_S(now);
283 wMilliseconds = (WORD)(WINPR_TIME_NS_REM_MS(now));
284 stm = gmtime_r(&ct, &tres);
285 ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
286
287 if (stm)
288 {
289 lpSystemTime->wYear = (WORD)(stm->tm_year + 1900);
290 lpSystemTime->wMonth = (WORD)(stm->tm_mon + 1);
291 lpSystemTime->wDayOfWeek = (WORD)stm->tm_wday;
292 lpSystemTime->wDay = (WORD)stm->tm_mday;
293 lpSystemTime->wHour = (WORD)stm->tm_hour;
294 lpSystemTime->wMinute = (WORD)stm->tm_min;
295 lpSystemTime->wSecond = (WORD)stm->tm_sec;
296 lpSystemTime->wMilliseconds = wMilliseconds;
297 }
298}
299
300BOOL SetSystemTime(WINPR_ATTR_UNUSED CONST SYSTEMTIME* lpSystemTime)
301{
302 /* TODO: Implement */
303 WLog_ERR("TODO", "TODO: Implement");
304 return FALSE;
305}
306
307VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
308{
309 time_t ct = 0;
310 struct tm tres;
311 struct tm* ltm = nullptr;
312 WORD wMilliseconds = 0;
313 UINT64 now = winpr_GetUnixTimeNS();
314 ct = WINPR_TIME_NS_TO_S(now);
315 wMilliseconds = (WORD)(WINPR_TIME_NS_REM_MS(now));
316 ltm = localtime_r(&ct, &tres);
317 ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
318
319 if (ltm)
320 {
321 lpSystemTime->wYear = (WORD)(ltm->tm_year + 1900);
322 lpSystemTime->wMonth = (WORD)(ltm->tm_mon + 1);
323 lpSystemTime->wDayOfWeek = (WORD)ltm->tm_wday;
324 lpSystemTime->wDay = (WORD)ltm->tm_mday;
325 lpSystemTime->wHour = (WORD)ltm->tm_hour;
326 lpSystemTime->wMinute = (WORD)ltm->tm_min;
327 lpSystemTime->wSecond = (WORD)ltm->tm_sec;
328 lpSystemTime->wMilliseconds = wMilliseconds;
329 }
330}
331
332BOOL SetLocalTime(WINPR_ATTR_UNUSED CONST SYSTEMTIME* lpSystemTime)
333{
334 /* TODO: Implement */
335 WLog_ERR("TODO", "TODO: Implement");
336 return FALSE;
337}
338
339VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
340{
341 union
342 {
343 UINT64 u64;
344 FILETIME ft;
345 } t;
346
347 t.u64 = (winpr_GetUnixTimeNS() / 100ull) + FILETIME_TO_UNIX_OFFSET_S * 10000000ull;
348 *lpSystemTimeAsFileTime = t.ft;
349}
350
351BOOL GetSystemTimeAdjustment(WINPR_ATTR_UNUSED PDWORD lpTimeAdjustment,
352 WINPR_ATTR_UNUSED PDWORD lpTimeIncrement,
353 WINPR_ATTR_UNUSED PBOOL lpTimeAdjustmentDisabled)
354{
355 /* TODO: Implement */
356 WLog_ERR("TODO", "TODO: Implement");
357 return FALSE;
358}
359
360#ifdef CLOCK_MONOTONIC_RAW
361#define CLOCK_ID CLOCK_MONOTONIC_RAW
362#else
363#define CLOCK_ID CLOCK_MONOTONIC
364#endif
365
366DWORD GetTickCount(void)
367{
368 return (DWORD)GetTickCount64();
369}
370#endif // _WIN32
371
372#if !defined(_WIN32) || defined(_UWP)
373
374#if defined(WITH_WINPR_DEPRECATED)
375/* OSVERSIONINFOEX Structure:
376 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724833
377 */
378
379BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
380{
381#ifdef _UWP
382
383 /* Windows 10 Version Info */
384 if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
385 (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
386 {
387 lpVersionInformation->dwMajorVersion = 10;
388 lpVersionInformation->dwMinorVersion = 0;
389 lpVersionInformation->dwBuildNumber = 0;
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 = 0;
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#else
407
408 /* Windows 7 SP1 Version Info */
409 if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
410 (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
411 {
412 lpVersionInformation->dwMajorVersion = 6;
413 lpVersionInformation->dwMinorVersion = 1;
414 lpVersionInformation->dwBuildNumber = 7601;
415 lpVersionInformation->dwPlatformId = VER_PLATFORM_WIN32_NT;
416 ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
417
418 if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
419 {
420 LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
421 lpVersionInformationEx->wServicePackMajor = 1;
422 lpVersionInformationEx->wServicePackMinor = 0;
423 lpVersionInformationEx->wSuiteMask = 0;
424 lpVersionInformationEx->wProductType = VER_NT_WORKSTATION;
425 lpVersionInformationEx->wReserved = 0;
426 }
427
428 return TRUE;
429 }
430
431#endif
432 return FALSE;
433}
434
435BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation)
436{
437 ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
438 return GetVersionExA((LPOSVERSIONINFOA)lpVersionInformation);
439}
440
441#endif
442
443#endif
444
445#if !defined(_WIN32) || defined(_UWP)
446
447BOOL GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
448{
449 BOOL rc = 0;
450 LPSTR buffer = nullptr;
451 if (!lpnSize || (*lpnSize > INT_MAX))
452 return FALSE;
453
454 if (*lpnSize > 0)
455 {
456 buffer = malloc(*lpnSize);
457 if (!buffer)
458 return FALSE;
459 }
460 rc = GetComputerNameA(buffer, lpnSize);
461
462 if (rc && (*lpnSize > 0))
463 {
464 const SSIZE_T res = ConvertUtf8NToWChar(buffer, *lpnSize, lpBuffer, *lpnSize);
465 rc = res > 0;
466 }
467
468 free(buffer);
469
470 return rc;
471}
472
473BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize)
474{
475 if (!lpnSize)
476 {
477 SetLastError(ERROR_BAD_ARGUMENTS);
478 return FALSE;
479 }
480
481 char hostname[256 + 1] = WINPR_C_ARRAY_INIT;
482 if (gethostname(hostname, ARRAYSIZE(hostname) - 1) == -1)
483 return FALSE;
484
485 size_t length = strnlen(hostname, MAX_COMPUTERNAME_LENGTH);
486 const char* dot = strchr(hostname, '.');
487 if (dot)
488 {
489 const size_t dotlen = WINPR_ASSERTING_INT_CAST(size_t, (dot - hostname));
490 if (dotlen < length)
491 length = dotlen;
492 }
493
494 if ((*lpnSize <= (DWORD)length) || !lpBuffer)
495 {
496 SetLastError(ERROR_BUFFER_OVERFLOW);
497 *lpnSize = (DWORD)(length + 1);
498 return FALSE;
499 }
500
501 strncpy(lpBuffer, hostname, length);
502 lpBuffer[length] = '\0';
503 *lpnSize = (DWORD)length;
504 return TRUE;
505}
506
507BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD lpnSize)
508{
509 size_t length = 0;
510 char hostname[256] = WINPR_C_ARRAY_INIT;
511
512 if (!lpnSize)
513 {
514 SetLastError(ERROR_BAD_ARGUMENTS);
515 return FALSE;
516 }
517
518 if ((NameType == ComputerNameNetBIOS) || (NameType == ComputerNamePhysicalNetBIOS))
519 {
520 BOOL rc = GetComputerNameA(lpBuffer, lpnSize);
521
522 if (!rc)
523 {
524 if (GetLastError() == ERROR_BUFFER_OVERFLOW)
525 SetLastError(ERROR_MORE_DATA);
526 }
527
528 return rc;
529 }
530
531 if (gethostname(hostname, sizeof(hostname)) == -1)
532 return FALSE;
533
534 length = strnlen(hostname, sizeof(hostname));
535
536 switch (NameType)
537 {
538 case ComputerNameDnsHostname:
539 case ComputerNameDnsDomain:
540 case ComputerNameDnsFullyQualified:
541 case ComputerNamePhysicalDnsHostname:
542 case ComputerNamePhysicalDnsDomain:
543 case ComputerNamePhysicalDnsFullyQualified:
544 if ((*lpnSize <= (DWORD)length) || !lpBuffer)
545 {
546 *lpnSize = (DWORD)(length + 1);
547 SetLastError(ERROR_MORE_DATA);
548 return FALSE;
549 }
550
551 CopyMemory(lpBuffer, hostname, length);
552 lpBuffer[length] = '\0';
553 *lpnSize = (DWORD)length;
554 break;
555
556 default:
557 return FALSE;
558 }
559
560 return TRUE;
561}
562
563BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD lpnSize)
564{
565 BOOL rc = 0;
566 LPSTR lpABuffer = nullptr;
567
568 if (!lpnSize)
569 {
570 SetLastError(ERROR_BAD_ARGUMENTS);
571 return FALSE;
572 }
573
574 if (*lpnSize > 0)
575 {
576 lpABuffer = calloc(*lpnSize, sizeof(CHAR));
577
578 if (!lpABuffer)
579 return FALSE;
580 }
581
582 rc = GetComputerNameExA(NameType, lpABuffer, lpnSize);
583
584 if (rc && (*lpnSize > 0))
585 {
586 const SSIZE_T res = ConvertUtf8NToWChar(lpABuffer, *lpnSize, lpBuffer, *lpnSize);
587 rc = res > 0;
588 }
589
590 free(lpABuffer);
591 return rc;
592}
593
594#if defined(__linux__)
595
596static BOOL sysinfo_read_sysfs_string(const char* path, char* buffer, size_t size)
597{
598 FILE* fp = fopen(path, "r");
599 if (!fp)
600 return FALSE;
601
602 BOOL rc = FALSE;
603 if (fgets(buffer, WINPR_ASSERTING_INT_CAST(int, size), fp))
604 {
605 size_t len = strlen(buffer);
606 while ((len > 0) && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
607 buffer[--len] = '\0';
608 rc = TRUE;
609 }
610 else
611 {
612 WLog_ERR(TAG, "error reading string in %s", path);
613 }
614 (void)fclose(fp);
615 return rc;
616}
617
618static BOOL sysinfo_read_sysfs_int(const char* path, long long* value)
619{
620 char buffer[64] = WINPR_C_ARRAY_INIT;
621 if (!sysinfo_read_sysfs_string(path, buffer, sizeof(buffer)))
622 return FALSE;
623
624 char* end = nullptr;
625 const long long v = strtoll(buffer, &end, 10);
626 if (end == buffer)
627 return FALSE;
628
629 *value = v;
630 return TRUE;
631}
632
635static BOOL sysinfo_get_power_status_platform(LPSYSTEM_POWER_STATUS status)
636{
637 DIR* dir = opendir("/sys/class/power_supply");
638 if (!dir)
639 {
640 /* no power_supply class at all: treat as a desktop with no battery, AC power assumed -
641 * matches real Windows' behavior on a machine with no battery present */
642 status->ACLineStatus = AC_LINE_ONLINE;
643 status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
644 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
645 return TRUE;
646 }
647
648 BOOL haveBattery = FALSE;
649 BOOL onAC = FALSE;
650 BOOL charging = FALSE;
651 long long percent = -1;
652 long long energyNow = -1;
653 long long energyFull = -1;
654 long long timeToEmpty = -1;
655
656 struct dirent* entry = nullptr;
657 // NOLINTNEXTLINE(concurrency-mt-unsafe): dir is a local DIR*, not shared across threads
658 while ((entry = readdir(dir)) != nullptr)
659 {
660 char path[PATH_MAX] = WINPR_C_ARRAY_INIT;
661 char value[64] = WINPR_C_ARRAY_INIT;
662 long long v = 0;
663
664 if (entry->d_name[0] == '.')
665 continue;
666
667 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/type", entry->d_name);
668 if (!sysinfo_read_sysfs_string(path, value, sizeof(value)))
669 continue;
670
671 if (strcmp(value, "Battery") == 0)
672 {
673 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/present",
674 entry->d_name);
675 if (sysinfo_read_sysfs_int(path, &v) && (v == 0))
676 continue; /* battery slot present in sysfs, no battery physically installed */
677
678 haveBattery = TRUE;
679
680 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/status",
681 entry->d_name);
682 if (sysinfo_read_sysfs_string(path, value, sizeof(value)) &&
683 (strcmp(value, "Charging") == 0))
684 charging = TRUE;
685
686 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/capacity",
687 entry->d_name);
688 if (sysinfo_read_sysfs_int(path, &v))
689 percent = v;
690
691 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/time_to_empty_now",
692 entry->d_name);
693 if (sysinfo_read_sysfs_int(path, &v) && (v > 0))
694 timeToEmpty = v;
695
696 /* not every driver exposes "capacity" directly; fall back to computing it from
697 * energy_now/energy_full when present */
698 if (percent < 0)
699 {
700 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/energy_now",
701 entry->d_name);
702 (void)sysinfo_read_sysfs_int(path, &energyNow);
703 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/energy_full",
704 entry->d_name);
705 (void)sysinfo_read_sysfs_int(path, &energyFull);
706
707 if ((energyNow < 0) || (energyFull <= 0))
708 {
709 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/charge_now",
710 entry->d_name);
711 (void)sysinfo_read_sysfs_int(path, &energyNow);
712 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/charge_full",
713 entry->d_name);
714 (void)sysinfo_read_sysfs_int(path, &energyFull);
715 }
716
717 if ((energyNow >= 0) && (energyFull > 0))
718 percent = (energyNow * 100) / energyFull;
719 }
720 }
721 else
722 {
723 /* Mains / USB / Wireless: any of these reporting online means we're on AC power */
724 (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/online",
725 entry->d_name);
726 if (sysinfo_read_sysfs_int(path, &v) && (v != 0))
727 onAC = TRUE;
728 }
729 }
730 (void)closedir(dir);
731
732 if (!haveBattery)
733 {
734 status->ACLineStatus = AC_LINE_ONLINE;
735 status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
736 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
737 return TRUE;
738 }
739
740 status->ACLineStatus = (onAC || charging) ? AC_LINE_ONLINE : AC_LINE_OFFLINE;
741
742 BYTE flag = 0;
743 if (charging)
744 flag |= BATTERY_FLAG_CHARGING;
745
746 if (percent >= 0)
747 {
748 if (percent > 100)
749 percent = 100;
750 status->BatteryLifePercent = (BYTE)percent;
751
752 if (percent <= 5)
753 flag |= BATTERY_FLAG_CRITICAL;
754 else if (percent <= 33)
755 flag |= BATTERY_FLAG_LOW;
756 else if (percent > 66)
757 flag |= BATTERY_FLAG_HIGH;
758 }
759 else
760 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
761
762 status->BatteryFlag = flag ? flag : BATTERY_FLAG_UNKNOWN;
763
764 if (timeToEmpty > 0)
765 status->BatteryLifeTime = (DWORD)timeToEmpty;
766
767 return TRUE;
768}
769
770#elif defined(__MACOSX__)
771
772static BOOL sysinfo_get_power_status_platform(LPSYSTEM_POWER_STATUS status)
773{
774 BOOL rc = TRUE;
775 CFTypeRef blob = IOPSCopyPowerSourcesInfo();
776 if (!blob)
777 {
778 WLog_ERR(TAG, "unable to retrieve IOPSCopyPowerSourcesInfo()");
779 status->ACLineStatus = AC_LINE_ONLINE;
780 status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
781 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
782 return TRUE;
783 }
784
785 BOOL haveBattery = FALSE;
786 BOOL onAC = FALSE;
787 BOOL charging = FALSE;
788 int percent = -1;
789 int timeToEmptySeconds = -1;
790
791 CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
792 if (sources)
793 {
794 const CFIndex count = CFArrayGetCount(sources);
795 for (CFIndex i = 0; i < count; i++)
796 {
797 CFDictionaryRef desc =
798 IOPSGetPowerSourceDescription(blob, CFArrayGetValueAtIndex(sources, i));
799 if (!desc)
800 continue;
801
802 CFBooleanRef isPresent = CFDictionaryGetValue(desc, CFSTR(kIOPSIsPresentKey));
803 if (isPresent && (CFBooleanGetValue(isPresent) == false))
804 continue;
805
806 CFStringRef stateStr = CFDictionaryGetValue(desc, CFSTR(kIOPSPowerSourceStateKey));
807 if (stateStr &&
808 (CFStringCompare(stateStr, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo))
809 onAC = TRUE;
810
811 CFNumberRef curCapacity = CFDictionaryGetValue(desc, CFSTR(kIOPSCurrentCapacityKey));
812 CFNumberRef maxCapacity = CFDictionaryGetValue(desc, CFSTR(kIOPSMaxCapacityKey));
813 if (curCapacity && maxCapacity)
814 {
815 int cur = 0;
816 int max = 0;
817 CFNumberGetValue(curCapacity, kCFNumberIntType, &cur);
818 CFNumberGetValue(maxCapacity, kCFNumberIntType, &max);
819 if (max > 0)
820 {
821 haveBattery = TRUE;
822 percent = (int)(((long long)cur * 100) / max);
823 }
824 }
825
826 CFBooleanRef isCharging = CFDictionaryGetValue(desc, CFSTR(kIOPSIsChargingKey));
827 if (isCharging && CFBooleanGetValue(isCharging))
828 charging = TRUE;
829
830 CFNumberRef timeToEmpty = CFDictionaryGetValue(desc, CFSTR(kIOPSTimeToEmptyKey));
831 if (timeToEmpty)
832 {
833 int minutes = -1;
834 CFNumberGetValue(timeToEmpty, kCFNumberIntType, &minutes);
835 if (minutes > 0)
836 timeToEmptySeconds = minutes * 60;
837 }
838 }
839 CFRelease(sources);
840 }
841 CFRelease(blob);
842
843 if (!haveBattery)
844 {
845 status->ACLineStatus = AC_LINE_ONLINE;
846 status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
847 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
848 return rc;
849 }
850
851 status->ACLineStatus = onAC ? AC_LINE_ONLINE : AC_LINE_OFFLINE;
852
853 BYTE flag = 0;
854 if (charging)
855 flag |= BATTERY_FLAG_CHARGING;
856
857 if (percent >= 0)
858 {
859 if (percent > 100)
860 percent = 100;
861 status->BatteryLifePercent = (BYTE)percent;
862
863 if (percent <= 5)
864 flag |= BATTERY_FLAG_CRITICAL;
865 else if (percent <= 33)
866 flag |= BATTERY_FLAG_LOW;
867 else if (percent > 66)
868 flag |= BATTERY_FLAG_HIGH;
869 }
870 else
871 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
872
873 status->BatteryFlag = flag ? flag : BATTERY_FLAG_UNKNOWN;
874
875 if (timeToEmptySeconds > 0)
876 status->BatteryLifeTime = (DWORD)timeToEmptySeconds;
877
878 return rc;
879}
880
881#elif defined(__FreeBSD__)
882
883static BOOL sysinfo_sysctl_int(const char* name, int* value)
884{
885 size_t len = sizeof(*value);
886 return sysctlbyname(name, value, &len, nullptr, 0) == 0;
887}
888
889static BOOL sysinfo_get_power_status_platform(LPSYSTEM_POWER_STATUS status)
890{
891 int units = 0;
892 if (!sysinfo_sysctl_int("hw.acpi.battery.units", &units) || (units <= 0))
893 {
894 status->ACLineStatus = AC_LINE_ONLINE;
895 status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
896 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
897 return TRUE;
898 }
899
900 int acline = -1;
901 (void)sysinfo_sysctl_int("hw.acpi.acline", &acline);
902 status->ACLineStatus =
903 (acline == 1) ? AC_LINE_ONLINE : ((acline == 0) ? AC_LINE_OFFLINE : AC_LINE_UNKNOWN);
904
905 int life = -1;
906 (void)sysinfo_sysctl_int("hw.acpi.battery.life", &life);
907
908 int remaining = -1;
909 (void)sysinfo_sysctl_int("hw.acpi.battery.time", &remaining);
910
911 /* hw.acpi.battery.state bits mirror the ACPI _BST battery-state field:
912 * 1=discharging, 2=charging, 4=critical */
913 int state = 0;
914 (void)sysinfo_sysctl_int("hw.acpi.battery.state", &state);
915
916 BYTE flag = 0;
917 if (state & 0x2)
918 flag |= BATTERY_FLAG_CHARGING;
919 if (state & 0x4)
920 flag |= BATTERY_FLAG_CRITICAL;
921
922 if ((life >= 0) && (life <= 100))
923 {
924 status->BatteryLifePercent = (BYTE)life;
925 if (!(flag & BATTERY_FLAG_CRITICAL))
926 {
927 if (life <= 5)
928 flag |= BATTERY_FLAG_CRITICAL;
929 else if (life <= 33)
930 flag |= BATTERY_FLAG_LOW;
931 else if (life > 66)
932 flag |= BATTERY_FLAG_HIGH;
933 }
934 }
935 else
936 status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
937
938 status->BatteryFlag = flag ? flag : BATTERY_FLAG_UNKNOWN;
939
940 if (remaining > 0)
941 status->BatteryLifeTime = (DWORD)remaining * 60; /* minutes -> seconds */
942
943 return TRUE;
944}
945
946#endif
947
948BOOL GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus)
949{
950 if (!lpSystemPowerStatus)
951 {
952 SetLastError(ERROR_BAD_ARGUMENTS);
953 return FALSE;
954 }
955
956 /* safe, "no battery information available" defaults - overwritten below on platforms with a
957 * real backend */
958 lpSystemPowerStatus->ACLineStatus = AC_LINE_UNKNOWN;
959 lpSystemPowerStatus->BatteryFlag = BATTERY_FLAG_UNKNOWN;
960 lpSystemPowerStatus->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
961 lpSystemPowerStatus->SystemStatusFlag = 0;
962 lpSystemPowerStatus->BatteryLifeTime = BATTERY_LIFE_UNKNOWN;
963 lpSystemPowerStatus->BatteryFullLifeTime = BATTERY_LIFE_UNKNOWN;
964
965#if defined(__linux__) || defined(__MACOSX__) || defined(__FreeBSD__)
966 return sysinfo_get_power_status_platform(lpSystemPowerStatus);
967#else
968 WLog_WARN(TAG, "GetSystemPowerStatus is not implemented on this platform, reporting "
969 "\"no battery, unknown state\"");
970 return TRUE;
971#endif
972}
973
974#endif
975
976#if defined(_UWP)
977
978DWORD GetTickCount(void)
979{
980 return (DWORD)GetTickCount64();
981}
982
983#endif
984
985#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600))
986
987ULONGLONG winpr_GetTickCount64(void)
988{
989 const UINT64 ns = winpr_GetTickCount64NS();
990 return WINPR_TIME_NS_TO_MS(ns);
991}
992
993#endif
994
995UINT64 winpr_GetTickCount64NS(void)
996{
997 UINT64 ticks = 0;
998#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
999 struct timespec ts = WINPR_C_ARRAY_INIT;
1000
1001 if (clock_gettime(CLOCK_ID, &ts) == 0)
1002 ticks = (WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_sec) * 1000000000ull) +
1003 WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_nsec);
1004#elif defined(__MACH__) && defined(__APPLE__)
1005 ticks = mac_get_time_ns();
1006#elif defined(_WIN32)
1007 LARGE_INTEGER li = WINPR_C_ARRAY_INIT;
1008 LARGE_INTEGER freq = WINPR_C_ARRAY_INIT;
1009 if (QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&li))
1010 ticks = li.QuadPart * 1000000000ull / freq.QuadPart;
1011#else
1012 struct timeval tv = WINPR_C_ARRAY_INIT;
1013
1014 if (gettimeofday(&tv, nullptr) == 0)
1015 ticks = (tv.tv_sec * 1000000000ull) + (tv.tv_usec * 1000ull);
1016
1017 /* We need to trick here:
1018 * this function should return the system uptime, but we need higher resolution.
1019 * so on first call get the actual timestamp along with the system uptime.
1020 *
1021 * return the uptime measured from now on (e.g. current measure - first measure + uptime at
1022 * first measure)
1023 */
1024 static UINT64 first = 0;
1025 static UINT64 uptime = 0;
1026 if (first == 0)
1027 {
1028 struct sysinfo info = WINPR_C_ARRAY_INIT;
1029 if (sysinfo(&info) == 0)
1030 {
1031 first = ticks;
1032 uptime = 1000000000ull * info.uptime;
1033 }
1034 }
1035
1036 ticks = ticks - first + uptime;
1037#endif
1038 return ticks;
1039}
1040
1041UINT64 winpr_GetUnixTimeNS(void)
1042{
1043#if defined(_WIN32)
1044
1045 union
1046 {
1047 UINT64 u64;
1048 FILETIME ft;
1049 } t = WINPR_C_ARRAY_INIT;
1050 GetSystemTimeAsFileTime(&t.ft);
1051 return (t.u64 - FILETIME_TO_UNIX_OFFSET_S * 10000000ull) * 100ull;
1052#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
1053 struct timespec ts = WINPR_C_ARRAY_INIT;
1054 if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
1055 return 0;
1056 return WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_sec) * 1000000000ull +
1057 WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_nsec);
1058#else
1059 struct timeval tv = WINPR_C_ARRAY_INIT;
1060 if (gettimeofday(&tv, nullptr) != 0)
1061 return 0;
1062 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000ull;
1063#endif
1064}
1065
1066/* If x86 */
1067#ifdef _M_IX86_AMD64
1068
1069#if defined(__GNUC__)
1070#define xgetbv(_func_, _lo_, _hi_) \
1071 __asm__ __volatile__("xgetbv" : "=a"(_lo_), "=d"(_hi_) : "c"(_func_))
1072#elif defined(_MSC_VER)
1073#define xgetbv(_func_, _lo_, _hi_) \
1074 { \
1075 unsigned __int64 val = _xgetbv(_func_); \
1076 _lo_ = val & 0xFFFFFFFF; \
1077 _hi_ = (val >> 32); \
1078 }
1079#endif
1080
1081#define B_BIT_AVX2 (1 << 5)
1082#define B_BIT_AVX512F (1 << 16)
1083#define D_BIT_MMX (1 << 23)
1084#define D_BIT_SSE (1 << 25)
1085#define D_BIT_SSE2 (1 << 26)
1086#define D_BIT_3DN (1 << 30)
1087// #define C_BIT_SSE3 (1 << 0)
1088#define C_BIT_PCLMULQDQ (1 << 1)
1089#define C81_BIT_LZCNT (1 << 5)
1090// #define C_BIT_3DNP (1 << 8)
1091#define C_BIT_3DNP (1 << 8)
1092#define C_BIT_SSSE3 (1 << 9)
1093#define C_BIT_SSE41 (1 << 19)
1094#define C_BIT_SSE42 (1 << 20)
1095#define C_BIT_FMA (1 << 12)
1096#define C_BIT_AES (1 << 25)
1097#define C_BIT_XGETBV (1 << 27)
1098#define C_BIT_AVX (1 << 28)
1099#define E_BIT_XMM (1 << 1)
1100#define E_BIT_YMM (1 << 2)
1101#define E_BITS_AVX (E_BIT_XMM | E_BIT_YMM)
1102
1103static void cpuid(unsigned info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx)
1104{
1105#ifdef __GNUC__
1106 *eax = *ebx = *ecx = *edx = 0;
1107 __asm volatile(
1108 /* The EBX (or RBX register on x86_64) is used for the PIC base address
1109 * and must not be corrupted by our inline assembly.
1110 */
1111#ifdef _M_IX86
1112 "mov %%ebx, %%esi;"
1113 "cpuid;"
1114 "xchg %%ebx, %%esi;"
1115#else
1116 "mov %%rbx, %%rsi;"
1117 "cpuid;"
1118 "xchg %%rbx, %%rsi;"
1119#endif
1120 : "=a"(*eax), "=S"(*ebx), "=c"(*ecx), "=d"(*edx)
1121 : "a"(info), "c"(0));
1122#elif defined(_MSC_VER)
1123 int a[4];
1124 __cpuid(a, info);
1125 *eax = a[0];
1126 *ebx = a[1];
1127 *ecx = a[2];
1128 *edx = a[3];
1129#endif
1130}
1131#elif defined(_M_ARM) || defined(_M_ARM64)
1132#if defined(__linux__)
1133// HWCAP flags from linux kernel - uapi/asm/hwcap.h
1134#define HWCAP_SWP (1 << 0)
1135#define HWCAP_HALF (1 << 1)
1136#define HWCAP_THUMB (1 << 2)
1137#define HWCAP_26BIT (1 << 3) /* Play it safe */
1138#define HWCAP_FAST_MULT (1 << 4)
1139#define HWCAP_FPA (1 << 5)
1140#define HWCAP_VFP (1 << 6)
1141#define HWCAP_EDSP (1 << 7)
1142#define HWCAP_JAVA (1 << 8)
1143#define HWCAP_IWMMXT (1 << 9)
1144#define HWCAP_CRUNCH (1 << 10)
1145#define HWCAP_THUMBEE (1 << 11)
1146#define HWCAP_NEON (1 << 12)
1147#define HWCAP_VFPv3 (1 << 13)
1148#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
1149#define HWCAP_TLS (1 << 15)
1150#define HWCAP_VFPv4 (1 << 16)
1151#define HWCAP_IDIVA (1 << 17)
1152#define HWCAP_IDIVT (1 << 18)
1153#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
1154#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
1155
1156// From linux kernel uapi/linux/auxvec.h
1157#define AT_HWCAP 16
1158
1159static unsigned GetARMCPUCaps(void)
1160{
1161 unsigned caps = 0;
1162 int fd = open("/proc/self/auxv", O_RDONLY);
1163
1164 if (fd == -1)
1165 return 0;
1166
1167 static struct
1168 {
1169 unsigned a_type; /* Entry type */
1170 unsigned a_val; /* Integer value */
1171 } auxvec;
1172
1173 while (1)
1174 {
1175 int num;
1176 num = read(fd, (char*)&auxvec, sizeof(auxvec));
1177
1178 if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0))
1179 break;
1180
1181 if (auxvec.a_type == AT_HWCAP)
1182 {
1183 caps = auxvec.a_val;
1184 }
1185 }
1186
1187 close(fd);
1188 return caps;
1189}
1190
1191#endif // defined(__linux__)
1192#endif // _M_IX86_AMD64
1193
1194#ifndef _WIN32
1195
1196#if defined(_M_ARM) || defined(_M_ARM64)
1197#ifdef __linux__
1198#include <sys/auxv.h>
1199#endif
1200#endif
1201
1202BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
1203{
1204 BOOL ret = FALSE;
1205#if defined(ANDROID)
1206 const uint64_t features = android_getCpuFeatures();
1207 const AndroidCpuFamily family = android_getCpuFamily();
1208 const BOOL isArm = (family == ANDROID_CPU_FAMILY_ARM) || (family == ANDROID_CPU_FAMILY_ARM64);
1209 const BOOL isX86 = (family == ANDROID_CPU_FAMILY_X86) || (family == ANDROID_CPU_FAMILY_X86_64);
1210
1211 if (isX86)
1212 {
1213 switch (ProcessorFeature)
1214 {
1215 case PF_MMX_INSTRUCTIONS_AVAILABLE:
1216 case PF_XMMI_INSTRUCTIONS_AVAILABLE:
1217 case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
1218 case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1219 case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1220 return TRUE;
1221 case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
1222 return features & ANDROID_CPU_X86_FEATURE_SSSE3;
1223 case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
1224 return features & ANDROID_CPU_X86_FEATURE_SSE4_1;
1225 case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
1226 return features & ANDROID_CPU_X86_FEATURE_SSE4_2;
1227 case PF_AVX_INSTRUCTIONS_AVAILABLE:
1228 return features & ANDROID_CPU_X86_FEATURE_AVX;
1229 case PF_AVX2_INSTRUCTIONS_AVAILABLE:
1230 return features & ANDROID_CPU_X86_FEATURE_AVX2;
1231 case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
1232 default:
1233 WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1234 return FALSE;
1235 }
1236 }
1237
1238 if (isArm)
1239 {
1240 switch (ProcessorFeature)
1241 {
1242 case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
1243 case PF_ARM_NEON:
1244 return features & ANDROID_CPU_ARM_FEATURE_NEON;
1245
1246 default:
1247 WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1248 return FALSE;
1249 }
1250 }
1251
1252 WLog_WARN(TAG, "Unsupported Android CPU family 0x%08" PRIx32, family);
1253 return FALSE;
1254
1255#elif defined(_M_ARM) || defined(_M_ARM64)
1256#ifdef __linux__
1257 const unsigned long caps = getauxval(AT_HWCAP);
1258
1259 switch (ProcessorFeature)
1260 {
1261 case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
1262 case PF_ARM_NEON:
1263
1264 if (caps & HWCAP_NEON)
1265 ret = TRUE;
1266
1267 break;
1268
1269 case PF_ARM_THUMB:
1270 if (caps & HWCAP_THUMB)
1271 ret = TRUE;
1272
1273 case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
1274 if (caps & HWCAP_VFPD32)
1275 ret = TRUE;
1276
1277 case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
1278 if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
1279 ret = TRUE;
1280
1281 case PF_ARM_VFP3:
1282 if (caps & HWCAP_VFPv3)
1283 ret = TRUE;
1284
1285 break;
1286
1287 case PF_ARM_JAZELLE:
1288 if (caps & HWCAP_JAVA)
1289 ret = TRUE;
1290
1291 break;
1292
1293 case PF_ARM_DSP:
1294 if (caps & HWCAP_EDSP)
1295 ret = TRUE;
1296
1297 break;
1298
1299 case PF_ARM_MPU:
1300 if (caps & HWCAP_EDSP)
1301 ret = TRUE;
1302
1303 break;
1304
1305 case PF_ARM_THUMB2:
1306 if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
1307 ret = TRUE;
1308
1309 break;
1310
1311 case PF_ARM_T2EE:
1312 if (caps & HWCAP_THUMBEE)
1313 ret = TRUE;
1314
1315 break;
1316
1317 case PF_ARM_INTEL_WMMX:
1318 if (caps & HWCAP_IWMMXT)
1319 ret = TRUE;
1320
1321 break;
1322 case PF_MMX_INSTRUCTIONS_AVAILABLE:
1323 case PF_XMMI_INSTRUCTIONS_AVAILABLE:
1324 case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
1325 case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1326 case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1327 case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
1328 case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
1329 case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
1330 case PF_AVX_INSTRUCTIONS_AVAILABLE:
1331 case PF_AVX2_INSTRUCTIONS_AVAILABLE:
1332 case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
1333 ret = FALSE;
1334 break;
1335 case PF_ARM_V8_INSTRUCTIONS_AVAILABLE:
1336 case PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE:
1337 case PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE:
1338 case PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE:
1339 case PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE:
1340 case PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE:
1341 case PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE:
1342 default:
1343 WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1344 break;
1345 }
1346
1347#else // __linux__
1348
1349 switch (ProcessorFeature)
1350 {
1351 case PF_MMX_INSTRUCTIONS_AVAILABLE:
1352 case PF_XMMI_INSTRUCTIONS_AVAILABLE:
1353 case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
1354 case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1355 case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1356 case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
1357 case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
1358 case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
1359 case PF_AVX_INSTRUCTIONS_AVAILABLE:
1360 case PF_AVX2_INSTRUCTIONS_AVAILABLE:
1361 case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
1362 ret = FALSE;
1363 break;
1364 case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
1365 case PF_ARM_NEON:
1366#ifdef __ARM_NEON
1367 ret = TRUE;
1368#endif
1369 break;
1370 case PF_ARM_V8_INSTRUCTIONS_AVAILABLE:
1371 case PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE:
1372 case PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE:
1373 case PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE:
1374 case PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE:
1375 case PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE:
1376 case PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE:
1377 default:
1378 WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1379 break;
1380 }
1381
1382#endif // __linux__
1383#endif
1384
1385#if defined(_M_IX86_AMD64)
1386#ifdef __GNUC__
1387 unsigned a = 0;
1388 unsigned b = 0;
1389 unsigned c = 0;
1390 unsigned d = 0;
1391 cpuid(1, &a, &b, &c, &d);
1392
1393 switch (ProcessorFeature)
1394 {
1395 case PF_MMX_INSTRUCTIONS_AVAILABLE:
1396 if (d & D_BIT_MMX)
1397 ret = TRUE;
1398
1399 break;
1400
1401 case PF_XMMI_INSTRUCTIONS_AVAILABLE:
1402 if (d & D_BIT_SSE)
1403 ret = TRUE;
1404
1405 break;
1406
1407 case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
1408 if (d & D_BIT_SSE2)
1409 ret = TRUE;
1410
1411 break;
1412
1413 case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1414 if (d & D_BIT_3DN)
1415 ret = TRUE;
1416
1417 break;
1418
1419 case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1420 ret = __builtin_cpu_supports("sse3");
1421 break;
1422
1423 case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
1424 ret = __builtin_cpu_supports("ssse3");
1425 break;
1426 case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
1427 ret = __builtin_cpu_supports("sse4.1");
1428 break;
1429 case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
1430 ret = __builtin_cpu_supports("sse4.2");
1431 break;
1432 case PF_AVX_INSTRUCTIONS_AVAILABLE:
1433 ret = __builtin_cpu_supports("avx");
1434 break;
1435 case PF_AVX2_INSTRUCTIONS_AVAILABLE:
1436 ret = __builtin_cpu_supports("avx2");
1437 break;
1438 case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
1439 ret = __builtin_cpu_supports("avx512f");
1440 break;
1441 case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
1442#if defined(__ARM_NEON__)
1443 ret = TRUE;
1444#endif
1445 break;
1446 default:
1447 WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1448 break;
1449 }
1450
1451#endif // __GNUC__
1452#endif
1453
1454#if defined(_M_E2K)
1455 /* compiler flags on e2k arch determine CPU features */
1456 switch (ProcessorFeature)
1457 {
1458 case PF_MMX_INSTRUCTIONS_AVAILABLE:
1459#ifdef __MMX__
1460 ret = TRUE;
1461#endif
1462 break;
1463
1464 case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1465#ifdef __3dNOW__
1466 ret = TRUE;
1467#endif
1468 break;
1469
1470 case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1471#ifdef __SSE3__
1472 ret = TRUE;
1473#endif
1474 break;
1475
1476 default:
1477 break;
1478 }
1479
1480#endif
1481 return ret;
1482}
1483
1484#endif //_WIN32
1485
1486DWORD GetTickCountPrecise(void)
1487{
1488#ifdef _WIN32
1489 LARGE_INTEGER freq = WINPR_C_ARRAY_INIT;
1490 LARGE_INTEGER current = WINPR_C_ARRAY_INIT;
1491 QueryPerformanceFrequency(&freq);
1492 QueryPerformanceCounter(&current);
1493 return (DWORD)(current.QuadPart * 1000LL / freq.QuadPart);
1494#else
1495 return GetTickCount();
1496#endif
1497}
1498
1499BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
1500{
1501 BOOL ret = FALSE;
1502#if defined(_M_ARM) || defined(_M_ARM64)
1503#ifdef __linux__
1504 unsigned caps;
1505 caps = GetARMCPUCaps();
1506
1507 switch (ProcessorFeature)
1508 {
1509 case PF_EX_ARM_VFP1:
1510 if (caps & HWCAP_VFP)
1511 ret = TRUE;
1512
1513 break;
1514
1515 case PF_EX_ARM_VFP3D16:
1516 if (caps & HWCAP_VFPv3D16)
1517 ret = TRUE;
1518
1519 break;
1520
1521 case PF_EX_ARM_VFP4:
1522 if (caps & HWCAP_VFPv4)
1523 ret = TRUE;
1524
1525 break;
1526
1527 case PF_EX_ARM_IDIVA:
1528 if (caps & HWCAP_IDIVA)
1529 ret = TRUE;
1530
1531 break;
1532
1533 case PF_EX_ARM_IDIVT:
1534 if (caps & HWCAP_IDIVT)
1535 ret = TRUE;
1536
1537 break;
1538 }
1539
1540#endif // __linux__
1541#elif defined(_M_IX86_AMD64)
1542 unsigned a = 0;
1543 unsigned b = 0;
1544 unsigned c = 0;
1545 unsigned d = 0;
1546 cpuid(1, &a, &b, &c, &d);
1547
1548 switch (ProcessorFeature)
1549 {
1550 case PF_EX_LZCNT:
1551 {
1552 unsigned a81 = 0;
1553 unsigned b81 = 0;
1554 unsigned c81 = 0;
1555 unsigned d81 = 0;
1556 cpuid(0x80000001, &a81, &b81, &c81, &d81);
1557
1558 if (c81 & C81_BIT_LZCNT)
1559 ret = TRUE;
1560 }
1561 break;
1562
1563 case PF_EX_3DNOW_PREFETCH:
1564 if (c & C_BIT_3DNP)
1565 ret = TRUE;
1566
1567 break;
1568
1569 case PF_EX_SSSE3:
1570 if (c & C_BIT_SSSE3)
1571 ret = TRUE;
1572
1573 break;
1574
1575 case PF_EX_SSE41:
1576 if (c & C_BIT_SSE41)
1577 ret = TRUE;
1578
1579 break;
1580
1581 case PF_EX_SSE42:
1582 if (c & C_BIT_SSE42)
1583 ret = TRUE;
1584
1585 break;
1586#if defined(__GNUC__) || defined(_MSC_VER)
1587
1588 case PF_EX_AVX:
1589 case PF_EX_AVX2:
1590 case PF_EX_AVX512F:
1591 case PF_EX_FMA:
1592 case PF_EX_AVX_AES:
1593 case PF_EX_AVX_PCLMULQDQ:
1594 {
1595 /* Check for general AVX support */
1596 if (!(c & C_BIT_AVX))
1597 break;
1598
1599 /* Check for xgetbv support */
1600 if (!(c & C_BIT_XGETBV))
1601 break;
1602
1603 int e = 0;
1604 int f = 0;
1605 xgetbv(0, e, f);
1606
1607 /* XGETBV enabled for applications and XMM/YMM states enabled */
1608 if ((e & E_BITS_AVX) == E_BITS_AVX)
1609 {
1610 switch (ProcessorFeature)
1611 {
1612 case PF_EX_AVX:
1613 ret = TRUE;
1614 break;
1615
1616 case PF_EX_AVX2:
1617 case PF_EX_AVX512F:
1618 cpuid(7, &a, &b, &c, &d);
1619 switch (ProcessorFeature)
1620 {
1621 case PF_EX_AVX2:
1622 if (b & B_BIT_AVX2)
1623 ret = TRUE;
1624 break;
1625
1626 case PF_EX_AVX512F:
1627 if (b & B_BIT_AVX512F)
1628 ret = TRUE;
1629 break;
1630
1631 default:
1632 break;
1633 }
1634 break;
1635
1636 case PF_EX_FMA:
1637 if (c & C_BIT_FMA)
1638 ret = TRUE;
1639
1640 break;
1641
1642 case PF_EX_AVX_AES:
1643 if (c & C_BIT_AES)
1644 ret = TRUE;
1645
1646 break;
1647
1648 case PF_EX_AVX_PCLMULQDQ:
1649 if (c & C_BIT_PCLMULQDQ)
1650 ret = TRUE;
1651
1652 break;
1653 default:
1654 break;
1655 }
1656 }
1657 }
1658 break;
1659#endif // __GNUC__ || _MSC_VER
1660
1661 default:
1662 break;
1663 }
1664#elif defined(_M_E2K)
1665 /* compiler flags on e2k arch determine CPU features */
1666 switch (ProcessorFeature)
1667 {
1668 case PF_EX_LZCNT:
1669#ifdef __LZCNT__
1670 ret = TRUE;
1671#endif
1672 break;
1673
1674 case PF_EX_SSSE3:
1675#ifdef __SSSE3__
1676 ret = TRUE;
1677#endif
1678 break;
1679
1680 case PF_EX_SSE41:
1681#ifdef __SSE4_1__
1682 ret = TRUE;
1683#endif
1684 break;
1685
1686 case PF_EX_SSE42:
1687#ifdef __SSE4_2__
1688 ret = TRUE;
1689#endif
1690 break;
1691
1692 case PF_EX_AVX:
1693#ifdef __AVX__
1694 ret = TRUE;
1695#endif
1696 break;
1697
1698 case PF_EX_AVX2:
1699#ifdef __AVX2__
1700 ret = TRUE;
1701#endif
1702 break;
1703
1704 case PF_EX_FMA:
1705#ifdef __FMA__
1706 ret = TRUE;
1707#endif
1708 break;
1709
1710 default:
1711 break;
1712 }
1713#endif
1714 return ret;
1715}
mirrors the real Win32 SYSTEM_POWER_STATUS struct.
Definition sysinfo.h:368