Coverage Report

Created: 2026-09-14 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/sysinfo/sysinfo.c
Line
Count
Source
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * System Information
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
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
0
#define FILETIME_TO_UNIX_OFFSET_S 11644473600UL
63
64
#if defined(__MACH__) && defined(__APPLE__)
65
66
#include <mach/mach_time.h>
67
68
static 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
77
static 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
87
/**
88
 * api-ms-win-core-sysinfo-l1-1-1.dll:
89
 *
90
 * EnumSystemFirmwareTables
91
 * GetSystemFirmwareTable
92
 * GetLogicalProcessorInformation
93
 * GetLogicalProcessorInformationEx
94
 * GetProductInfo
95
 * GetSystemDirectoryA
96
 * GetSystemDirectoryW
97
 * GetSystemTimeAdjustment
98
 * GetSystemWindowsDirectoryA
99
 * GetSystemWindowsDirectoryW
100
 * GetWindowsDirectoryA
101
 * GetWindowsDirectoryW
102
 * GlobalMemoryStatusEx
103
 * SetComputerNameExW
104
 * VerSetConditionMask
105
 */
106
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
123
static WORD GetProcessorArchitecture(void)
124
0
{
125
0
  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
0
  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
0
  return cpuArch;
197
0
}
198
199
static DWORD GetNumberOfProcessors(void)
200
0
{
201
0
  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
0
  numCPUs = (DWORD)sysconf(_SC_NPROCESSORS_ONLN);
216
0
#endif
217
0
  return numCPUs;
218
0
}
219
220
static DWORD GetSystemPageSize(void)
221
0
{
222
0
  DWORD dwPageSize = 0;
223
0
  long sc_page_size = -1;
224
0
#if defined(_SC_PAGESIZE)
225
226
0
  if (sc_page_size < 0)
227
0
    sc_page_size = sysconf(_SC_PAGESIZE);
228
229
0
#endif
230
0
#if defined(_SC_PAGE_SIZE)
231
232
0
  if (sc_page_size < 0)
233
0
    sc_page_size = sysconf(_SC_PAGE_SIZE);
234
235
0
#endif
236
237
0
  if (sc_page_size > 0)
238
0
    dwPageSize = (DWORD)sc_page_size;
239
240
0
  if (dwPageSize < 4096)
241
0
    dwPageSize = 4096;
242
243
0
  return dwPageSize;
244
0
}
245
246
void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
247
0
{
248
0
  const SYSTEM_INFO empty = WINPR_C_ARRAY_INIT;
249
0
  WINPR_ASSERT(lpSystemInfo);
250
251
0
  *lpSystemInfo = empty;
252
0
  lpSystemInfo->DUMMYUNIONNAME.DUMMYSTRUCTNAME.wProcessorArchitecture =
253
0
      GetProcessorArchitecture();
254
0
  lpSystemInfo->dwPageSize = GetSystemPageSize();
255
0
  lpSystemInfo->dwNumberOfProcessors = GetNumberOfProcessors();
256
0
}
257
258
void GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
259
0
{
260
0
  GetSystemInfo(lpSystemInfo);
261
0
}
262
263
void GetSystemTime(LPSYSTEMTIME lpSystemTime)
264
0
{
265
0
  time_t ct = 0;
266
0
  struct tm tres;
267
0
  struct tm* stm = nullptr;
268
0
  WORD wMilliseconds = 0;
269
0
  UINT64 now = winpr_GetUnixTimeNS();
270
0
  ct = WINPR_TIME_NS_TO_S(now);
271
0
  wMilliseconds = (WORD)(WINPR_TIME_NS_REM_MS(now));
272
0
  stm = gmtime_r(&ct, &tres);
273
0
  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
274
275
0
  if (stm)
276
0
  {
277
0
    lpSystemTime->wYear = (WORD)(stm->tm_year + 1900);
278
0
    lpSystemTime->wMonth = (WORD)(stm->tm_mon + 1);
279
0
    lpSystemTime->wDayOfWeek = (WORD)stm->tm_wday;
280
0
    lpSystemTime->wDay = (WORD)stm->tm_mday;
281
0
    lpSystemTime->wHour = (WORD)stm->tm_hour;
282
0
    lpSystemTime->wMinute = (WORD)stm->tm_min;
283
0
    lpSystemTime->wSecond = (WORD)stm->tm_sec;
284
0
    lpSystemTime->wMilliseconds = wMilliseconds;
285
0
  }
286
0
}
287
288
BOOL SetSystemTime(WINPR_ATTR_UNUSED CONST SYSTEMTIME* lpSystemTime)
289
0
{
290
  /* TODO: Implement */
291
0
  WLog_ERR("TODO", "TODO: Implement");
292
0
  return FALSE;
293
0
}
294
295
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
296
0
{
297
0
  time_t ct = 0;
298
0
  struct tm tres;
299
0
  struct tm* ltm = nullptr;
300
0
  WORD wMilliseconds = 0;
301
0
  UINT64 now = winpr_GetUnixTimeNS();
302
0
  ct = WINPR_TIME_NS_TO_S(now);
303
0
  wMilliseconds = (WORD)(WINPR_TIME_NS_REM_MS(now));
304
0
  ltm = localtime_r(&ct, &tres);
305
0
  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
306
307
0
  if (ltm)
308
0
  {
309
0
    lpSystemTime->wYear = (WORD)(ltm->tm_year + 1900);
310
0
    lpSystemTime->wMonth = (WORD)(ltm->tm_mon + 1);
311
0
    lpSystemTime->wDayOfWeek = (WORD)ltm->tm_wday;
312
0
    lpSystemTime->wDay = (WORD)ltm->tm_mday;
313
0
    lpSystemTime->wHour = (WORD)ltm->tm_hour;
314
0
    lpSystemTime->wMinute = (WORD)ltm->tm_min;
315
0
    lpSystemTime->wSecond = (WORD)ltm->tm_sec;
316
0
    lpSystemTime->wMilliseconds = wMilliseconds;
317
0
  }
318
0
}
319
320
BOOL SetLocalTime(WINPR_ATTR_UNUSED CONST SYSTEMTIME* lpSystemTime)
321
0
{
322
  /* TODO: Implement */
323
0
  WLog_ERR("TODO", "TODO: Implement");
324
0
  return FALSE;
325
0
}
326
327
VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
328
0
{
329
0
  union
330
0
  {
331
0
    UINT64 u64;
332
0
    FILETIME ft;
333
0
  } t;
334
335
0
  t.u64 = (winpr_GetUnixTimeNS() / 100ull) + FILETIME_TO_UNIX_OFFSET_S * 10000000ull;
336
0
  *lpSystemTimeAsFileTime = t.ft;
337
0
}
338
339
BOOL GetSystemTimeAdjustment(WINPR_ATTR_UNUSED PDWORD lpTimeAdjustment,
340
                             WINPR_ATTR_UNUSED PDWORD lpTimeIncrement,
341
                             WINPR_ATTR_UNUSED PBOOL lpTimeAdjustmentDisabled)
342
0
{
343
  /* TODO: Implement */
344
0
  WLog_ERR("TODO", "TODO: Implement");
345
0
  return FALSE;
346
0
}
347
348
#ifdef CLOCK_MONOTONIC_RAW
349
0
#define CLOCK_ID CLOCK_MONOTONIC_RAW
350
#else
351
#define CLOCK_ID CLOCK_MONOTONIC
352
#endif
353
354
DWORD GetTickCount(void)
355
0
{
356
0
  return (DWORD)GetTickCount64();
357
0
}
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
367
BOOL 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
423
BOOL 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
435
BOOL GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
436
0
{
437
0
  BOOL rc = 0;
438
0
  LPSTR buffer = nullptr;
439
0
  if (!lpnSize || (*lpnSize > INT_MAX))
440
0
    return FALSE;
441
442
0
  if (*lpnSize > 0)
443
0
  {
444
0
    buffer = malloc(*lpnSize);
445
0
    if (!buffer)
446
0
      return FALSE;
447
0
  }
448
0
  rc = GetComputerNameA(buffer, lpnSize);
449
450
0
  if (rc && (*lpnSize > 0))
451
0
  {
452
0
    const SSIZE_T res = ConvertUtf8NToWChar(buffer, *lpnSize, lpBuffer, *lpnSize);
453
0
    rc = res > 0;
454
0
  }
455
456
0
  free(buffer);
457
458
0
  return rc;
459
0
}
460
461
BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize)
462
0
{
463
0
  if (!lpnSize)
464
0
  {
465
0
    SetLastError(ERROR_BAD_ARGUMENTS);
466
0
    return FALSE;
467
0
  }
468
469
0
  char hostname[256 + 1] = WINPR_C_ARRAY_INIT;
470
0
  if (gethostname(hostname, ARRAYSIZE(hostname) - 1) == -1)
471
0
    return FALSE;
472
473
0
  size_t length = strnlen(hostname, MAX_COMPUTERNAME_LENGTH);
474
0
  const char* dot = strchr(hostname, '.');
475
0
  if (dot)
476
0
  {
477
0
    const size_t dotlen = WINPR_ASSERTING_INT_CAST(size_t, (dot - hostname));
478
0
    if (dotlen < length)
479
0
      length = dotlen;
480
0
  }
481
482
0
  if ((*lpnSize <= (DWORD)length) || !lpBuffer)
483
0
  {
484
0
    SetLastError(ERROR_BUFFER_OVERFLOW);
485
0
    *lpnSize = (DWORD)(length + 1);
486
0
    return FALSE;
487
0
  }
488
489
0
  strncpy(lpBuffer, hostname, length);
490
0
  lpBuffer[length] = '\0';
491
0
  *lpnSize = (DWORD)length;
492
0
  return TRUE;
493
0
}
494
495
BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD lpnSize)
496
0
{
497
0
  size_t length = 0;
498
0
  char hostname[256] = WINPR_C_ARRAY_INIT;
499
500
0
  if (!lpnSize)
501
0
  {
502
0
    SetLastError(ERROR_BAD_ARGUMENTS);
503
0
    return FALSE;
504
0
  }
505
506
0
  if ((NameType == ComputerNameNetBIOS) || (NameType == ComputerNamePhysicalNetBIOS))
507
0
  {
508
0
    BOOL rc = GetComputerNameA(lpBuffer, lpnSize);
509
510
0
    if (!rc)
511
0
    {
512
0
      if (GetLastError() == ERROR_BUFFER_OVERFLOW)
513
0
        SetLastError(ERROR_MORE_DATA);
514
0
    }
515
516
0
    return rc;
517
0
  }
518
519
0
  if (gethostname(hostname, sizeof(hostname)) == -1)
520
0
    return FALSE;
521
522
0
  length = strnlen(hostname, sizeof(hostname));
523
524
0
  switch (NameType)
525
0
  {
526
0
    case ComputerNameDnsHostname:
527
0
    case ComputerNameDnsDomain:
528
0
    case ComputerNameDnsFullyQualified:
529
0
    case ComputerNamePhysicalDnsHostname:
530
0
    case ComputerNamePhysicalDnsDomain:
531
0
    case ComputerNamePhysicalDnsFullyQualified:
532
0
      if ((*lpnSize <= (DWORD)length) || !lpBuffer)
533
0
      {
534
0
        *lpnSize = (DWORD)(length + 1);
535
0
        SetLastError(ERROR_MORE_DATA);
536
0
        return FALSE;
537
0
      }
538
539
0
      CopyMemory(lpBuffer, hostname, length);
540
0
      lpBuffer[length] = '\0';
541
0
      *lpnSize = (DWORD)length;
542
0
      break;
543
544
0
    default:
545
0
      return FALSE;
546
0
  }
547
548
0
  return TRUE;
549
0
}
550
551
BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD lpnSize)
552
0
{
553
0
  BOOL rc = 0;
554
0
  LPSTR lpABuffer = nullptr;
555
556
0
  if (!lpnSize)
557
0
  {
558
0
    SetLastError(ERROR_BAD_ARGUMENTS);
559
0
    return FALSE;
560
0
  }
561
562
0
  if (*lpnSize > 0)
563
0
  {
564
0
    lpABuffer = calloc(*lpnSize, sizeof(CHAR));
565
566
0
    if (!lpABuffer)
567
0
      return FALSE;
568
0
  }
569
570
0
  rc = GetComputerNameExA(NameType, lpABuffer, lpnSize);
571
572
0
  if (rc && (*lpnSize > 0))
573
0
  {
574
0
    const SSIZE_T res = ConvertUtf8NToWChar(lpABuffer, *lpnSize, lpBuffer, *lpnSize);
575
0
    rc = res > 0;
576
0
  }
577
578
0
  free(lpABuffer);
579
0
  return rc;
580
0
}
581
582
#if defined(__linux__)
583
584
static BOOL sysinfo_read_sysfs_string(const char* path, char* buffer, size_t size)
585
0
{
586
0
  FILE* fp = fopen(path, "r");
587
0
  if (!fp)
588
0
    return FALSE;
589
590
0
  BOOL rc = FALSE;
591
0
  if (fgets(buffer, WINPR_ASSERTING_INT_CAST(int, size), fp))
592
0
  {
593
0
    size_t len = strlen(buffer);
594
0
    while ((len > 0) && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
595
0
      buffer[--len] = '\0';
596
0
    rc = TRUE;
597
0
  }
598
0
  else
599
0
  {
600
0
    WLog_ERR(TAG, "error reading string in %s", path);
601
0
  }
602
0
  (void)fclose(fp);
603
0
  return rc;
604
0
}
605
606
static BOOL sysinfo_read_sysfs_int(const char* path, long long* value)
607
0
{
608
0
  char buffer[64] = WINPR_C_ARRAY_INIT;
609
0
  if (!sysinfo_read_sysfs_string(path, buffer, sizeof(buffer)))
610
0
    return FALSE;
611
612
0
  char* end = nullptr;
613
0
  const long long v = strtoll(buffer, &end, 10);
614
0
  if (end == buffer)
615
0
    return FALSE;
616
617
0
  *value = v;
618
0
  return TRUE;
619
0
}
620
621
/** @brief reads /sys/class/power_supply/, the same kernel interface on both desktop Linux and
622
 *  Android (no ANDROID-specific carve-out needed: Android exposes the identical sysfs nodes). */
623
static BOOL sysinfo_get_power_status_platform(LPSYSTEM_POWER_STATUS status)
624
0
{
625
0
  DIR* dir = opendir("/sys/class/power_supply");
626
0
  if (!dir)
627
0
  {
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
0
    status->ACLineStatus = AC_LINE_ONLINE;
631
0
    status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
632
0
    status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
633
0
    return TRUE;
634
0
  }
635
636
0
  BOOL haveBattery = FALSE;
637
0
  BOOL onAC = FALSE;
638
0
  BOOL charging = FALSE;
639
0
  long long percent = -1;
640
0
  long long energyNow = -1;
641
0
  long long energyFull = -1;
642
0
  long long timeToEmpty = -1;
643
644
0
  struct dirent* entry = nullptr;
645
  // NOLINTNEXTLINE(concurrency-mt-unsafe): dir is a local DIR*, not shared across threads
646
0
  while ((entry = readdir(dir)) != nullptr)
647
0
  {
648
0
    char path[PATH_MAX] = WINPR_C_ARRAY_INIT;
649
0
    char value[64] = WINPR_C_ARRAY_INIT;
650
0
    long long v = 0;
651
652
0
    if (entry->d_name[0] == '.')
653
0
      continue;
654
655
0
    (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/type", entry->d_name);
656
0
    if (!sysinfo_read_sysfs_string(path, value, sizeof(value)))
657
0
      continue;
658
659
0
    if (strcmp(value, "Battery") == 0)
660
0
    {
661
0
      (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/present",
662
0
                     entry->d_name);
663
0
      if (sysinfo_read_sysfs_int(path, &v) && (v == 0))
664
0
        continue; /* battery slot present in sysfs, no battery physically installed */
665
666
0
      haveBattery = TRUE;
667
668
0
      (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/status",
669
0
                     entry->d_name);
670
0
      if (sysinfo_read_sysfs_string(path, value, sizeof(value)) &&
671
0
          (strcmp(value, "Charging") == 0))
672
0
        charging = TRUE;
673
674
0
      (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/capacity",
675
0
                     entry->d_name);
676
0
      if (sysinfo_read_sysfs_int(path, &v))
677
0
        percent = v;
678
679
0
      (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/time_to_empty_now",
680
0
                     entry->d_name);
681
0
      if (sysinfo_read_sysfs_int(path, &v) && (v > 0))
682
0
        timeToEmpty = v;
683
684
      /* not every driver exposes "capacity" directly; fall back to computing it from
685
       * energy_now/energy_full when present */
686
0
      if (percent < 0)
687
0
      {
688
0
        (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/energy_now",
689
0
                       entry->d_name);
690
0
        (void)sysinfo_read_sysfs_int(path, &energyNow);
691
0
        (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/energy_full",
692
0
                       entry->d_name);
693
0
        (void)sysinfo_read_sysfs_int(path, &energyFull);
694
695
0
        if ((energyNow < 0) || (energyFull <= 0))
696
0
        {
697
0
          (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/charge_now",
698
0
                         entry->d_name);
699
0
          (void)sysinfo_read_sysfs_int(path, &energyNow);
700
0
          (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/charge_full",
701
0
                         entry->d_name);
702
0
          (void)sysinfo_read_sysfs_int(path, &energyFull);
703
0
        }
704
705
0
        if ((energyNow >= 0) && (energyFull > 0))
706
0
          percent = (energyNow * 100) / energyFull;
707
0
      }
708
0
    }
709
0
    else
710
0
    {
711
      /* Mains / USB / Wireless: any of these reporting online means we're on AC power */
712
0
      (void)snprintf(path, sizeof(path) - 1, "/sys/class/power_supply/%s/online",
713
0
                     entry->d_name);
714
0
      if (sysinfo_read_sysfs_int(path, &v) && (v != 0))
715
0
        onAC = TRUE;
716
0
    }
717
0
  }
718
0
  (void)closedir(dir);
719
720
0
  if (!haveBattery)
721
0
  {
722
0
    status->ACLineStatus = AC_LINE_ONLINE;
723
0
    status->BatteryFlag = BATTERY_FLAG_NO_BATTERY;
724
0
    status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
725
0
    return TRUE;
726
0
  }
727
728
0
  status->ACLineStatus = (onAC || charging) ? AC_LINE_ONLINE : AC_LINE_OFFLINE;
729
730
0
  BYTE flag = 0;
731
0
  if (charging)
732
0
    flag |= BATTERY_FLAG_CHARGING;
733
734
0
  if (percent >= 0)
735
0
  {
736
0
    if (percent > 100)
737
0
      percent = 100;
738
0
    status->BatteryLifePercent = (BYTE)percent;
739
740
0
    if (percent <= 5)
741
0
      flag |= BATTERY_FLAG_CRITICAL;
742
0
    else if (percent <= 33)
743
0
      flag |= BATTERY_FLAG_LOW;
744
0
    else if (percent > 66)
745
0
      flag |= BATTERY_FLAG_HIGH;
746
0
  }
747
0
  else
748
0
    status->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
749
750
0
  status->BatteryFlag = flag ? flag : BATTERY_FLAG_UNKNOWN;
751
752
0
  if (timeToEmpty > 0)
753
0
    status->BatteryLifeTime = (DWORD)timeToEmpty;
754
755
0
  return TRUE;
756
0
}
757
758
#elif defined(__MACOSX__)
759
760
static 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
871
static 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
877
static 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
936
BOOL GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus)
937
0
{
938
0
  if (!lpSystemPowerStatus)
939
0
  {
940
0
    SetLastError(ERROR_BAD_ARGUMENTS);
941
0
    return FALSE;
942
0
  }
943
944
  /* safe, "no battery information available" defaults - overwritten below on platforms with a
945
   * real backend */
946
0
  lpSystemPowerStatus->ACLineStatus = AC_LINE_UNKNOWN;
947
0
  lpSystemPowerStatus->BatteryFlag = BATTERY_FLAG_UNKNOWN;
948
0
  lpSystemPowerStatus->BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
949
0
  lpSystemPowerStatus->SystemStatusFlag = 0;
950
0
  lpSystemPowerStatus->BatteryLifeTime = BATTERY_LIFE_UNKNOWN;
951
0
  lpSystemPowerStatus->BatteryFullLifeTime = BATTERY_LIFE_UNKNOWN;
952
953
0
#if defined(__linux__) || defined(__MACOSX__) || defined(__FreeBSD__)
954
0
  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
0
}
961
962
#endif
963
964
#if defined(_UWP)
965
966
DWORD GetTickCount(void)
967
{
968
  return (DWORD)GetTickCount64();
969
}
970
971
#endif
972
973
#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600))
974
975
ULONGLONG winpr_GetTickCount64(void)
976
0
{
977
0
  const UINT64 ns = winpr_GetTickCount64NS();
978
0
  return WINPR_TIME_NS_TO_MS(ns);
979
0
}
980
981
#endif
982
983
UINT64 winpr_GetTickCount64NS(void)
984
0
{
985
0
  UINT64 ticks = 0;
986
0
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L)
987
0
  struct timespec ts = WINPR_C_ARRAY_INIT;
988
989
0
  if (clock_gettime(CLOCK_ID, &ts) == 0)
990
0
    ticks = (WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_sec) * 1000000000ull) +
991
0
            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
0
  return ticks;
1027
0
}
1028
1029
UINT64 winpr_GetUnixTimeNS(void)
1030
0
{
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
0
  struct timespec ts = WINPR_C_ARRAY_INIT;
1042
0
  if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
1043
0
    return 0;
1044
0
  return WINPR_ASSERTING_INT_CAST(uint64_t, ts.tv_sec) * 1000000000ull +
1045
0
         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
0
}
1053
1054
/* If x86 */
1055
#ifdef _M_IX86_AMD64
1056
1057
#if defined(__GNUC__)
1058
#define xgetbv(_func_, _lo_, _hi_) \
1059
0
  __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
0
#define B_BIT_AVX2 (1 << 5)
1070
0
#define B_BIT_AVX512F (1 << 16)
1071
0
#define D_BIT_MMX (1 << 23)
1072
0
#define D_BIT_SSE (1 << 25)
1073
0
#define D_BIT_SSE2 (1 << 26)
1074
0
#define D_BIT_3DN (1 << 30)
1075
// #define C_BIT_SSE3 (1 << 0)
1076
0
#define C_BIT_PCLMULQDQ (1 << 1)
1077
0
#define C81_BIT_LZCNT (1 << 5)
1078
// #define C_BIT_3DNP (1 << 8)
1079
0
#define C_BIT_3DNP (1 << 8)
1080
0
#define C_BIT_SSSE3 (1 << 9)
1081
0
#define C_BIT_SSE41 (1 << 19)
1082
0
#define C_BIT_SSE42 (1 << 20)
1083
0
#define C_BIT_FMA (1 << 12)
1084
0
#define C_BIT_AES (1 << 25)
1085
0
#define C_BIT_XGETBV (1 << 27)
1086
0
#define C_BIT_AVX (1 << 28)
1087
0
#define E_BIT_XMM (1 << 1)
1088
0
#define E_BIT_YMM (1 << 2)
1089
0
#define E_BITS_AVX (E_BIT_XMM | E_BIT_YMM)
1090
1091
static void cpuid(unsigned info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx)
1092
0
{
1093
0
#ifdef __GNUC__
1094
0
  *eax = *ebx = *ecx = *edx = 0;
1095
0
  __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
0
      "mov %%rbx, %%rsi;"
1105
0
      "cpuid;"
1106
0
      "xchg %%rbx, %%rsi;"
1107
0
#endif
1108
0
      : "=a"(*eax), "=S"(*ebx), "=c"(*ecx), "=d"(*edx)
1109
0
      : "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
0
}
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
1147
static 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
1190
BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
1191
0
{
1192
0
  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
0
#if defined(_M_IX86_AMD64)
1374
0
#ifdef __GNUC__
1375
0
  unsigned a = 0;
1376
0
  unsigned b = 0;
1377
0
  unsigned c = 0;
1378
0
  unsigned d = 0;
1379
0
  cpuid(1, &a, &b, &c, &d);
1380
1381
0
  switch (ProcessorFeature)
1382
0
  {
1383
0
    case PF_MMX_INSTRUCTIONS_AVAILABLE:
1384
0
      if (d & D_BIT_MMX)
1385
0
        ret = TRUE;
1386
1387
0
      break;
1388
1389
0
    case PF_XMMI_INSTRUCTIONS_AVAILABLE:
1390
0
      if (d & D_BIT_SSE)
1391
0
        ret = TRUE;
1392
1393
0
      break;
1394
1395
0
    case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
1396
0
      if (d & D_BIT_SSE2)
1397
0
        ret = TRUE;
1398
1399
0
      break;
1400
1401
0
    case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
1402
0
      if (d & D_BIT_3DN)
1403
0
        ret = TRUE;
1404
1405
0
      break;
1406
1407
0
    case PF_SSE3_INSTRUCTIONS_AVAILABLE:
1408
0
      ret = __builtin_cpu_supports("sse3");
1409
0
      break;
1410
1411
0
    case PF_SSSE3_INSTRUCTIONS_AVAILABLE:
1412
0
      ret = __builtin_cpu_supports("ssse3");
1413
0
      break;
1414
0
    case PF_SSE4_1_INSTRUCTIONS_AVAILABLE:
1415
0
      ret = __builtin_cpu_supports("sse4.1");
1416
0
      break;
1417
0
    case PF_SSE4_2_INSTRUCTIONS_AVAILABLE:
1418
0
      ret = __builtin_cpu_supports("sse4.2");
1419
0
      break;
1420
0
    case PF_AVX_INSTRUCTIONS_AVAILABLE:
1421
0
      ret = __builtin_cpu_supports("avx");
1422
0
      break;
1423
0
    case PF_AVX2_INSTRUCTIONS_AVAILABLE:
1424
0
      ret = __builtin_cpu_supports("avx2");
1425
0
      break;
1426
0
    case PF_AVX512F_INSTRUCTIONS_AVAILABLE:
1427
0
      ret = __builtin_cpu_supports("avx512f");
1428
0
      break;
1429
0
    case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
1430
#if defined(__ARM_NEON__)
1431
      ret = TRUE;
1432
#endif
1433
0
      break;
1434
0
    default:
1435
0
      WLog_WARN(TAG, "feature 0x%08" PRIx32 " check not implemented", ProcessorFeature);
1436
0
      break;
1437
0
  }
1438
1439
0
#endif // __GNUC__
1440
0
#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
0
  return ret;
1470
0
}
1471
1472
#endif //_WIN32
1473
1474
DWORD GetTickCountPrecise(void)
1475
0
{
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
0
  return GetTickCount();
1484
0
#endif
1485
0
}
1486
1487
BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
1488
0
{
1489
0
  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
0
  unsigned b = 0;
1532
0
  unsigned c = 0;
1533
0
  unsigned d = 0;
1534
0
  cpuid(1, &a, &b, &c, &d);
1535
1536
0
  switch (ProcessorFeature)
1537
0
  {
1538
0
    case PF_EX_LZCNT:
1539
0
    {
1540
0
      unsigned a81 = 0;
1541
0
      unsigned b81 = 0;
1542
0
      unsigned c81 = 0;
1543
0
      unsigned d81 = 0;
1544
0
      cpuid(0x80000001, &a81, &b81, &c81, &d81);
1545
1546
0
      if (c81 & C81_BIT_LZCNT)
1547
0
        ret = TRUE;
1548
0
    }
1549
0
    break;
1550
1551
0
    case PF_EX_3DNOW_PREFETCH:
1552
0
      if (c & C_BIT_3DNP)
1553
0
        ret = TRUE;
1554
1555
0
      break;
1556
1557
0
    case PF_EX_SSSE3:
1558
0
      if (c & C_BIT_SSSE3)
1559
0
        ret = TRUE;
1560
1561
0
      break;
1562
1563
0
    case PF_EX_SSE41:
1564
0
      if (c & C_BIT_SSE41)
1565
0
        ret = TRUE;
1566
1567
0
      break;
1568
1569
0
    case PF_EX_SSE42:
1570
0
      if (c & C_BIT_SSE42)
1571
0
        ret = TRUE;
1572
1573
0
      break;
1574
0
#if defined(__GNUC__) || defined(_MSC_VER)
1575
1576
0
    case PF_EX_AVX:
1577
0
    case PF_EX_AVX2:
1578
0
    case PF_EX_AVX512F:
1579
0
    case PF_EX_FMA:
1580
0
    case PF_EX_AVX_AES:
1581
0
    case PF_EX_AVX_PCLMULQDQ:
1582
0
    {
1583
      /* Check for general AVX support */
1584
0
      if (!(c & C_BIT_AVX))
1585
0
        break;
1586
1587
      /* Check for xgetbv support */
1588
0
      if (!(c & C_BIT_XGETBV))
1589
0
        break;
1590
1591
0
      int e = 0;
1592
0
      int f = 0;
1593
0
      xgetbv(0, e, f);
1594
1595
      /* XGETBV enabled for applications and XMM/YMM states enabled */
1596
0
      if ((e & E_BITS_AVX) == E_BITS_AVX)
1597
0
      {
1598
0
        switch (ProcessorFeature)
1599
0
        {
1600
0
          case PF_EX_AVX:
1601
0
            ret = TRUE;
1602
0
            break;
1603
1604
0
          case PF_EX_AVX2:
1605
0
          case PF_EX_AVX512F:
1606
0
            cpuid(7, &a, &b, &c, &d);
1607
0
            switch (ProcessorFeature)
1608
0
            {
1609
0
              case PF_EX_AVX2:
1610
0
                if (b & B_BIT_AVX2)
1611
0
                  ret = TRUE;
1612
0
                break;
1613
1614
0
              case PF_EX_AVX512F:
1615
0
                if (b & B_BIT_AVX512F)
1616
0
                  ret = TRUE;
1617
0
                break;
1618
1619
0
              default:
1620
0
                break;
1621
0
            }
1622
0
            break;
1623
1624
0
          case PF_EX_FMA:
1625
0
            if (c & C_BIT_FMA)
1626
0
              ret = TRUE;
1627
1628
0
            break;
1629
1630
0
          case PF_EX_AVX_AES:
1631
0
            if (c & C_BIT_AES)
1632
0
              ret = TRUE;
1633
1634
0
            break;
1635
1636
0
          case PF_EX_AVX_PCLMULQDQ:
1637
0
            if (c & C_BIT_PCLMULQDQ)
1638
0
              ret = TRUE;
1639
1640
0
            break;
1641
0
          default:
1642
0
            break;
1643
0
        }
1644
0
      }
1645
0
    }
1646
0
    break;
1647
0
#endif // __GNUC__ || _MSC_VER
1648
1649
0
    default:
1650
0
      break;
1651
0
  }
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
0
  return ret;
1703
0
}