These functions can be used to check if an processor feature is supported.
IsProcessorFeaturePresentEx is a extended version which is not available
in the windows API and allows to query additional features.
Currently it works on the following platforms:
- i386/amd64 when compiling with gcc
- ARM on linux
{
{ PRIM_X86_MMX_AVAILABLE, "MMX" },
{ PRIM_X86_3DNOW_AVAILABLE, "3DNow" },
- { PRIM_X86_3DNOW_PREFETCH_AVAILABLE, "3DNow-PF" },
+ { PRIM_X86_3DNOW_PREFETCH_AVAILABLE, "3DNow-PF" },
{ PRIM_X86_SSE_AVAILABLE, "SSE" },
{ PRIM_X86_SSE2_AVAILABLE, "SSE2" },
{ PRIM_X86_SSE3_AVAILABLE, "SSE3" },
{ PRIM_X86_SSE42_AVAILABLE, "SSE4.2" },
{ PRIM_X86_AVX_AVAILABLE, "AVX" },
{ PRIM_X86_FMA_AVAILABLE, "FMA" },
- { PRIM_X86_AVX_AES_AVAILABLE, "AVX-AES" },
+ { PRIM_X86_AVX_AES_AVAILABLE, "AVX-AES" },
{ PRIM_X86_AVX2_AVAILABLE, "AVX2" },
};
{ PRIM_ARM_VFP4_AVAILABLE, "VFP4" },
{ PRIM_ARM_FPA_AVAILABLE, "FPA" },
{ PRIM_ARM_FPE_AVAILABLE, "FPE" },
- { PRIM_ARM_IWMMXT_AVAILABLE, "IWMMXT" },
+ { PRIM_ARM_IWMMXT_AVAILABLE, "IWMMXT" },
{ PRIM_ARM_NEON_AVAILABLE, "NEON" },
};
#define PF_FLOATING_POINT_PRECISION_ERRATA 0
#define PF_FLOATING_POINT_EMULATED 1
#define PF_COMPARE_EXCHANGE_DOUBLE 2
-#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
+#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
#define PF_PPC_MOVEMEM_64BIT_OK 4
-#define PF_ALPHA_BYTE_INSTRUCTIONS 5
-#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6
+#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 //sse
#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7
#define PF_RDTSC_INSTRUCTION_AVAILABLE 8
#define PF_PAE_ENABLED 9
-#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10
+#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 //sse2
#define PF_SSE_DAZ_MODE_AVAILABLE 11
#define PF_NX_ENABLED 12
#define PF_SSE3_INSTRUCTIONS_AVAILABLE 13
#define PF_ARM_EXTERNAL_CACHE_AVAILABLE 26
#define PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE 27
+#define PF_ARM_V4 0x80000001
+#define PF_ARM_V5 0x80000002
+#define PF_ARM_V6 0x80000003
+#define PF_ARM_V7 0x80000004
+#define PF_ARM_THUMB 0x80000005
+#define PF_ARM_JAZELLE 0x80000006
+#define PF_ARM_DSP 0x80000007
+#define PF_ARM_MOVE_CP 0x80000008
+#define PF_ARM_VFP10 0x80000009
+#define PF_ARM_MPU 0x8000000A
+#define PF_ARM_WRITE_BUFFER 0x8000000B
+#define PF_ARM_MBX 0x8000000C
+#define PF_ARM_L2CACHE 0x8000000D
+#define PF_ARM_PHYSICALLY_TAGGED_CACHE 0x8000000E
+#define PF_ARM_VFP_SINGLE_PRECISION 0x8000000F
+#define PF_ARM_VFP_DOUBLE_PRECISION 0x80000010
+#define PF_ARM_ITCM 0x80000011
+#define PF_ARM_DTCM 0x80000012
+#define PF_ARM_UNIFIED_CACHE 0x80000013
+#define PF_ARM_WRITE_BACK_CACHE 0x80000014
+#define PF_ARM_CACHE_CAN_BE_LOCKED_DOWN 0x80000015
+#define PF_ARM_L2CACHE_MEMORY_MAPPED 0x80000016
+#define PF_ARM_L2CACHE_COPROC 0x80000017
+#define PF_ARM_THUMB2 0x80000018
+#define PF_ARM_T2EE 0x80000019
+#define PF_ARM_VFP3 0x8000001A
+#define PF_ARM_NEON 0x8000001B
+#define PF_ARM_UNALIGNED_ACCESS 0x8000001C
+
+#define PF_ARM_INTEL_XSCALE 0x80010001
+#define PF_ARM_INTEL_PMU 0x80010002
+#define PF_ARM_INTEL_WMMX 0x80010003
+
+// extended flags
+#define PF_EX_3DNOW_PREFETCH 1
+#define PF_EX_SSSE3 2
+#define PF_EX_SSE41 3
+#define PF_EX_SSE42 4
+#define PF_EX_AVX 5
+#define PF_EX_FMA 6
+#define PF_EX_AVX_AES 7
+#define PF_EX_AVX2 8
+#define PF_EX_ARM_VFP1 9
+#define PF_EX_ARM_VFP3D16 10
+#define PF_EX_ARM_VFP4 11
+#define PF_EX_ARM_IDIVA 12
+#define PF_EX_ARM_IDIVT 13
+
typedef struct _SYSTEM_INFO
{
union
WINPR_API DWORD GetTickCount(void);
+WINPR_API BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature);
#endif
+WINPR_API BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature);
+
#endif /* WINPR_SYSINFO_H */
* System Information
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2013 Bernhard Miklautz <bmiklautz@thinstuff.at>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#endif
#include <winpr/sysinfo.h>
+#include <winpr/platform.h>
+
+#if defined(__linux__) && defined(__GNUC__)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
/**
* api-ms-win-core-sysinfo-l1-1-1.dll:
{
DWORD numCPUs = 1;
- /* TODO: Android and iOS */
+ /* TODO: iOS */
#if defined(__linux__) || defined(__sun) || defined(_AIX)
numCPUs = (DWORD) sysconf(_SC_NPROCESSORS_ONLN);
return ticks;
}
+/* If x86 and gcc*/
+#ifdef _M_IX86_AMD64
+#ifdef __GNUC__
+
+#ifdef __AVX__
+#define xgetbv(_func_, _lo_, _hi_) \
+ __asm__ __volatile__ ("xgetbv" : "=a" (_lo_), "=d" (_hi_) : "c" (_func_))
+#endif
+
+#define D_BIT_MMX (1<<23)
+#define D_BIT_SSE (1<<25)
+#define D_BIT_SSE2 (1<<26)
+#define D_BIT_3DN (1<<30)
+#define C_BIT_SSE3 (1<<0)
+#define C_BIT_3DNP (1<<8)
+#define C_BIT_SSSE3 (1<<9)
+#define C_BIT_SSE41 (1<<19)
+#define C_BIT_SSE42 (1<<20)
+#define C_BIT_XGETBV (1<<27)
+#define C_BIT_AVX (1<<28)
+#define C_BITS_AVX (C_BIT_XGETBV|C_BIT_AVX)
+#define E_BIT_XMM (1<<1)
+#define E_BIT_YMM (1<<2)
+#define E_BITS_AVX (E_BIT_XMM|E_BIT_YMM)
+#define C_BIT_FMA (1<<11)
+#define C_BIT_AVX_AES (1<<24)
+
+static void cpuid(
+ unsigned info,
+ unsigned *eax,
+ unsigned *ebx,
+ unsigned *ecx,
+ unsigned *edx)
+{
+ *eax = *ebx = *ecx = *edx = 0;
+
+ __asm volatile
+ (
+ /* The EBX (or RBX register on x86_64) is used for the PIC base address
+ * and must not be corrupted by our inline assembly.
+ */
+#ifdef _M_IX86
+ "mov %%ebx, %%esi;"
+ "cpuid;"
+ "xchg %%ebx, %%esi;"
+#else
+ "mov %%rbx, %%rsi;"
+ "cpuid;"
+ "xchg %%rbx, %%rsi;"
+#endif
+ : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (info)
+ );
+}
+#endif // __GNUC__
+#elif defined(_M_ARM)
+#if defined(__linux__)
+// HWCAP flags from linux kernel - uapi/asm/hwcap.h
+#define HWCAP_SWP (1 << 0)
+#define HWCAP_HALF (1 << 1)
+#define HWCAP_THUMB (1 << 2)
+#define HWCAP_26BIT (1 << 3) /* Play it safe */
+#define HWCAP_FAST_MULT (1 << 4)
+#define HWCAP_FPA (1 << 5)
+#define HWCAP_VFP (1 << 6)
+#define HWCAP_EDSP (1 << 7)
+#define HWCAP_JAVA (1 << 8)
+#define HWCAP_IWMMXT (1 << 9)
+#define HWCAP_CRUNCH (1 << 10)
+#define HWCAP_THUMBEE (1 << 11)
+#define HWCAP_NEON (1 << 12)
+#define HWCAP_VFPv3 (1 << 13)
+#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
+#define HWCAP_TLS (1 << 15)
+#define HWCAP_VFPv4 (1 << 16)
+#define HWCAP_IDIVA (1 << 17)
+#define HWCAP_IDIVT (1 << 18)
+#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
+#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
+
+// From linux kernel uapi/linux/auxvec.h
+#define AT_HWCAP 16
+
+static unsigned GetARMCPUCaps(void){
+ unsigned caps = 0;
+
+ int fd = open ("/proc/self/auxv", O_RDONLY);
+
+ if (fd == -1)
+ return 0;
+
+ static struct
+ {
+ unsigned a_type; /* Entry type */
+ unsigned a_val; /* Integer value */
+ } auxvec;
+
+ while (1){
+ int num;
+ num = read(fd, (char *)&auxvec, sizeof(auxvec));
+ if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0))
+ break;
+ if (auxvec.a_type == AT_HWCAP)
+ {
+ caps = auxvec.a_val;
+ }
+ }
+ close(fd);
+ return caps;
+}
+
+#endif // defined(__linux__)
+#endif // _M_IX86_AMD64
+
+BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
+{
+ BOOL ret = FALSE;
+#ifdef _M_ARM
+#ifdef __linux__
+ unsigned caps;
+ caps = GetARMCPUCaps();
+
+ switch (ProcessorFeature)
+ {
+ case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
+ case PF_ARM_NEON:
+ if (caps & HWCAP_NEON)
+ ret = TRUE;
+ break;
+ case PF_ARM_THUMB:
+ if (caps & HWCAP_THUMB)
+ ret = TRUE;
+ case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
+ if (caps & HWCAP_VFPD32)
+ ret = TRUE;
+ case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
+ if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
+ ret = TRUE;
+ case PF_ARM_VFP3:
+ if (caps & HWCAP_VFPv3)
+ ret = TRUE;
+ break;
+ case PF_ARM_JAZELLE:
+ if (caps & HWCAP_JAVA)
+ ret = TRUE;
+ break;
+ case PF_ARM_DSP:
+ if (caps & HWCAP_EDSP)
+ ret = TRUE;
+ break;
+ case PF_ARM_MPU:
+ if (caps & HWCAP_EDSP)
+ ret = TRUE;
+ break;
+ case PF_ARM_THUMB2:
+ if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
+ ret = TRUE;
+ break;
+ case PF_ARM_T2EE:
+ if (caps & HWCAP_THUMBEE)
+ ret = TRUE;
+ break;
+ case PF_ARM_INTEL_WMMX:
+ if (caps & HWCAP_IWMMXT)
+ ret = TRUE;
+ break;
+ default:
+ break;
+ }
+#endif
+#elif defined(_M_IX86_AMD64)
+#ifdef __GNUC__
+ unsigned a, b, c, d;
+
+ cpuid(1, &a, &b, &c, &d);
+
+ switch (ProcessorFeature)
+ {
+ case PF_MMX_INSTRUCTIONS_AVAILABLE:
+ if (d & D_BIT_MMX)
+ ret = TRUE;
+ break;
+ case PF_XMMI_INSTRUCTIONS_AVAILABLE:
+ if (d & D_BIT_SSE)
+ ret = TRUE;
+ break;
+ case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
+ if (d & D_BIT_SSE2)
+ ret = TRUE;
+ break;
+ case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
+ if (d & D_BIT_3DN)
+ ret = TRUE;
+ break;
+ case PF_SSE3_INSTRUCTIONS_AVAILABLE:
+ if (c & C_BIT_SSE3)
+ ret = TRUE;
+ break;
+ default:
+ break;
+ }
+
+#endif // __GNUC__
+#endif
+ return ret;
+}
+#endif _WIN32
+
+BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
+{
+ BOOL ret = FALSE;
+#ifdef _M_ARM
+#ifdef __linux__
+ unsigned caps;
+ caps = GetARMCPUCaps();
+
+ switch (ProcessorFeature)
+ {
+ case PF_EX_ARM_VFP1:
+ if (caps & HWCAP_VFP)
+ ret = TRUE;
+ break;
+ case PF_EX_ARM_VFP3D16:
+ if (caps & HWCAP_VFPv3D16)
+ ret = TRUE;
+ break;
+ case PF_EX_ARM_VFP4:
+ if (caps & HWCAP_VFPv4)
+ ret = TRUE;
+ break;
+ case PF_EX_ARM_IDIVA:
+ if (caps & HWCAP_IDIVA)
+ ret = TRUE;
+ break;
+ case PF_EX_ARM_IDIVT:
+ if (caps & HWCAP_IDIVT)
+ ret = TRUE;
+ break;
+ }
+#endif // __linux__
+#elif defined(_M_IX86_AMD64)
+ unsigned a, b, c, d;
+ cpuid(1, &a, &b, &c, &d);
+
+ switch (ProcessorFeature)
+ {
+ case PF_EX_3DNOW_PREFETCH:
+ if (c & C_BIT_3DNP)
+ ret = TRUE;
+ break;
+ case PF_EX_SSSE3:
+ if (c & C_BIT_SSSE3)
+ ret = TRUE;
+ break;
+ case PF_EX_SSE41:
+ if (c & C_BIT_SSE41)
+ ret = TRUE;
+ break;
+ case PF_EX_SSE42:
+ if (c & C_BIT_SSE42)
+ ret = TRUE;
+ break;
+#ifdef __AVX__
+ case PF_EX_AVX:
+ case PF_EX_FMA:
+ case PF_EX_AVX_AES:
+ {
+ if ((c & C_BITS_AVX) != C_BITS_AVX)
+ ret = FALSE;
+
+ int e, f;
+ xgetbv(0, e, f);
+
+ if ((e & E_BITS_AVX) == E_BITS_AVX)
+ {
+ switch (ProcessorFeature)
+ {
+ case: PF_EX_AVX:
+ ret = TRUE;
+ break;
+ case: PF_EX_FMA:
+ if (c & C_BIT_FMA)
+ ret = TRUE;
+ break;
+ case: PF_EX_AVX_AES:
+ if (c & C_BIT_AVX_AES)
+ ret = TRUE;
+ break;
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+ break;
+#endif //__AVX__
+ default:
+ break;
+ }
#endif
+ return ret;
+}
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
- TestGetNativeSystemInfo.c)
+ TestGetNativeSystemInfo.c
+ TestCPUFeatures.c
+ )
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
--- /dev/null
+
+#include <winpr/crt.h>
+#include <winpr/sysinfo.h>
+#include <winpr/platform.h>
+
+int TestCPUFeatures(int argc, char* argv[])
+{
+ printf("Base CPU Flags:\n");
+#ifdef _M_IX86_AMD64
+ printf("\tPF_MMX_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_XMMI_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_XMMI64_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_3DNOW_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_SSE3_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\n");
+ printf("Extended CPU Flags (not found in windows API):\n");
+ printf("\tPF_EX_3DNOW_PREFETCH: %s\n", IsProcessorFeaturePresentEx(PF_EX_3DNOW_PREFETCH) ? "yes" : "no");
+ printf("\tPF_EX_SSSE3: %s\n", IsProcessorFeaturePresentEx(PF_EX_SSSE3) ? "yes" : "no");
+ printf("\tPF_EX_SSE41: %s\n", IsProcessorFeaturePresentEx(PF_EX_SSE41) ? "yes" : "no");
+ printf("\tPF_EX_SSE42: %s\n", IsProcessorFeaturePresentEx(PF_EX_SSE42) ? "yes" : "no");
+ printf("\tPF_EX_AVX: %s\n", IsProcessorFeaturePresentEx(PF_EX_AVX) ? "yes" : "no");
+ printf("\tPF_EX_FMA: %s\n", IsProcessorFeaturePresentEx(PF_EX_FMA) ? "yes" : "no");
+ printf("\tPF_EX_AVX_AES: %s\n", IsProcessorFeaturePresentEx(PF_EX_AVX_AES) ? "yes" : "no");
+#elif defined(_M_ARM)
+ printf("\tPF_ARM_NEON_INSTRUCTIONS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_ARM_THUMB: %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB) ? "yes" : "no");
+ printf("\tPF_ARM_VFP_32_REGISTERS_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_ARM_DIVIDE_INSTRUCTION_AVAILABLE: %s\n", IsProcessorFeaturePresent(PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE) ? "yes" : "no");
+ printf("\tPF_ARM_VFP3: %s\n", IsProcessorFeaturePresent(PF_ARM_VFP3) ? "yes" : "no");
+ printf("\tPF_ARM_THUMB: %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB) ? "yes" : "no");
+ printf("\tPF_ARM_JAZELLE: %s\n", IsProcessorFeaturePresent(PF_ARM_JAZELLE) ? "yes" : "no");
+ printf("\tPF_ARM_DSP: %s\n", IsProcessorFeaturePresent(PF_ARM_DSP) ? "yes" : "no");
+ printf("\tPF_ARM_THUMB2: %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB2) ? "yes" : "no");
+ printf("\tPF_ARM_T2EE: %s\n", IsProcessorFeaturePresent(PF_ARM_T2EE) ? "yes" : "no");
+ printf("\tPF_ARM_INTEL_WMMX: %s\n", IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX) ? "yes" : "no");
+ printf("Extended CPU Flags (not found in windows API):\n");
+ printf("\tPF_EX_ARM_VFP1: %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP1) ? "yes" : "no");
+ printf("\tPF_EX_ARM_VFP3D16: %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP3D16) ? "yes" : "no");
+ printf("\tPF_EX_ARM_VFP4: %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP4) ? "yes" : "no");
+ printf("\tPF_EX_ARM_IDIVA: %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_IDIVA) ? "yes" : "no");
+ printf("\tPF_EX_ARM_IDIVT: %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_IDIVT) ? "yes" : "no");
+#endif
+ printf("\n");
+ return 0;
+}