Coverage Report

Created: 2026-10-15 06:26

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