From: Bernhard Miklautz Date: Wed, 27 Feb 2013 09:17:24 +0000 (+0100) Subject: winpr/sysinfo: added IsProcessorFeaturePresent and IsProcessorFeaturePresentEx X-Git-Tag: 1.1.0-beta1~26^2~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf7f7f0f603d53ebc47cb61c3392a07af4046e66;p=platform%2Fupstream%2Ffreerdp.git winpr/sysinfo: added IsProcessorFeaturePresent and IsProcessorFeaturePresentEx 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 --- diff --git a/libfreerdp/primitives/primitives.c b/libfreerdp/primitives/primitives.c index 99c71e3..245a6ce 100644 --- a/libfreerdp/primitives/primitives.c +++ b/libfreerdp/primitives/primitives.c @@ -247,7 +247,7 @@ static const flagpair_t x86_flags[] = { { 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" }, @@ -256,7 +256,7 @@ static const flagpair_t x86_flags[] = { 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" }, }; @@ -268,7 +268,7 @@ static const flagpair_t arm_flags[] = { 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" }, }; diff --git a/winpr/include/winpr/sysinfo.h b/winpr/include/winpr/sysinfo.h index 2b37ab8..001232a 100644 --- a/winpr/include/winpr/sysinfo.h +++ b/winpr/include/winpr/sysinfo.h @@ -69,14 +69,13 @@ #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 @@ -95,6 +94,54 @@ #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 @@ -243,7 +290,10 @@ WINPR_API VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); WINPR_API DWORD GetTickCount(void); +WINPR_API BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature); #endif +WINPR_API BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature); + #endif /* WINPR_SYSINFO_H */ diff --git a/winpr/libwinpr/sysinfo/sysinfo.c b/winpr/libwinpr/sysinfo/sysinfo.c index 6f574fe..0dddf6a 100644 --- a/winpr/libwinpr/sysinfo/sysinfo.c +++ b/winpr/libwinpr/sysinfo/sysinfo.c @@ -3,6 +3,7 @@ * System Information * * Copyright 2012 Marc-Andre Moreau + * Copyright 2013 Bernhard Miklautz * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +23,13 @@ #endif #include +#include + +#if defined(__linux__) && defined(__GNUC__) +#include +#include +#include +#endif /** * api-ms-win-core-sysinfo-l1-1-1.dll: @@ -109,7 +117,7 @@ DWORD GetNumberOfProcessors() { DWORD numCPUs = 1; - /* TODO: Android and iOS */ + /* TODO: iOS */ #if defined(__linux__) || defined(__sun) || defined(_AIX) numCPUs = (DWORD) sysconf(_SC_NPROCESSORS_ONLN); @@ -331,4 +339,305 @@ DWORD GetTickCount(void) 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; +} diff --git a/winpr/libwinpr/sysinfo/test/CMakeLists.txt b/winpr/libwinpr/sysinfo/test/CMakeLists.txt index 79ba944..3eb8101 100644 --- a/winpr/libwinpr/sysinfo/test/CMakeLists.txt +++ b/winpr/libwinpr/sysinfo/test/CMakeLists.txt @@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_SYSINFO") 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} diff --git a/winpr/libwinpr/sysinfo/test/TestCPUFeatures.c b/winpr/libwinpr/sysinfo/test/TestCPUFeatures.c new file mode 100644 index 0000000..e7c7e83 --- /dev/null +++ b/winpr/libwinpr/sysinfo/test/TestCPUFeatures.c @@ -0,0 +1,45 @@ + +#include +#include +#include + +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; +}