Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/sysinfo/sysinfo.c
Line
Count
Source (jump to first uncovered line)
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/sysinfo.h>
24
#include <winpr/platform.h>
25
26
#if defined(ANDROID)
27
#include "cpufeatures/cpu-features.h"
28
#endif
29
30
#if defined(__linux__)
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <fcntl.h>
34
#endif
35
36
#include "../log.h"
37
#define TAG WINPR_TAG("sysinfo")
38
39
/**
40
 * api-ms-win-core-sysinfo-l1-1-1.dll:
41
 *
42
 * EnumSystemFirmwareTables
43
 * GetSystemFirmwareTable
44
 * GetLogicalProcessorInformation
45
 * GetLogicalProcessorInformationEx
46
 * GetProductInfo
47
 * GetSystemDirectoryA
48
 * GetSystemDirectoryW
49
 * GetSystemTimeAdjustment
50
 * GetSystemWindowsDirectoryA
51
 * GetSystemWindowsDirectoryW
52
 * GetWindowsDirectoryA
53
 * GetWindowsDirectoryW
54
 * GlobalMemoryStatusEx
55
 * SetComputerNameExW
56
 * VerSetConditionMask
57
 */
58
59
#ifndef _WIN32
60
61
#include <time.h>
62
#include <sys/time.h>
63
64
#ifdef WINPR_HAVE_UNISTD_H
65
#include <unistd.h>
66
#endif
67
68
#include <winpr/crt.h>
69
#include <winpr/platform.h>
70
71
#if defined(__MACOSX__) || defined(__IOS__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
72
    defined(__OpenBSD__) || defined(__DragonFly__)
73
#include <sys/sysctl.h>
74
#endif
75
76
static DWORD GetProcessorArchitecture(void)
77
0
{
78
0
  DWORD cpuArch = PROCESSOR_ARCHITECTURE_UNKNOWN;
79
#if defined(ANDROID)
80
  AndroidCpuFamily family = android_getCpuFamily();
81
82
  switch (family)
83
  {
84
    case ANDROID_CPU_FAMILY_ARM:
85
      return PROCESSOR_ARCHITECTURE_ARM;
86
87
    case ANDROID_CPU_FAMILY_X86:
88
      return PROCESSOR_ARCHITECTURE_INTEL;
89
90
    case ANDROID_CPU_FAMILY_MIPS:
91
      return PROCESSOR_ARCHITECTURE_MIPS;
92
93
    case ANDROID_CPU_FAMILY_ARM64:
94
      return PROCESSOR_ARCHITECTURE_ARM64;
95
96
    case ANDROID_CPU_FAMILY_X86_64:
97
      return PROCESSOR_ARCHITECTURE_AMD64;
98
99
    case ANDROID_CPU_FAMILY_MIPS64:
100
      return PROCESSOR_ARCHITECTURE_MIPS64;
101
102
    default:
103
      return PROCESSOR_ARCHITECTURE_UNKNOWN;
104
  }
105
106
#elif defined(_M_ARM)
107
  cpuArch = PROCESSOR_ARCHITECTURE_ARM;
108
#elif defined(_M_IX86)
109
  cpuArch = PROCESSOR_ARCHITECTURE_INTEL;
110
#elif defined(_M_MIPS64)
111
  /* Needs to be before __mips__ since the compiler defines both */
112
  cpuArch = PROCESSOR_ARCHITECTURE_MIPS64;
113
#elif defined(_M_MIPS)
114
  cpuArch = PROCESSOR_ARCHITECTURE_MIPS;
115
#elif defined(_M_ARM64)
116
  cpuArch = PROCESSOR_ARCHITECTURE_ARM64;
117
#elif defined(_M_AMD64)
118
0
  cpuArch = PROCESSOR_ARCHITECTURE_AMD64;
119
#elif defined(_M_PPC)
120
  cpuArch = PROCESSOR_ARCHITECTURE_PPC;
121
#elif defined(_M_ALPHA)
122
  cpuArch = PROCESSOR_ARCHITECTURE_ALPHA;
123
#endif
124
0
  return cpuArch;
125
0
}
126
127
static DWORD GetNumberOfProcessors(void)
128
0
{
129
0
  DWORD numCPUs = 1;
130
#if defined(ANDROID)
131
  return android_getCpuCount();
132
  /* TODO: iOS */
133
#elif defined(__linux__) || defined(__sun) || defined(_AIX)
134
0
  numCPUs = (DWORD)sysconf(_SC_NPROCESSORS_ONLN);
135
#elif defined(__MACOSX__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
136
    defined(__OpenBSD__) || defined(__DragonFly__)
137
  {
138
    int mib[4];
139
    size_t length = sizeof(numCPUs);
140
    mib[0] = CTL_HW;
141
#if defined(__FreeBSD__) || defined(__OpenBSD__)
142
    mib[1] = HW_NCPU;
143
#else
144
    mib[1] = HW_AVAILCPU;
145
#endif
146
    sysctl(mib, 2, &numCPUs, &length, NULL, 0);
147
148
    if (numCPUs < 1)
149
    {
150
      mib[1] = HW_NCPU;
151
      sysctl(mib, 2, &numCPUs, &length, NULL, 0);
152
153
      if (numCPUs < 1)
154
        numCPUs = 1;
155
    }
156
  }
157
#elif defined(__hpux)
158
  numCPUs = (DWORD)mpctl(MPC_GETNUMSPUS, NULL, NULL);
159
#elif defined(__sgi)
160
  numCPUs = (DWORD)sysconf(_SC_NPROC_ONLN);
161
#endif
162
0
  return numCPUs;
163
0
}
164
165
static DWORD GetSystemPageSize(void)
166
0
{
167
0
  DWORD dwPageSize = 0;
168
0
  long sc_page_size = -1;
169
0
#if defined(_SC_PAGESIZE)
170
171
0
  if (sc_page_size < 0)
172
0
    sc_page_size = sysconf(_SC_PAGESIZE);
173
174
0
#endif
175
0
#if defined(_SC_PAGE_SIZE)
176
177
0
  if (sc_page_size < 0)
178
0
    sc_page_size = sysconf(_SC_PAGE_SIZE);
179
180
0
#endif
181
182
0
  if (sc_page_size > 0)
183
0
    dwPageSize = (DWORD)sc_page_size;
184
185
0
  if (dwPageSize < 4096)
186
0
    dwPageSize = 4096;
187
188
0
  return dwPageSize;
189
0
}
190
191
void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
192
0
{
193
0
  lpSystemInfo->wProcessorArchitecture = GetProcessorArchitecture();
194
0
  lpSystemInfo->wReserved = 0;
195
0
  lpSystemInfo->dwPageSize = GetSystemPageSize();
196
0
  lpSystemInfo->lpMinimumApplicationAddress = NULL;
197
0
  lpSystemInfo->lpMaximumApplicationAddress = NULL;
198
0
  lpSystemInfo->dwActiveProcessorMask = 0;
199
0
  lpSystemInfo->dwNumberOfProcessors = GetNumberOfProcessors();
200
0
  lpSystemInfo->dwProcessorType = 0;
201
0
  lpSystemInfo->dwAllocationGranularity = 0;
202
0
  lpSystemInfo->wProcessorLevel = 0;
203
0
  lpSystemInfo->wProcessorRevision = 0;
204
0
}
205
206
void GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
207
0
{
208
0
  GetSystemInfo(lpSystemInfo);
209
0
}
210
211
void GetSystemTime(LPSYSTEMTIME lpSystemTime)
212
0
{
213
0
  time_t ct = 0;
214
0
  struct tm tres;
215
0
  struct tm* stm = NULL;
216
0
  WORD wMilliseconds = 0;
217
0
  ct = time(NULL);
218
0
  wMilliseconds = (WORD)(GetTickCount() % 1000);
219
0
  stm = gmtime_r(&ct, &tres);
220
0
  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
221
222
0
  if (stm)
223
0
  {
224
0
    lpSystemTime->wYear = (WORD)(stm->tm_year + 1900);
225
0
    lpSystemTime->wMonth = (WORD)(stm->tm_mon + 1);
226
0
    lpSystemTime->wDayOfWeek = (WORD)stm->tm_wday;
227
0
    lpSystemTime->wDay = (WORD)stm->tm_mday;
228
0
    lpSystemTime->wHour = (WORD)stm->tm_hour;
229
0
    lpSystemTime->wMinute = (WORD)stm->tm_min;
230
0
    lpSystemTime->wSecond = (WORD)stm->tm_sec;
231
0
    lpSystemTime->wMilliseconds = wMilliseconds;
232
0
  }
233
0
}
234
235
BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime)
236
0
{
237
  /* TODO: Implement */
238
0
  return FALSE;
239
0
}
240
241
VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
242
0
{
243
0
  time_t ct = 0;
244
0
  struct tm tres;
245
0
  struct tm* ltm = NULL;
246
0
  WORD wMilliseconds = 0;
247
0
  ct = time(NULL);
248
0
  wMilliseconds = (WORD)(GetTickCount() % 1000);
249
0
  ltm = localtime_r(&ct, &tres);
250
0
  ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
251
252
0
  if (ltm)
253
0
  {
254
0
    lpSystemTime->wYear = (WORD)(ltm->tm_year + 1900);
255
0
    lpSystemTime->wMonth = (WORD)(ltm->tm_mon + 1);
256
0
    lpSystemTime->wDayOfWeek = (WORD)ltm->tm_wday;
257
0
    lpSystemTime->wDay = (WORD)ltm->tm_mday;
258
0
    lpSystemTime->wHour = (WORD)ltm->tm_hour;
259
0
    lpSystemTime->wMinute = (WORD)ltm->tm_min;
260
0
    lpSystemTime->wSecond = (WORD)ltm->tm_sec;
261
0
    lpSystemTime->wMilliseconds = wMilliseconds;
262
0
  }
263
0
}
264
265
BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime)
266
0
{
267
  /* TODO: Implement */
268
0
  return FALSE;
269
0
}
270
271
VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
272
0
{
273
0
  ULARGE_INTEGER time64;
274
0
  time64.u.HighPart = 0;
275
  /* time represented in tenths of microseconds since midnight of January 1, 1601 */
276
0
  time64.QuadPart = time(NULL) + 11644473600LL; /* Seconds since January 1, 1601 */
277
0
  time64.QuadPart *= 10000000;                  /* Convert timestamp to tenths of a microsecond */
278
0
  lpSystemTimeAsFileTime->dwLowDateTime = time64.u.LowPart;
279
0
  lpSystemTimeAsFileTime->dwHighDateTime = time64.u.HighPart;
280
0
}
281
282
BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement,
283
                             PBOOL lpTimeAdjustmentDisabled)
284
0
{
285
  /* TODO: Implement */
286
0
  return FALSE;
287
0
}
288
289
#ifndef CLOCK_MONOTONIC_RAW
290
#define CLOCK_MONOTONIC_RAW 4
291
#endif
292
293
DWORD GetTickCount(void)
294
0
{
295
0
  DWORD ticks = 0;
296
0
#ifdef __linux__
297
0
  struct timespec ts;
298
299
0
  if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
300
0
    ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
301
302
#else
303
  /**
304
   * FIXME: this is relative to the Epoch time, and we
305
   * need to return a value relative to the system uptime.
306
   */
307
  struct timeval tv;
308
309
  if (!gettimeofday(&tv, NULL))
310
    ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
311
312
#endif
313
0
  return ticks;
314
0
}
315
#endif // _WIN32
316
317
#if !defined(_WIN32) || defined(_UWP)
318
319
#if defined(WITH_WINPR_DEPRECATED)
320
/* OSVERSIONINFOEX Structure:
321
 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724833
322
 */
323
324
BOOL GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
325
{
326
#ifdef _UWP
327
328
  /* Windows 10 Version Info */
329
  if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
330
      (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
331
  {
332
    lpVersionInformation->dwMajorVersion = 10;
333
    lpVersionInformation->dwMinorVersion = 0;
334
    lpVersionInformation->dwBuildNumber = 0;
335
    lpVersionInformation->dwPlatformId = VER_PLATFORM_WIN32_NT;
336
    ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
337
338
    if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
339
    {
340
      LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
341
      lpVersionInformationEx->wServicePackMajor = 0;
342
      lpVersionInformationEx->wServicePackMinor = 0;
343
      lpVersionInformationEx->wSuiteMask = 0;
344
      lpVersionInformationEx->wProductType = VER_NT_WORKSTATION;
345
      lpVersionInformationEx->wReserved = 0;
346
    }
347
348
    return TRUE;
349
  }
350
351
#else
352
353
  /* Windows 7 SP1 Version Info */
354
  if ((lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA)) ||
355
      (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)))
356
  {
357
    lpVersionInformation->dwMajorVersion = 6;
358
    lpVersionInformation->dwMinorVersion = 1;
359
    lpVersionInformation->dwBuildNumber = 7601;
360
    lpVersionInformation->dwPlatformId = VER_PLATFORM_WIN32_NT;
361
    ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
362
363
    if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
364
    {
365
      LPOSVERSIONINFOEXA lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
366
      lpVersionInformationEx->wServicePackMajor = 1;
367
      lpVersionInformationEx->wServicePackMinor = 0;
368
      lpVersionInformationEx->wSuiteMask = 0;
369
      lpVersionInformationEx->wProductType = VER_NT_WORKSTATION;
370
      lpVersionInformationEx->wReserved = 0;
371
    }
372
373
    return TRUE;
374
  }
375
376
#endif
377
  return FALSE;
378
}
379
380
BOOL GetVersionExW(LPOSVERSIONINFOW lpVersionInformation)
381
{
382
  ZeroMemory(lpVersionInformation->szCSDVersion, sizeof(lpVersionInformation->szCSDVersion));
383
  return GetVersionExA((LPOSVERSIONINFOA)lpVersionInformation);
384
}
385
386
#endif
387
388
#endif
389
390
#if !defined(_WIN32) || defined(_UWP)
391
392
BOOL GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
393
0
{
394
0
  BOOL rc;
395
0
  LPSTR buffer = NULL;
396
0
  if (!lpnSize || (*lpnSize > INT_MAX))
397
0
    return FALSE;
398
399
0
  if (*lpnSize > 0)
400
0
  {
401
0
    buffer = malloc(*lpnSize);
402
0
    if (!buffer)
403
0
      return FALSE;
404
0
  }
405
0
  rc = GetComputerNameA(buffer, lpnSize);
406
407
0
  if (rc && (*lpnSize > 0))
408
0
  {
409
0
    const SSIZE_T res = ConvertUtf8NToWChar(buffer, *lpnSize, lpBuffer, *lpnSize);
410
0
    rc = res > 0;
411
0
  }
412
413
0
  free(buffer);
414
415
0
  return rc;
416
0
}
417
418
BOOL GetComputerNameA(LPSTR lpBuffer, LPDWORD lpnSize)
419
0
{
420
0
  char* dot;
421
0
  size_t length;
422
0
  char hostname[256] = { 0 };
423
424
0
  if (!lpnSize)
425
0
  {
426
0
    SetLastError(ERROR_BAD_ARGUMENTS);
427
0
    return FALSE;
428
0
  }
429
430
0
  if (gethostname(hostname, sizeof(hostname)) == -1)
431
0
    return FALSE;
432
433
0
  length = strnlen(hostname, sizeof(hostname));
434
0
  dot = strchr(hostname, '.');
435
436
0
  if (dot)
437
0
    length = (dot - hostname);
438
439
0
  if ((*lpnSize <= (DWORD)length) || !lpBuffer)
440
0
  {
441
0
    SetLastError(ERROR_BUFFER_OVERFLOW);
442
0
    *lpnSize = (DWORD)(length + 1);
443
0
    return FALSE;
444
0
  }
445
446
0
  CopyMemory(lpBuffer, hostname, length);
447
0
  lpBuffer[length] = '\0';
448
0
  *lpnSize = (DWORD)length;
449
0
  return TRUE;
450
0
}
451
452
BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD lpnSize)
453
0
{
454
0
  size_t length;
455
0
  char hostname[256] = { 0 };
456
457
0
  if (!lpnSize)
458
0
  {
459
0
    SetLastError(ERROR_BAD_ARGUMENTS);
460
0
    return FALSE;
461
0
  }
462
463
0
  if ((NameType == ComputerNameNetBIOS) || (NameType == ComputerNamePhysicalNetBIOS))
464
0
  {
465
0
    BOOL rc = GetComputerNameA(lpBuffer, lpnSize);
466
467
0
    if (!rc)
468
0
    {
469
0
      if (GetLastError() == ERROR_BUFFER_OVERFLOW)
470
0
        SetLastError(ERROR_MORE_DATA);
471
0
    }
472
473
0
    return rc;
474
0
  }
475
476
0
  if (gethostname(hostname, sizeof(hostname)) == -1)
477
0
    return FALSE;
478
479
0
  length = strnlen(hostname, sizeof(hostname));
480
481
0
  switch (NameType)
482
0
  {
483
0
    case ComputerNameDnsHostname:
484
0
    case ComputerNameDnsDomain:
485
0
    case ComputerNameDnsFullyQualified:
486
0
    case ComputerNamePhysicalDnsHostname:
487
0
    case ComputerNamePhysicalDnsDomain:
488
0
    case ComputerNamePhysicalDnsFullyQualified:
489
0
      if ((*lpnSize <= (DWORD)length) || !lpBuffer)
490
0
      {
491
0
        *lpnSize = (DWORD)(length + 1);
492
0
        SetLastError(ERROR_MORE_DATA);
493
0
        return FALSE;
494
0
      }
495
496
0
      CopyMemory(lpBuffer, hostname, length);
497
0
      lpBuffer[length] = '\0';
498
0
      *lpnSize = (DWORD)length;
499
0
      break;
500
501
0
    default:
502
0
      return FALSE;
503
0
  }
504
505
0
  return TRUE;
506
0
}
507
508
BOOL GetComputerNameExW(COMPUTER_NAME_FORMAT NameType, LPWSTR lpBuffer, LPDWORD lpnSize)
509
0
{
510
0
  BOOL rc;
511
0
  LPSTR lpABuffer = NULL;
512
513
0
  if (!lpnSize)
514
0
  {
515
0
    SetLastError(ERROR_BAD_ARGUMENTS);
516
0
    return FALSE;
517
0
  }
518
519
0
  if (*lpnSize > 0)
520
0
  {
521
0
    lpABuffer = calloc(*lpnSize, sizeof(CHAR));
522
523
0
    if (!lpABuffer)
524
0
      return FALSE;
525
0
  }
526
527
0
  rc = GetComputerNameExA(NameType, lpABuffer, lpnSize);
528
529
0
  if (rc && (*lpnSize > 0))
530
0
  {
531
0
    const SSIZE_T res = ConvertUtf8NToWChar(lpABuffer, *lpnSize, lpBuffer, *lpnSize);
532
0
    rc = res > 0;
533
0
  }
534
535
0
  free(lpABuffer);
536
0
  return rc;
537
0
}
538
539
#endif
540
541
#if defined(_UWP)
542
543
DWORD GetTickCount(void)
544
{
545
  return (DWORD)GetTickCount64();
546
}
547
548
#endif
549
550
#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600))
551
552
ULONGLONG winpr_GetTickCount64(void)
553
0
{
554
0
  ULONGLONG ticks = 0;
555
0
#if defined(__linux__)
556
0
  struct timespec ts;
557
558
0
  if (!clock_gettime(CLOCK_MONOTONIC_RAW, &ts))
559
0
    ticks = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
560
561
#elif defined(_WIN32)
562
  FILETIME ft;
563
  ULARGE_INTEGER ul;
564
  GetSystemTimeAsFileTime(&ft);
565
  ul.LowPart = ft.dwLowDateTime;
566
  ul.HighPart = ft.dwHighDateTime;
567
  ticks = ul.QuadPart;
568
#else
569
  /**
570
   * FIXME: this is relative to the Epoch time, and we
571
   * need to return a value relative to the system uptime.
572
   */
573
  struct timeval tv;
574
575
  if (!gettimeofday(&tv, NULL))
576
    ticks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
577
578
#endif
579
0
  return ticks;
580
0
}
581
582
#endif
583
584
/* If x86 */
585
#ifdef _M_IX86_AMD64
586
587
#if defined(__GNUC__)
588
#define xgetbv(_func_, _lo_, _hi_) \
589
0
  __asm__ __volatile__("xgetbv" : "=a"(_lo_), "=d"(_hi_) : "c"(_func_))
590
#elif defined(_MSC_VER)
591
#define xgetbv(_func_, _lo_, _hi_)              \
592
  {                                           \
593
    unsigned __int64 val = _xgetbv(_func_); \
594
    _lo_ = val & 0xFFFFFFFF;                \
595
    _hi_ = (val >> 32);                     \
596
  }
597
#endif
598
599
0
#define B_BIT_AVX2 (1 << 5)
600
0
#define B_BIT_AVX512F (1 << 16)
601
0
#define D_BIT_MMX (1 << 23)
602
0
#define D_BIT_SSE (1 << 25)
603
0
#define D_BIT_SSE2 (1 << 26)
604
0
#define D_BIT_3DN (1 << 30)
605
0
#define C_BIT_SSE3 (1 << 0)
606
0
#define C_BIT_PCLMULQDQ (1 << 1)
607
0
#define C81_BIT_LZCNT (1 << 5)
608
#define C_BIT_3DNP (1 << 8)
609
0
#define C_BIT_3DNP (1 << 8)
610
0
#define C_BIT_SSSE3 (1 << 9)
611
0
#define C_BIT_SSE41 (1 << 19)
612
0
#define C_BIT_SSE42 (1 << 20)
613
0
#define C_BIT_FMA (1 << 12)
614
0
#define C_BIT_AES (1 << 25)
615
0
#define C_BIT_XGETBV (1 << 27)
616
0
#define C_BIT_AVX (1 << 28)
617
0
#define E_BIT_XMM (1 << 1)
618
0
#define E_BIT_YMM (1 << 2)
619
0
#define E_BITS_AVX (E_BIT_XMM | E_BIT_YMM)
620
621
static void cpuid(unsigned info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx)
622
0
{
623
0
#ifdef __GNUC__
624
0
  *eax = *ebx = *ecx = *edx = 0;
625
0
  __asm volatile(
626
  /* The EBX (or RBX register on x86_64) is used for the PIC base address
627
   * and must not be corrupted by our inline assembly.
628
   */
629
#ifdef _M_IX86
630
      "mov %%ebx, %%esi;"
631
      "cpuid;"
632
      "xchg %%ebx, %%esi;"
633
#else
634
0
      "mov %%rbx, %%rsi;"
635
0
      "cpuid;"
636
0
      "xchg %%rbx, %%rsi;"
637
0
#endif
638
0
      : "=a"(*eax), "=S"(*ebx), "=c"(*ecx), "=d"(*edx)
639
0
      : "a"(info), "c"(0));
640
#elif defined(_MSC_VER)
641
  int a[4];
642
  __cpuid(a, info);
643
  *eax = a[0];
644
  *ebx = a[1];
645
  *ecx = a[2];
646
  *edx = a[3];
647
#endif
648
0
}
649
#elif defined(_M_ARM)
650
#if defined(__linux__)
651
// HWCAP flags from linux kernel - uapi/asm/hwcap.h
652
#define HWCAP_SWP (1 << 0)
653
#define HWCAP_HALF (1 << 1)
654
#define HWCAP_THUMB (1 << 2)
655
#define HWCAP_26BIT (1 << 3) /* Play it safe */
656
#define HWCAP_FAST_MULT (1 << 4)
657
#define HWCAP_FPA (1 << 5)
658
#define HWCAP_VFP (1 << 6)
659
#define HWCAP_EDSP (1 << 7)
660
#define HWCAP_JAVA (1 << 8)
661
#define HWCAP_IWMMXT (1 << 9)
662
#define HWCAP_CRUNCH (1 << 10)
663
#define HWCAP_THUMBEE (1 << 11)
664
#define HWCAP_NEON (1 << 12)
665
#define HWCAP_VFPv3 (1 << 13)
666
#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
667
#define HWCAP_TLS (1 << 15)
668
#define HWCAP_VFPv4 (1 << 16)
669
#define HWCAP_IDIVA (1 << 17)
670
#define HWCAP_IDIVT (1 << 18)
671
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
672
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
673
674
// From linux kernel uapi/linux/auxvec.h
675
#define AT_HWCAP 16
676
677
static unsigned GetARMCPUCaps(void)
678
{
679
  unsigned caps = 0;
680
  int fd = open("/proc/self/auxv", O_RDONLY);
681
682
  if (fd == -1)
683
    return 0;
684
685
  static struct
686
  {
687
    unsigned a_type; /* Entry type */
688
    unsigned a_val;  /* Integer value */
689
  } auxvec;
690
691
  while (1)
692
  {
693
    int num;
694
    num = read(fd, (char*)&auxvec, sizeof(auxvec));
695
696
    if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0))
697
      break;
698
699
    if (auxvec.a_type == AT_HWCAP)
700
    {
701
      caps = auxvec.a_val;
702
    }
703
  }
704
705
  close(fd);
706
  return caps;
707
}
708
709
#endif // defined(__linux__)
710
#endif // _M_IX86_AMD64
711
712
#ifndef _WIN32
713
714
BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
715
0
{
716
0
  BOOL ret = FALSE;
717
#if defined(ANDROID)
718
  const uint64_t features = android_getCpuFeatures();
719
720
  switch (ProcessorFeature)
721
  {
722
    case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
723
    case PF_ARM_NEON:
724
      return features & ANDROID_CPU_ARM_FEATURE_NEON;
725
726
    default:
727
      return FALSE;
728
  }
729
730
#elif defined(_M_ARM)
731
#ifdef __linux__
732
  const unsigned caps = GetARMCPUCaps();
733
734
  switch (ProcessorFeature)
735
  {
736
    case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
737
    case PF_ARM_NEON:
738
      if (caps & HWCAP_NEON)
739
        ret = TRUE;
740
741
      break;
742
743
    case PF_ARM_THUMB:
744
      if (caps & HWCAP_THUMB)
745
        ret = TRUE;
746
747
    case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
748
      if (caps & HWCAP_VFPD32)
749
        ret = TRUE;
750
751
    case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
752
      if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
753
        ret = TRUE;
754
755
    case PF_ARM_VFP3:
756
      if (caps & HWCAP_VFPv3)
757
        ret = TRUE;
758
759
      break;
760
761
    case PF_ARM_JAZELLE:
762
      if (caps & HWCAP_JAVA)
763
        ret = TRUE;
764
765
      break;
766
767
    case PF_ARM_DSP:
768
      if (caps & HWCAP_EDSP)
769
        ret = TRUE;
770
771
      break;
772
773
    case PF_ARM_MPU:
774
      if (caps & HWCAP_EDSP)
775
        ret = TRUE;
776
777
      break;
778
779
    case PF_ARM_THUMB2:
780
      if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
781
        ret = TRUE;
782
783
      break;
784
785
    case PF_ARM_T2EE:
786
      if (caps & HWCAP_THUMBEE)
787
        ret = TRUE;
788
789
      break;
790
791
    case PF_ARM_INTEL_WMMX:
792
      if (caps & HWCAP_IWMMXT)
793
        ret = TRUE;
794
795
      break;
796
797
    default:
798
      break;
799
  }
800
801
#elif defined(__APPLE__) // __linux__
802
803
  switch (ProcessorFeature)
804
  {
805
    case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
806
    case PF_ARM_NEON:
807
      ret = TRUE;
808
      break;
809
  }
810
811
#endif // __linux__
812
#elif defined(_M_IX86_AMD64)
813
0
#ifdef __GNUC__
814
0
  unsigned a, b, c, d;
815
0
  cpuid(1, &a, &b, &c, &d);
816
817
0
  switch (ProcessorFeature)
818
0
  {
819
0
    case PF_MMX_INSTRUCTIONS_AVAILABLE:
820
0
      if (d & D_BIT_MMX)
821
0
        ret = TRUE;
822
823
0
      break;
824
825
0
    case PF_XMMI_INSTRUCTIONS_AVAILABLE:
826
0
      if (d & D_BIT_SSE)
827
0
        ret = TRUE;
828
829
0
      break;
830
831
0
    case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
832
0
      if (d & D_BIT_SSE2)
833
0
        ret = TRUE;
834
835
0
      break;
836
837
0
    case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
838
0
      if (d & D_BIT_3DN)
839
0
        ret = TRUE;
840
841
0
      break;
842
843
0
    case PF_SSE3_INSTRUCTIONS_AVAILABLE:
844
0
      if (c & C_BIT_SSE3)
845
0
        ret = TRUE;
846
847
0
      break;
848
849
0
    default:
850
0
      break;
851
0
  }
852
853
0
#endif // __GNUC__
854
0
#endif
855
0
  return ret;
856
0
}
857
858
#endif //_WIN32
859
860
DWORD GetTickCountPrecise(void)
861
0
{
862
#ifdef _WIN32
863
  LARGE_INTEGER freq;
864
  LARGE_INTEGER current;
865
  QueryPerformanceFrequency(&freq);
866
  QueryPerformanceCounter(&current);
867
  return (DWORD)(current.QuadPart * 1000LL / freq.QuadPart);
868
#else
869
0
  return GetTickCount();
870
0
#endif
871
0
}
872
873
BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
874
0
{
875
0
  BOOL ret = FALSE;
876
#ifdef _M_ARM
877
#ifdef __linux__
878
  unsigned caps;
879
  caps = GetARMCPUCaps();
880
881
  switch (ProcessorFeature)
882
  {
883
    case PF_EX_ARM_VFP1:
884
      if (caps & HWCAP_VFP)
885
        ret = TRUE;
886
887
      break;
888
889
    case PF_EX_ARM_VFP3D16:
890
      if (caps & HWCAP_VFPv3D16)
891
        ret = TRUE;
892
893
      break;
894
895
    case PF_EX_ARM_VFP4:
896
      if (caps & HWCAP_VFPv4)
897
        ret = TRUE;
898
899
      break;
900
901
    case PF_EX_ARM_IDIVA:
902
      if (caps & HWCAP_IDIVA)
903
        ret = TRUE;
904
905
      break;
906
907
    case PF_EX_ARM_IDIVT:
908
      if (caps & HWCAP_IDIVT)
909
        ret = TRUE;
910
911
      break;
912
  }
913
914
#endif // __linux__
915
#elif defined(_M_IX86_AMD64)
916
0
  unsigned a, b, c, d;
917
0
  cpuid(1, &a, &b, &c, &d);
918
919
0
  switch (ProcessorFeature)
920
0
  {
921
0
    case PF_EX_LZCNT:
922
0
    {
923
0
      unsigned a81, b81, c81, d81;
924
0
      cpuid(0x80000001, &a81, &b81, &c81, &d81);
925
926
0
      if (c81 & C81_BIT_LZCNT)
927
0
        ret = TRUE;
928
0
    }
929
0
    break;
930
931
0
    case PF_EX_3DNOW_PREFETCH:
932
0
      if (c & C_BIT_3DNP)
933
0
        ret = TRUE;
934
935
0
      break;
936
937
0
    case PF_EX_SSSE3:
938
0
      if (c & C_BIT_SSSE3)
939
0
        ret = TRUE;
940
941
0
      break;
942
943
0
    case PF_EX_SSE41:
944
0
      if (c & C_BIT_SSE41)
945
0
        ret = TRUE;
946
947
0
      break;
948
949
0
    case PF_EX_SSE42:
950
0
      if (c & C_BIT_SSE42)
951
0
        ret = TRUE;
952
953
0
      break;
954
0
#if defined(__GNUC__) || defined(_MSC_VER)
955
956
0
    case PF_EX_AVX:
957
0
    case PF_EX_AVX2:
958
0
    case PF_EX_AVX512F:
959
0
    case PF_EX_FMA:
960
0
    case PF_EX_AVX_AES:
961
0
    case PF_EX_AVX_PCLMULQDQ:
962
0
    {
963
      /* Check for general AVX support */
964
0
      if (!(c & C_BIT_AVX))
965
0
        break;
966
967
      /* Check for xgetbv support */
968
0
      if (!(c & C_BIT_XGETBV))
969
0
        break;
970
971
0
      int e, f;
972
0
      xgetbv(0, e, f);
973
974
      /* XGETBV enabled for applications and XMM/YMM states enabled */
975
0
      if ((e & E_BITS_AVX) == E_BITS_AVX)
976
0
      {
977
0
        switch (ProcessorFeature)
978
0
        {
979
0
          case PF_EX_AVX:
980
0
            ret = TRUE;
981
0
            break;
982
983
0
          case PF_EX_AVX2:
984
0
          case PF_EX_AVX512F:
985
0
            cpuid(7, &a, &b, &c, &d);
986
0
            switch (ProcessorFeature)
987
0
            {
988
0
              case PF_EX_AVX2:
989
0
                if (b & B_BIT_AVX2)
990
0
                  ret = TRUE;
991
0
                break;
992
993
0
              case PF_EX_AVX512F:
994
0
                if (b & B_BIT_AVX512F)
995
0
                  ret = TRUE;
996
0
                break;
997
998
0
              default:
999
0
                break;
1000
0
            }
1001
0
            break;
1002
1003
0
          case PF_EX_FMA:
1004
0
            if (c & C_BIT_FMA)
1005
0
              ret = TRUE;
1006
1007
0
            break;
1008
1009
0
          case PF_EX_AVX_AES:
1010
0
            if (c & C_BIT_AES)
1011
0
              ret = TRUE;
1012
1013
0
            break;
1014
1015
0
          case PF_EX_AVX_PCLMULQDQ:
1016
0
            if (c & C_BIT_PCLMULQDQ)
1017
0
              ret = TRUE;
1018
1019
0
            break;
1020
0
        }
1021
0
      }
1022
0
    }
1023
0
    break;
1024
0
#endif // __GNUC__ || _MSC_VER
1025
1026
0
    default:
1027
0
      break;
1028
0
  }
1029
1030
0
#endif
1031
0
  return ret;
1032
0
}