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