Coverage Report

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