external: import cpu_features library
Taken from https://github.com/google/cpu_features at revision 26133d3b620c2c27f31d571efd27371100f891e9
This commit is contained in:
parent
69e75c90e7
commit
931aca28e3
55 changed files with 5724 additions and 0 deletions
36
external/cpu_features/src/cpuid_x86_clang_gcc.c
vendored
Normal file
36
external/cpu_features/src/cpuid_x86_clang_gcc.c
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/cpuid_x86.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
|
||||
|
||||
#include <cpuid.h>
|
||||
|
||||
Leaf CpuId(uint32_t leaf_id) {
|
||||
Leaf leaf;
|
||||
__cpuid_count(leaf_id, 0, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx);
|
||||
return leaf;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax(void) {
|
||||
uint32_t eax, edx;
|
||||
__asm("XGETBV" : "=a"(eax), "=d"(edx) : "c"(0));
|
||||
return eax;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_COMPILER_CLANG) ||
|
||||
// defined(CPU_FEATURES_COMPILER_GCC)
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86)
|
||||
34
external/cpu_features/src/cpuid_x86_msvc.c
vendored
Normal file
34
external/cpu_features/src/cpuid_x86_msvc.c
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/cpuid_x86.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_MSC)
|
||||
#include <immintrin.h>
|
||||
#include <intrin.h> // For __cpuidex()
|
||||
|
||||
Leaf CpuId(uint32_t leaf_id) {
|
||||
Leaf leaf;
|
||||
int data[4];
|
||||
__cpuid(data, leaf_id);
|
||||
leaf.eax = data[0];
|
||||
leaf.ebx = data[1];
|
||||
leaf.ecx = data[2];
|
||||
leaf.edx = data[3];
|
||||
return leaf;
|
||||
}
|
||||
|
||||
uint32_t GetXCR0Eax(void) { return _xgetbv(0); }
|
||||
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86) && defined(CPU_FEATURES_COMPILER_MSC)
|
||||
141
external/cpu_features/src/cpuinfo_aarch64.c
vendored
Normal file
141
external/cpu_features/src/cpuinfo_aarch64.c
vendored
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpuinfo_aarch64.h"
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
DECLARE_SETTER(Aarch64Features, fp)
|
||||
DECLARE_SETTER(Aarch64Features, asimd)
|
||||
DECLARE_SETTER(Aarch64Features, aes)
|
||||
DECLARE_SETTER(Aarch64Features, pmull)
|
||||
DECLARE_SETTER(Aarch64Features, sha1)
|
||||
DECLARE_SETTER(Aarch64Features, sha2)
|
||||
DECLARE_SETTER(Aarch64Features, crc32)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{AARCH64_HWCAP_FP, 0}, "fp", &set_fp}, //
|
||||
{{AARCH64_HWCAP_ASIMD, 0}, "asimd", &set_asimd}, //
|
||||
{{AARCH64_HWCAP_AES, 0}, "aes", &set_aes}, //
|
||||
{{AARCH64_HWCAP_PMULL, 0}, "pmull", &set_pmull}, //
|
||||
{{AARCH64_HWCAP_SHA1, 0}, "sha1", &set_sha1}, //
|
||||
{{AARCH64_HWCAP_SHA2, 0}, "sha2", &set_sha2}, //
|
||||
{{AARCH64_HWCAP_CRC32, 0}, "crc32", &set_crc32}, //
|
||||
};
|
||||
|
||||
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
|
||||
|
||||
static bool HandleAarch64Line(const LineResult result,
|
||||
Aarch64Info* const info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(Aarch64Info* const info) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const Aarch64Info kEmptyAarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
Aarch64Info info = kEmptyAarch64Info;
|
||||
|
||||
FillProcCpuInfoData(&info);
|
||||
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
|
||||
CpuFeatures_GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||
Aarch64FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case AARCH64_FP:
|
||||
return features->fp;
|
||||
case AARCH64_ASIMD:
|
||||
return features->asimd;
|
||||
case AARCH64_AES:
|
||||
return features->aes;
|
||||
case AARCH64_PMULL:
|
||||
return features->pmull;
|
||||
case AARCH64_SHA1:
|
||||
return features->sha1;
|
||||
case AARCH64_SHA2:
|
||||
return features->sha2;
|
||||
case AARCH64_CRC32:
|
||||
return features->crc32;
|
||||
case AARCH64_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case AARCH64_FP:
|
||||
return "fp";
|
||||
case AARCH64_ASIMD:
|
||||
return "asimd";
|
||||
case AARCH64_AES:
|
||||
return "aes";
|
||||
case AARCH64_PMULL:
|
||||
return "pmull";
|
||||
case AARCH64_SHA1:
|
||||
return "sha1";
|
||||
case AARCH64_SHA2:
|
||||
return "sha2";
|
||||
case AARCH64_CRC32:
|
||||
return "crc32";
|
||||
case AARCH64_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
||||
259
external/cpu_features/src/cpuinfo_arm.c
vendored
Normal file
259
external/cpu_features/src/cpuinfo_arm.c
vendored
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpuinfo_arm.h"
|
||||
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
DECLARE_SETTER(ArmFeatures, vfp)
|
||||
DECLARE_SETTER(ArmFeatures, iwmmxt)
|
||||
DECLARE_SETTER(ArmFeatures, neon)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv3)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv3d16)
|
||||
DECLARE_SETTER(ArmFeatures, vfpv4)
|
||||
DECLARE_SETTER(ArmFeatures, idiva)
|
||||
DECLARE_SETTER(ArmFeatures, idivt)
|
||||
DECLARE_SETTER(ArmFeatures, aes)
|
||||
DECLARE_SETTER(ArmFeatures, pmull)
|
||||
DECLARE_SETTER(ArmFeatures, sha1)
|
||||
DECLARE_SETTER(ArmFeatures, sha2)
|
||||
DECLARE_SETTER(ArmFeatures, crc32)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{ARM_HWCAP_VFP, 0}, "vfp", &set_vfp}, //
|
||||
{{ARM_HWCAP_IWMMXT, 0}, "iwmmxt", &set_iwmmxt}, //
|
||||
{{ARM_HWCAP_NEON, 0}, "neon", &set_neon}, //
|
||||
{{ARM_HWCAP_VFPV3, 0}, "vfpv3", &set_vfpv3}, //
|
||||
{{ARM_HWCAP_VFPV3D16, 0}, "vfpv3d16", &set_vfpv3d16}, //
|
||||
{{ARM_HWCAP_VFPV4, 0}, "vfpv4", &set_vfpv4}, //
|
||||
{{ARM_HWCAP_IDIVA, 0}, "idiva", &set_idiva}, //
|
||||
{{ARM_HWCAP_IDIVT, 0}, "idivt", &set_idivt}, //
|
||||
{{0, ARM_HWCAP2_AES}, "aes", &set_aes}, //
|
||||
{{0, ARM_HWCAP2_PMULL}, "pmull", &set_pmull}, //
|
||||
{{0, ARM_HWCAP2_SHA1}, "sha1", &set_sha1}, //
|
||||
{{0, ARM_HWCAP2_SHA2}, "sha2", &set_sha2}, //
|
||||
{{0, ARM_HWCAP2_CRC32}, "crc32", &set_crc32}, //
|
||||
};
|
||||
|
||||
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
|
||||
|
||||
typedef struct {
|
||||
bool processor_reports_armv6;
|
||||
bool hardware_reports_goldfish;
|
||||
} ProcCpuInfoData;
|
||||
|
||||
static int IndexOfNonDigit(StringView str) {
|
||||
size_t index = 0;
|
||||
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
|
||||
str = CpuFeatures_StringView_PopFront(str, 1);
|
||||
++index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
|
||||
ProcCpuInfoData* const proc_info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, &info->features);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
|
||||
// CPU architecture is a number that may be followed by letters. e.g.
|
||||
// "6TEJ", "7".
|
||||
const StringView digits =
|
||||
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
|
||||
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor"))) {
|
||||
proc_info->processor_reports_armv6 =
|
||||
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
|
||||
proc_info->hardware_reports_goldfish =
|
||||
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static uint32_t GetCpuId(const ArmInfo* const info) {
|
||||
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
|
||||
(ExtractBitRange(info->variant, 3, 0) << 20) |
|
||||
(ExtractBitRange(info->part, 11, 0) << 4) |
|
||||
(ExtractBitRange(info->revision, 3, 0) << 0);
|
||||
}
|
||||
|
||||
static void FixErrors(ArmInfo* const info,
|
||||
ProcCpuInfoData* const proc_cpu_info_data) {
|
||||
// Fixing Samsung kernel reporting invalid cpu architecture.
|
||||
// http://code.google.com/p/android/issues/detail?id=10812
|
||||
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
|
||||
info->architecture = 6;
|
||||
}
|
||||
|
||||
// Handle kernel configuration bugs that prevent the correct reporting of CPU
|
||||
// features.
|
||||
switch (GetCpuId(info)) {
|
||||
case 0x4100C080:
|
||||
// Special case: The emulator-specific Android 4.2 kernel fails to report
|
||||
// support for the 32-bit ARM IDIV instruction. Technically, this is a
|
||||
// feature of the virtual CPU implemented by the emulator. Note that it
|
||||
// could also support Thumb IDIV in the future, and this will have to be
|
||||
// slightly updated.
|
||||
if (info->architecture >= 7 &&
|
||||
proc_cpu_info_data->hardware_reports_goldfish) {
|
||||
info->features.idiva = true;
|
||||
}
|
||||
break;
|
||||
case 0x511004D0:
|
||||
// https://crbug.com/341598.
|
||||
info->features.neon = false;
|
||||
break;
|
||||
case 0x510006F2:
|
||||
case 0x510006F3:
|
||||
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
|
||||
// IDIV support.
|
||||
info->features.idiva = true;
|
||||
info->features.idivt = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Propagate cpu features.
|
||||
if (info->features.vfpv4) info->features.vfpv3 = true;
|
||||
if (info->features.neon) info->features.vfpv3 = true;
|
||||
if (info->features.vfpv3) info->features.vfp = true;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(ArmInfo* const info,
|
||||
ProcCpuInfoData* proc_cpu_info_data) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
|
||||
proc_cpu_info_data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const ArmInfo kEmptyArmInfo;
|
||||
|
||||
static const ProcCpuInfoData kEmptyProcCpuInfoData;
|
||||
|
||||
ArmInfo GetArmInfo(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
ArmInfo info = kEmptyArmInfo;
|
||||
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
|
||||
|
||||
FillProcCpuInfoData(&info, &proc_cpu_info_data);
|
||||
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
|
||||
CpuFeatures_GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
|
||||
FixErrors(&info, &proc_cpu_info_data);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetArmFeaturesEnumValue(const ArmFeatures* features,
|
||||
ArmFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case ARM_VFP:
|
||||
return features->vfp;
|
||||
case ARM_IWMMXT:
|
||||
return features->iwmmxt;
|
||||
case ARM_NEON:
|
||||
return features->neon;
|
||||
case ARM_VFPV3:
|
||||
return features->vfpv3;
|
||||
case ARM_VFPV3D16:
|
||||
return features->vfpv3d16;
|
||||
case ARM_VFPV4:
|
||||
return features->vfpv4;
|
||||
case ARM_IDIVA:
|
||||
return features->idiva;
|
||||
case ARM_IDIVT:
|
||||
return features->idivt;
|
||||
case ARM_AES:
|
||||
return features->aes;
|
||||
case ARM_PMULL:
|
||||
return features->pmull;
|
||||
case ARM_SHA1:
|
||||
return features->sha1;
|
||||
case ARM_SHA2:
|
||||
return features->sha2;
|
||||
case ARM_CRC32:
|
||||
return features->crc32;
|
||||
case ARM_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case ARM_VFP:
|
||||
return "vfp";
|
||||
case ARM_IWMMXT:
|
||||
return "iwmmxt";
|
||||
case ARM_NEON:
|
||||
return "neon";
|
||||
case ARM_VFPV3:
|
||||
return "vfpv3";
|
||||
case ARM_VFPV3D16:
|
||||
return "vfpv3d16";
|
||||
case ARM_VFPV4:
|
||||
return "vfpv4";
|
||||
case ARM_IDIVA:
|
||||
return "idiva";
|
||||
case ARM_IDIVT:
|
||||
return "idivt";
|
||||
case ARM_AES:
|
||||
return "aes";
|
||||
case ARM_PMULL:
|
||||
return "pmull";
|
||||
case ARM_SHA1:
|
||||
return "sha1";
|
||||
case ARM_SHA2:
|
||||
return "sha2";
|
||||
case ARM_CRC32:
|
||||
return "crc32";
|
||||
case ARM_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
||||
98
external/cpu_features/src/cpuinfo_mips.c
vendored
Normal file
98
external/cpu_features/src/cpuinfo_mips.c
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpuinfo_mips.h"
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
DECLARE_SETTER(MipsFeatures, msa)
|
||||
DECLARE_SETTER(MipsFeatures, eva)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{MIPS_HWCAP_MSA, 0}, "msa", &set_msa}, //
|
||||
{{MIPS_HWCAP_EVA, 0}, "eva", &set_eva}, //
|
||||
};
|
||||
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
|
||||
|
||||
static bool HandleMipsLine(const LineResult result,
|
||||
MipsFeatures* const features) {
|
||||
StringView key, value;
|
||||
// See tests for an example.
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
|
||||
CpuFeatures_SetFromFlags(kConfigsSize, kConfigs, value, features);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(MipsFeatures* const features) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const MipsInfo kEmptyMipsInfo;
|
||||
|
||||
MipsInfo GetMipsInfo(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
MipsInfo info = kEmptyMipsInfo;
|
||||
|
||||
FillProcCpuInfoData(&info.features);
|
||||
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
|
||||
CpuFeatures_GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
return info;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||
MipsFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case MIPS_MSA:
|
||||
return features->msa;
|
||||
case MIPS_EVA:
|
||||
return features->eva;
|
||||
case MIPS_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case MIPS_MSA:
|
||||
return "msa";
|
||||
case MIPS_EVA:
|
||||
return "eva";
|
||||
case MIPS_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown feature";
|
||||
}
|
||||
358
external/cpu_features/src/cpuinfo_ppc.c
vendored
Normal file
358
external/cpu_features/src/cpuinfo_ppc.c
vendored
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
// Copyright 2018 IBM.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpuinfo_ppc.h"
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
DECLARE_SETTER(PPCFeatures, ppc32)
|
||||
DECLARE_SETTER(PPCFeatures, ppc64)
|
||||
DECLARE_SETTER(PPCFeatures, ppc601)
|
||||
DECLARE_SETTER(PPCFeatures, altivec)
|
||||
DECLARE_SETTER(PPCFeatures, fpu)
|
||||
DECLARE_SETTER(PPCFeatures, mmu)
|
||||
DECLARE_SETTER(PPCFeatures, mac_4xx)
|
||||
DECLARE_SETTER(PPCFeatures, unifiedcache)
|
||||
DECLARE_SETTER(PPCFeatures, spe)
|
||||
DECLARE_SETTER(PPCFeatures, efpsingle)
|
||||
DECLARE_SETTER(PPCFeatures, efpdouble)
|
||||
DECLARE_SETTER(PPCFeatures, no_tb)
|
||||
DECLARE_SETTER(PPCFeatures, power4)
|
||||
DECLARE_SETTER(PPCFeatures, power5)
|
||||
DECLARE_SETTER(PPCFeatures, power5plus)
|
||||
DECLARE_SETTER(PPCFeatures, cell)
|
||||
DECLARE_SETTER(PPCFeatures, booke)
|
||||
DECLARE_SETTER(PPCFeatures, smt)
|
||||
DECLARE_SETTER(PPCFeatures, icachesnoop)
|
||||
DECLARE_SETTER(PPCFeatures, arch205)
|
||||
DECLARE_SETTER(PPCFeatures, pa6t)
|
||||
DECLARE_SETTER(PPCFeatures, dfp)
|
||||
DECLARE_SETTER(PPCFeatures, power6ext)
|
||||
DECLARE_SETTER(PPCFeatures, arch206)
|
||||
DECLARE_SETTER(PPCFeatures, vsx)
|
||||
DECLARE_SETTER(PPCFeatures, pseries_perfmon_compat)
|
||||
DECLARE_SETTER(PPCFeatures, truele)
|
||||
DECLARE_SETTER(PPCFeatures, ppcle)
|
||||
DECLARE_SETTER(PPCFeatures, arch207)
|
||||
DECLARE_SETTER(PPCFeatures, htm)
|
||||
DECLARE_SETTER(PPCFeatures, dscr)
|
||||
DECLARE_SETTER(PPCFeatures, ebb)
|
||||
DECLARE_SETTER(PPCFeatures, isel)
|
||||
DECLARE_SETTER(PPCFeatures, tar)
|
||||
DECLARE_SETTER(PPCFeatures, vcrypto)
|
||||
DECLARE_SETTER(PPCFeatures, htm_nosc)
|
||||
DECLARE_SETTER(PPCFeatures, arch300)
|
||||
DECLARE_SETTER(PPCFeatures, ieee128)
|
||||
DECLARE_SETTER(PPCFeatures, darn)
|
||||
DECLARE_SETTER(PPCFeatures, scv)
|
||||
DECLARE_SETTER(PPCFeatures, htm_no_suspend)
|
||||
|
||||
static const CapabilityConfig kConfigs[] = {
|
||||
{{PPC_FEATURE_32, 0}, "ppc32", &set_ppc32},
|
||||
{{PPC_FEATURE_64, 0}, "ppc64", &set_ppc64},
|
||||
{{PPC_FEATURE_601_INSTR, 0}, "ppc601", &set_ppc601},
|
||||
{{PPC_FEATURE_HAS_ALTIVEC, 0}, "altivec", &set_altivec},
|
||||
{{PPC_FEATURE_HAS_FPU, 0}, "fpu", &set_fpu},
|
||||
{{PPC_FEATURE_HAS_MMU, 0}, "mmu", &set_mmu},
|
||||
{{PPC_FEATURE_HAS_4xxMAC, 0}, "4xxmac", &set_mac_4xx},
|
||||
{{PPC_FEATURE_UNIFIED_CACHE, 0}, "ucache", &set_unifiedcache},
|
||||
{{PPC_FEATURE_HAS_SPE, 0}, "spe", &set_spe},
|
||||
{{PPC_FEATURE_HAS_EFP_SINGLE, 0}, "efpsingle", &set_efpsingle},
|
||||
{{PPC_FEATURE_HAS_EFP_DOUBLE, 0}, "efpdouble", &set_efpdouble},
|
||||
{{PPC_FEATURE_NO_TB, 0}, "notb", &set_no_tb},
|
||||
{{PPC_FEATURE_POWER4, 0}, "power4", &set_power4},
|
||||
{{PPC_FEATURE_POWER5, 0}, "power5", &set_power5},
|
||||
{{PPC_FEATURE_POWER5_PLUS, 0}, "power5+", &set_power5plus},
|
||||
{{PPC_FEATURE_CELL, 0}, "cellbe", &set_cell},
|
||||
{{PPC_FEATURE_BOOKE, 0}, "booke", &set_booke},
|
||||
{{PPC_FEATURE_SMT, 0}, "smt", &set_smt},
|
||||
{{PPC_FEATURE_ICACHE_SNOOP, 0}, "ic_snoop", &set_icachesnoop},
|
||||
{{PPC_FEATURE_ARCH_2_05, 0}, "arch_2_05", &set_arch205},
|
||||
{{PPC_FEATURE_PA6T, 0}, "pa6t", &set_pa6t},
|
||||
{{PPC_FEATURE_HAS_DFP, 0}, "dfp", &set_dfp},
|
||||
{{PPC_FEATURE_POWER6_EXT, 0}, "power6x", &set_power6ext},
|
||||
{{PPC_FEATURE_ARCH_2_06, 0}, "arch_2_06", &set_arch206},
|
||||
{{PPC_FEATURE_HAS_VSX, 0}, "vsx", &set_vsx},
|
||||
{{PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0},
|
||||
"archpmu",
|
||||
&set_pseries_perfmon_compat},
|
||||
{{PPC_FEATURE_TRUE_LE, 0}, "true_le", &set_truele},
|
||||
{{PPC_FEATURE_PPC_LE, 0}, "ppcle", &set_ppcle},
|
||||
{{0, PPC_FEATURE2_ARCH_2_07}, "arch_2_07", &set_arch207},
|
||||
{{0, PPC_FEATURE2_HTM}, "htm", &set_htm},
|
||||
{{0, PPC_FEATURE2_DSCR}, "dscr", &set_dscr},
|
||||
{{0, PPC_FEATURE2_EBB}, "ebb", &set_ebb},
|
||||
{{0, PPC_FEATURE2_ISEL}, "isel", &set_isel},
|
||||
{{0, PPC_FEATURE2_TAR}, "tar", &set_tar},
|
||||
{{0, PPC_FEATURE2_VEC_CRYPTO}, "vcrypto", &set_vcrypto},
|
||||
{{0, PPC_FEATURE2_HTM_NOSC}, "htm-nosc", &set_htm_nosc},
|
||||
{{0, PPC_FEATURE2_ARCH_3_00}, "arch_3_00", &set_arch300},
|
||||
{{0, PPC_FEATURE2_HAS_IEEE128}, "ieee128", &set_ieee128},
|
||||
{{0, PPC_FEATURE2_DARN}, "darn", &set_darn},
|
||||
{{0, PPC_FEATURE2_SCV}, "scv", &set_scv},
|
||||
{{0, PPC_FEATURE2_HTM_NO_SUSPEND}, "htm-no-suspend", &set_htm_no_suspend},
|
||||
};
|
||||
static const size_t kConfigsSize = sizeof(kConfigs) / sizeof(CapabilityConfig);
|
||||
|
||||
static bool HandlePPCLine(const LineResult result,
|
||||
PPCPlatformStrings* const strings) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_HasWord(key, "platform")) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->platform,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->model,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->machine,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->cpu,
|
||||
sizeof(strings->platform));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const PPCInfo kEmptyPPCInfo;
|
||||
|
||||
PPCInfo GetPPCInfo(void) {
|
||||
/*
|
||||
* On Power feature flags aren't currently in cpuinfo so we only look at
|
||||
* the auxilary vector.
|
||||
*/
|
||||
PPCInfo info = kEmptyPPCInfo;
|
||||
|
||||
CpuFeatures_OverrideFromHwCaps(kConfigsSize, kConfigs,
|
||||
CpuFeatures_GetHardwareCapabilities(),
|
||||
&info.features);
|
||||
return info;
|
||||
}
|
||||
|
||||
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
|
||||
|
||||
PPCPlatformStrings GetPPCPlatformStrings(void) {
|
||||
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
|
||||
|
||||
FillProcCpuInfoData(&strings);
|
||||
strings.type = CpuFeatures_GetPlatformType();
|
||||
return strings;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetPPCFeaturesEnumValue(const PPCFeatures* features,
|
||||
PPCFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case PPC_32:
|
||||
return features->ppc32;
|
||||
case PPC_64:
|
||||
return features->ppc64;
|
||||
case PPC_601_INSTR:
|
||||
return features->ppc601;
|
||||
case PPC_HAS_ALTIVEC:
|
||||
return features->altivec;
|
||||
case PPC_HAS_FPU:
|
||||
return features->fpu;
|
||||
case PPC_HAS_MMU:
|
||||
return features->mmu;
|
||||
case PPC_HAS_4xxMAC:
|
||||
return features->mac_4xx;
|
||||
case PPC_UNIFIED_CACHE:
|
||||
return features->unifiedcache;
|
||||
case PPC_HAS_SPE:
|
||||
return features->spe;
|
||||
case PPC_HAS_EFP_SINGLE:
|
||||
return features->efpsingle;
|
||||
case PPC_HAS_EFP_DOUBLE:
|
||||
return features->efpdouble;
|
||||
case PPC_NO_TB:
|
||||
return features->no_tb;
|
||||
case PPC_POWER4:
|
||||
return features->power4;
|
||||
case PPC_POWER5:
|
||||
return features->power5;
|
||||
case PPC_POWER5_PLUS:
|
||||
return features->power5plus;
|
||||
case PPC_CELL:
|
||||
return features->cell;
|
||||
case PPC_BOOKE:
|
||||
return features->booke;
|
||||
case PPC_SMT:
|
||||
return features->smt;
|
||||
case PPC_ICACHE_SNOOP:
|
||||
return features->icachesnoop;
|
||||
case PPC_ARCH_2_05:
|
||||
return features->arch205;
|
||||
case PPC_PA6T:
|
||||
return features->pa6t;
|
||||
case PPC_HAS_DFP:
|
||||
return features->dfp;
|
||||
case PPC_POWER6_EXT:
|
||||
return features->power6ext;
|
||||
case PPC_ARCH_2_06:
|
||||
return features->arch206;
|
||||
case PPC_HAS_VSX:
|
||||
return features->vsx;
|
||||
case PPC_PSERIES_PERFMON_COMPAT:
|
||||
return features->pseries_perfmon_compat;
|
||||
case PPC_TRUE_LE:
|
||||
return features->truele;
|
||||
case PPC_PPC_LE:
|
||||
return features->ppcle;
|
||||
case PPC_ARCH_2_07:
|
||||
return features->arch207;
|
||||
case PPC_HTM:
|
||||
return features->htm;
|
||||
case PPC_DSCR:
|
||||
return features->dscr;
|
||||
case PPC_EBB:
|
||||
return features->ebb;
|
||||
case PPC_ISEL:
|
||||
return features->isel;
|
||||
case PPC_TAR:
|
||||
return features->tar;
|
||||
case PPC_VEC_CRYPTO:
|
||||
return features->vcrypto;
|
||||
case PPC_HTM_NOSC:
|
||||
return features->htm_nosc;
|
||||
case PPC_ARCH_3_00:
|
||||
return features->arch300;
|
||||
case PPC_HAS_IEEE128:
|
||||
return features->ieee128;
|
||||
case PPC_DARN:
|
||||
return features->darn;
|
||||
case PPC_SCV:
|
||||
return features->scv;
|
||||
case PPC_HTM_NO_SUSPEND:
|
||||
return features->htm_no_suspend;
|
||||
case PPC_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Have used the same names as glibc */
|
||||
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
|
||||
switch (value) {
|
||||
case PPC_32:
|
||||
return "ppc32";
|
||||
case PPC_64:
|
||||
return "ppc64";
|
||||
case PPC_601_INSTR:
|
||||
return "ppc601";
|
||||
case PPC_HAS_ALTIVEC:
|
||||
return "altivec";
|
||||
case PPC_HAS_FPU:
|
||||
return "fpu";
|
||||
case PPC_HAS_MMU:
|
||||
return "mmu";
|
||||
case PPC_HAS_4xxMAC:
|
||||
return "4xxmac";
|
||||
case PPC_UNIFIED_CACHE:
|
||||
return "ucache";
|
||||
case PPC_HAS_SPE:
|
||||
return "spe";
|
||||
case PPC_HAS_EFP_SINGLE:
|
||||
return "efpsingle";
|
||||
case PPC_HAS_EFP_DOUBLE:
|
||||
return "efpdouble";
|
||||
case PPC_NO_TB:
|
||||
return "notb";
|
||||
case PPC_POWER4:
|
||||
return "power4";
|
||||
case PPC_POWER5:
|
||||
return "power5";
|
||||
case PPC_POWER5_PLUS:
|
||||
return "power5+";
|
||||
case PPC_CELL:
|
||||
return "cellbe";
|
||||
case PPC_BOOKE:
|
||||
return "booke";
|
||||
case PPC_SMT:
|
||||
return "smt";
|
||||
case PPC_ICACHE_SNOOP:
|
||||
return "ic_snoop";
|
||||
case PPC_ARCH_2_05:
|
||||
return "arch_2_05";
|
||||
case PPC_PA6T:
|
||||
return "pa6t";
|
||||
case PPC_HAS_DFP:
|
||||
return "dfp";
|
||||
case PPC_POWER6_EXT:
|
||||
return "power6x";
|
||||
case PPC_ARCH_2_06:
|
||||
return "arch_2_06";
|
||||
case PPC_HAS_VSX:
|
||||
return "vsx";
|
||||
case PPC_PSERIES_PERFMON_COMPAT:
|
||||
return "archpmu";
|
||||
case PPC_TRUE_LE:
|
||||
return "true_le";
|
||||
case PPC_PPC_LE:
|
||||
return "ppcle";
|
||||
case PPC_ARCH_2_07:
|
||||
return "arch_2_07";
|
||||
case PPC_HTM:
|
||||
return "htm";
|
||||
case PPC_DSCR:
|
||||
return "dscr";
|
||||
case PPC_EBB:
|
||||
return "ebb";
|
||||
case PPC_ISEL:
|
||||
return "isel";
|
||||
case PPC_TAR:
|
||||
return "tar";
|
||||
case PPC_VEC_CRYPTO:
|
||||
return "vcrypto";
|
||||
case PPC_HTM_NOSC:
|
||||
return "htm-nosc";
|
||||
case PPC_ARCH_3_00:
|
||||
return "arch_3_00";
|
||||
case PPC_HAS_IEEE128:
|
||||
return "ieee128";
|
||||
case PPC_DARN:
|
||||
return "darn";
|
||||
case PPC_SCV:
|
||||
return "scv";
|
||||
case PPC_HTM_NO_SUSPEND:
|
||||
return "htm-no-suspend";
|
||||
case PPC_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown_feature";
|
||||
}
|
||||
447
external/cpu_features/src/cpuinfo_x86.c
vendored
Normal file
447
external/cpu_features/src/cpuinfo_x86.c
vendored
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpuinfo_x86.h"
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/cpuid_x86.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static const Leaf kEmptyLeaf;
|
||||
|
||||
static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
|
||||
if (leaf_id <= max_cpuid_leaf) {
|
||||
return CpuId(leaf_id);
|
||||
} else {
|
||||
return kEmptyLeaf;
|
||||
}
|
||||
}
|
||||
|
||||
#define MASK_XMM 0x2
|
||||
#define MASK_YMM 0x4
|
||||
#define MASK_MASKREG 0x20
|
||||
#define MASK_ZMM0_15 0x40
|
||||
#define MASK_ZMM16_31 0x80
|
||||
|
||||
static bool HasMask(uint32_t value, uint32_t mask) {
|
||||
return (value & mask) == mask;
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores xmm registers during context
|
||||
// switches.
|
||||
static bool HasXmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM);
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores ymm registers during context
|
||||
// switches.
|
||||
static bool HasYmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM | MASK_YMM);
|
||||
}
|
||||
|
||||
// Checks that operating system saves and restores zmm registers during context
|
||||
// switches.
|
||||
static bool HasZmmOsXSave(uint32_t xcr0_eax) {
|
||||
return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 |
|
||||
MASK_ZMM16_31);
|
||||
}
|
||||
|
||||
static void SetVendor(const Leaf leaf, char* const vendor) {
|
||||
*(uint32_t*)(vendor) = leaf.ebx;
|
||||
*(uint32_t*)(vendor + 4) = leaf.edx;
|
||||
*(uint32_t*)(vendor + 8) = leaf.ecx;
|
||||
vendor[12] = '\0';
|
||||
}
|
||||
|
||||
static int IsVendor(const Leaf leaf, const char* const name) {
|
||||
const uint32_t ebx = *(const uint32_t*)(name);
|
||||
const uint32_t edx = *(const uint32_t*)(name + 4);
|
||||
const uint32_t ecx = *(const uint32_t*)(name + 8);
|
||||
return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
|
||||
}
|
||||
|
||||
// Reference https://en.wikipedia.org/wiki/CPUID.
|
||||
static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info) {
|
||||
const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
|
||||
const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
|
||||
|
||||
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
|
||||
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
|
||||
const uint32_t xcr0_eax = (have_xsave && have_osxsave) ? GetXCR0Eax() : 0;
|
||||
const bool have_sse_os_support = HasXmmOsXSave(xcr0_eax);
|
||||
const bool have_avx_os_support = HasYmmOsXSave(xcr0_eax);
|
||||
const bool have_avx512_os_support = HasZmmOsXSave(xcr0_eax);
|
||||
|
||||
const uint32_t family = ExtractBitRange(leaf_1.eax, 11, 8);
|
||||
const uint32_t extended_family = ExtractBitRange(leaf_1.eax, 27, 20);
|
||||
const uint32_t model = ExtractBitRange(leaf_1.eax, 7, 4);
|
||||
const uint32_t extended_model = ExtractBitRange(leaf_1.eax, 19, 16);
|
||||
|
||||
X86Features* const features = &info->features;
|
||||
|
||||
info->family = extended_family + family;
|
||||
info->model = (extended_model << 4) + model;
|
||||
info->stepping = ExtractBitRange(leaf_1.eax, 3, 0);
|
||||
|
||||
features->smx = IsBitSet(leaf_1.ecx, 6);
|
||||
features->cx16 = IsBitSet(leaf_1.ecx, 13);
|
||||
features->aes = IsBitSet(leaf_1.ecx, 25);
|
||||
features->f16c = IsBitSet(leaf_1.ecx, 29);
|
||||
features->sgx = IsBitSet(leaf_7.ebx, 2);
|
||||
features->bmi1 = IsBitSet(leaf_7.ebx, 3);
|
||||
features->bmi2 = IsBitSet(leaf_7.ebx, 8);
|
||||
features->erms = IsBitSet(leaf_7.ebx, 9);
|
||||
features->vpclmulqdq = IsBitSet(leaf_7.ecx, 10);
|
||||
|
||||
if (have_sse_os_support) {
|
||||
features->ssse3 = IsBitSet(leaf_1.ecx, 9);
|
||||
features->sse4_1 = IsBitSet(leaf_1.ecx, 19);
|
||||
features->sse4_2 = IsBitSet(leaf_1.ecx, 20);
|
||||
}
|
||||
|
||||
if (have_avx_os_support) {
|
||||
features->fma3 = IsBitSet(leaf_1.ecx, 12);
|
||||
features->avx = IsBitSet(leaf_1.ecx, 28);
|
||||
features->avx2 = IsBitSet(leaf_7.ebx, 5);
|
||||
}
|
||||
|
||||
if (have_avx512_os_support) {
|
||||
features->avx512f = IsBitSet(leaf_7.ebx, 16);
|
||||
features->avx512cd = IsBitSet(leaf_7.ebx, 28);
|
||||
features->avx512er = IsBitSet(leaf_7.ebx, 27);
|
||||
features->avx512pf = IsBitSet(leaf_7.ebx, 26);
|
||||
features->avx512bw = IsBitSet(leaf_7.ebx, 30);
|
||||
features->avx512dq = IsBitSet(leaf_7.ebx, 17);
|
||||
features->avx512vl = IsBitSet(leaf_7.ebx, 31);
|
||||
features->avx512ifma = IsBitSet(leaf_7.ebx, 21);
|
||||
features->avx512vbmi = IsBitSet(leaf_7.ecx, 1);
|
||||
features->avx512vbmi2 = IsBitSet(leaf_7.ecx, 6);
|
||||
features->avx512vnni = IsBitSet(leaf_7.ecx, 11);
|
||||
features->avx512bitalg = IsBitSet(leaf_7.ecx, 12);
|
||||
features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14);
|
||||
features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2);
|
||||
features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3);
|
||||
}
|
||||
}
|
||||
|
||||
static const X86Info kEmptyX86Info;
|
||||
|
||||
X86Info GetX86Info(void) {
|
||||
X86Info info = kEmptyX86Info;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
SetVendor(leaf_0, info.vendor);
|
||||
if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD")) {
|
||||
ParseCpuId(max_cpuid_leaf, &info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
#define CPUID(FAMILY, MODEL) (((FAMILY & 0xFF) << 8) | (MODEL & 0xFF))
|
||||
|
||||
X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
|
||||
if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
|
||||
switch (CPUID(info->family, info->model)) {
|
||||
case CPUID(0x06, 0x35):
|
||||
case CPUID(0x06, 0x36):
|
||||
// https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)
|
||||
return INTEL_ATOM_BNL;
|
||||
case CPUID(0x06, 0x37):
|
||||
case CPUID(0x06, 0x4C):
|
||||
// https://en.wikipedia.org/wiki/Silvermont
|
||||
return INTEL_ATOM_SMT;
|
||||
case CPUID(0x06, 0x5C):
|
||||
// https://en.wikipedia.org/wiki/Goldmont
|
||||
return INTEL_ATOM_GMT;
|
||||
case CPUID(0x06, 0x0F):
|
||||
case CPUID(0x06, 0x16):
|
||||
// https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)
|
||||
return INTEL_CORE;
|
||||
case CPUID(0x06, 0x17):
|
||||
case CPUID(0x06, 0x1D):
|
||||
// https://en.wikipedia.org/wiki/Penryn_(microarchitecture)
|
||||
return INTEL_PNR;
|
||||
case CPUID(0x06, 0x1A):
|
||||
case CPUID(0x06, 0x1E):
|
||||
case CPUID(0x06, 0x1F):
|
||||
case CPUID(0x06, 0x2E):
|
||||
// https://en.wikipedia.org/wiki/Nehalem_(microarchitecture)
|
||||
return INTEL_NHM;
|
||||
case CPUID(0x06, 0x25):
|
||||
case CPUID(0x06, 0x2C):
|
||||
case CPUID(0x06, 0x2F):
|
||||
// https://en.wikipedia.org/wiki/Westmere_(microarchitecture)
|
||||
return INTEL_WSM;
|
||||
case CPUID(0x06, 0x2A):
|
||||
case CPUID(0x06, 0x2D):
|
||||
// https://en.wikipedia.org/wiki/Sandy_Bridge#Models_and_steppings
|
||||
return INTEL_SNB;
|
||||
case CPUID(0x06, 0x3A):
|
||||
case CPUID(0x06, 0x3E):
|
||||
// https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture)#Models_and_steppings
|
||||
return INTEL_IVB;
|
||||
case CPUID(0x06, 0x3C):
|
||||
case CPUID(0x06, 0x3F):
|
||||
case CPUID(0x06, 0x45):
|
||||
case CPUID(0x06, 0x46):
|
||||
// https://en.wikipedia.org/wiki/Haswell_(microarchitecture)
|
||||
return INTEL_HSW;
|
||||
case CPUID(0x06, 0x3D):
|
||||
case CPUID(0x06, 0x47):
|
||||
case CPUID(0x06, 0x4F):
|
||||
case CPUID(0x06, 0x56):
|
||||
// https://en.wikipedia.org/wiki/Broadwell_(microarchitecture)
|
||||
return INTEL_BDW;
|
||||
case CPUID(0x06, 0x4E):
|
||||
case CPUID(0x06, 0x55):
|
||||
case CPUID(0x06, 0x5E):
|
||||
// https://en.wikipedia.org/wiki/Skylake_(microarchitecture)
|
||||
return INTEL_SKL;
|
||||
case CPUID(0x06, 0x8E):
|
||||
case CPUID(0x06, 0x9E):
|
||||
// https://en.wikipedia.org/wiki/Kaby_Lake
|
||||
return INTEL_KBL;
|
||||
default:
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
|
||||
switch (info->family) {
|
||||
// https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures
|
||||
case 0x0F:
|
||||
return AMD_HAMMER;
|
||||
case 0x10:
|
||||
return AMD_K10;
|
||||
case 0x14:
|
||||
return AMD_BOBCAT;
|
||||
case 0x15:
|
||||
return AMD_BULLDOZER;
|
||||
case 0x16:
|
||||
return AMD_JAGUAR;
|
||||
case 0x17:
|
||||
return AMD_ZEN;
|
||||
default:
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
|
||||
static void SetString(const uint32_t max_cpuid_ext_leaf, const uint32_t leaf_id,
|
||||
char* buffer) {
|
||||
const Leaf leaf = SafeCpuId(max_cpuid_ext_leaf, leaf_id);
|
||||
// We allow calling memcpy from SetString which is only called when requesting
|
||||
// X86BrandString.
|
||||
memcpy(buffer, &leaf, sizeof(Leaf));
|
||||
}
|
||||
|
||||
void FillX86BrandString(char brand_string[49]) {
|
||||
const Leaf leaf_ext_0 = CpuId(0x80000000);
|
||||
const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
|
||||
SetString(max_cpuid_leaf_ext, 0x80000002, brand_string);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000003, brand_string + 16);
|
||||
SetString(max_cpuid_leaf_ext, 0x80000004, brand_string + 32);
|
||||
brand_string[48] = '\0';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
int GetX86FeaturesEnumValue(const X86Features* features,
|
||||
X86FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case X86_AES:
|
||||
return features->aes;
|
||||
case X86_ERMS:
|
||||
return features->erms;
|
||||
case X86_F16C:
|
||||
return features->f16c;
|
||||
case X86_FMA3:
|
||||
return features->fma3;
|
||||
case X86_VPCLMULQDQ:
|
||||
return features->vpclmulqdq;
|
||||
case X86_BMI1:
|
||||
return features->bmi1;
|
||||
case X86_BMI2:
|
||||
return features->bmi2;
|
||||
case X86_SSSE3:
|
||||
return features->ssse3;
|
||||
case X86_SSE4_1:
|
||||
return features->sse4_1;
|
||||
case X86_SSE4_2:
|
||||
return features->sse4_2;
|
||||
case X86_AVX:
|
||||
return features->avx;
|
||||
case X86_AVX2:
|
||||
return features->avx2;
|
||||
case X86_AVX512F:
|
||||
return features->avx512f;
|
||||
case X86_AVX512CD:
|
||||
return features->avx512cd;
|
||||
case X86_AVX512ER:
|
||||
return features->avx512er;
|
||||
case X86_AVX512PF:
|
||||
return features->avx512pf;
|
||||
case X86_AVX512BW:
|
||||
return features->avx512bw;
|
||||
case X86_AVX512DQ:
|
||||
return features->avx512dq;
|
||||
case X86_AVX512VL:
|
||||
return features->avx512vl;
|
||||
case X86_AVX512IFMA:
|
||||
return features->avx512ifma;
|
||||
case X86_AVX512VBMI:
|
||||
return features->avx512vbmi;
|
||||
case X86_AVX512VBMI2:
|
||||
return features->avx512vbmi2;
|
||||
case X86_AVX512VNNI:
|
||||
return features->avx512vnni;
|
||||
case X86_AVX512BITALG:
|
||||
return features->avx512bitalg;
|
||||
case X86_AVX512VPOPCNTDQ:
|
||||
return features->avx512vpopcntdq;
|
||||
case X86_AVX512_4VNNIW:
|
||||
return features->avx512_4vnniw;
|
||||
case X86_AVX512_4VBMI2:
|
||||
return features->avx512_4vbmi2;
|
||||
case X86_SMX:
|
||||
return features->smx;
|
||||
case X86_SGX:
|
||||
return features->sgx;
|
||||
case X86_CX16:
|
||||
return features->cx16;
|
||||
case X86_LAST_:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* GetX86FeaturesEnumName(X86FeaturesEnum value) {
|
||||
switch (value) {
|
||||
case X86_AES:
|
||||
return "aes";
|
||||
case X86_ERMS:
|
||||
return "erms";
|
||||
case X86_F16C:
|
||||
return "f16c";
|
||||
case X86_FMA3:
|
||||
return "fma3";
|
||||
case X86_VPCLMULQDQ:
|
||||
return "vpclmulqdq";
|
||||
case X86_BMI1:
|
||||
return "bmi1";
|
||||
case X86_BMI2:
|
||||
return "bmi2";
|
||||
case X86_SSSE3:
|
||||
return "ssse3";
|
||||
case X86_SSE4_1:
|
||||
return "sse4_1";
|
||||
case X86_SSE4_2:
|
||||
return "sse4_2";
|
||||
case X86_AVX:
|
||||
return "avx";
|
||||
case X86_AVX2:
|
||||
return "avx2";
|
||||
case X86_AVX512F:
|
||||
return "avx512f";
|
||||
case X86_AVX512CD:
|
||||
return "avx512cd";
|
||||
case X86_AVX512ER:
|
||||
return "avx512er";
|
||||
case X86_AVX512PF:
|
||||
return "avx512pf";
|
||||
case X86_AVX512BW:
|
||||
return "avx512bw";
|
||||
case X86_AVX512DQ:
|
||||
return "avx512dq";
|
||||
case X86_AVX512VL:
|
||||
return "avx512vl";
|
||||
case X86_AVX512IFMA:
|
||||
return "avx512ifma";
|
||||
case X86_AVX512VBMI:
|
||||
return "avx512vbmi";
|
||||
case X86_AVX512VBMI2:
|
||||
return "avx512vbmi2";
|
||||
case X86_AVX512VNNI:
|
||||
return "avx512vnni";
|
||||
case X86_AVX512BITALG:
|
||||
return "avx512bitalg";
|
||||
case X86_AVX512VPOPCNTDQ:
|
||||
return "avx512vpopcntdq";
|
||||
case X86_AVX512_4VNNIW:
|
||||
return "avx512_4vnniw";
|
||||
case X86_AVX512_4VBMI2:
|
||||
return "avx512_4vbmi2";
|
||||
case X86_SMX:
|
||||
return "smx";
|
||||
case X86_SGX:
|
||||
return "sgx";
|
||||
case X86_CX16:
|
||||
return "cx16";
|
||||
case X86_LAST_:
|
||||
break;
|
||||
}
|
||||
return "unknown_feature";
|
||||
}
|
||||
|
||||
const char* GetX86MicroarchitectureName(X86Microarchitecture uarch) {
|
||||
switch (uarch) {
|
||||
case X86_UNKNOWN:
|
||||
return "X86_UNKNOWN";
|
||||
case INTEL_CORE:
|
||||
return "INTEL_CORE";
|
||||
case INTEL_PNR:
|
||||
return "INTEL_PNR";
|
||||
case INTEL_NHM:
|
||||
return "INTEL_NHM";
|
||||
case INTEL_ATOM_BNL:
|
||||
return "INTEL_ATOM_BNL";
|
||||
case INTEL_WSM:
|
||||
return "INTEL_WSM";
|
||||
case INTEL_SNB:
|
||||
return "INTEL_SNB";
|
||||
case INTEL_IVB:
|
||||
return "INTEL_IVB";
|
||||
case INTEL_ATOM_SMT:
|
||||
return "INTEL_ATOM_SMT";
|
||||
case INTEL_HSW:
|
||||
return "INTEL_HSW";
|
||||
case INTEL_BDW:
|
||||
return "INTEL_BDW";
|
||||
case INTEL_SKL:
|
||||
return "INTEL_SKL";
|
||||
case INTEL_ATOM_GMT:
|
||||
return "INTEL_ATOM_GMT";
|
||||
case INTEL_KBL:
|
||||
return "INTEL_KBL";
|
||||
case INTEL_CFL:
|
||||
return "INTEL_CFL";
|
||||
case INTEL_CNL:
|
||||
return "INTEL_CNL";
|
||||
case AMD_HAMMER:
|
||||
return "AMD_HAMMER";
|
||||
case AMD_K10:
|
||||
return "AMD_K10";
|
||||
case AMD_BOBCAT:
|
||||
return "AMD_BOBCAT";
|
||||
case AMD_BULLDOZER:
|
||||
return "AMD_BULLDOZER";
|
||||
case AMD_JAGUAR:
|
||||
return "AMD_JAGUAR";
|
||||
case AMD_ZEN:
|
||||
return "AMD_ZEN";
|
||||
}
|
||||
return "unknown microarchitecture";
|
||||
}
|
||||
57
external/cpu_features/src/filesystem.c
vendored
Normal file
57
external/cpu_features/src/filesystem.c
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
int CpuFeatures_OpenFile(const char* filename) {
|
||||
return _open(filename, _O_RDONLY);
|
||||
}
|
||||
|
||||
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
|
||||
|
||||
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||
size_t buffer_size) {
|
||||
return _read(file_descriptor, buffer, buffer_size);
|
||||
}
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
int CpuFeatures_OpenFile(const char* filename) {
|
||||
int result;
|
||||
do {
|
||||
result = open(filename, O_RDONLY);
|
||||
} while (result == -1L && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
|
||||
|
||||
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||
size_t buffer_size) {
|
||||
int result;
|
||||
do {
|
||||
result = read(file_descriptor, buffer, buffer_size);
|
||||
} while (result == -1L && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
187
external/cpu_features/src/hwcaps.c
vendored
Normal file
187
external/cpu_features/src/hwcaps.c
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#if defined(NDEBUG)
|
||||
#define D(...)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define D(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_MIPS) || defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||
#define HWCAPS_ANDROID_MIPS_OR_ARM
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) && \
|
||||
!defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
#define HWCAPS_REGULAR_LINUX
|
||||
#endif
|
||||
|
||||
#if defined(HWCAPS_ANDROID_MIPS_OR_ARM) || defined(HWCAPS_REGULAR_LINUX)
|
||||
#define HWCAPS_SUPPORTED
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetElfHwcapFromGetauxval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// On Linux we simply use getauxval.
|
||||
#if defined(HWCAPS_REGULAR_LINUX)
|
||||
#include <dlfcn.h>
|
||||
#include <sys/auxv.h>
|
||||
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||
return getauxval(hwcap_type);
|
||||
}
|
||||
#endif // defined(HWCAPS_REGULAR_LINUX)
|
||||
|
||||
// On Android we probe the system's C library for a 'getauxval' function and
|
||||
// call it if it exits, or return 0 for failure. This function is available
|
||||
// since API level 20.
|
||||
//
|
||||
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
|
||||
// case where some NDK developers use headers for a platform that is newer than
|
||||
// the one really targetted by their application. This is typically done to use
|
||||
// newer native APIs only when running on more recent Android versions, and
|
||||
// requires careful symbol management.
|
||||
//
|
||||
// Note that getauxval() can't really be re-implemented here, because its
|
||||
// implementation does not parse /proc/self/auxv. Instead it depends on values
|
||||
// that are passed by the kernel at process-init time to the C runtime
|
||||
// initialization layer.
|
||||
#if defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
#include <dlfcn.h>
|
||||
#define AT_HWCAP 16
|
||||
#define AT_HWCAP2 26
|
||||
#define AT_PLATFORM 15
|
||||
#define AT_BASE_PLATFORM 24
|
||||
|
||||
typedef unsigned long getauxval_func_t(unsigned long);
|
||||
|
||||
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||
uint32_t ret = 0;
|
||||
void* libc_handle = NULL;
|
||||
getauxval_func_t* func = NULL;
|
||||
|
||||
dlerror(); // Cleaning error state before calling dlopen.
|
||||
libc_handle = dlopen("libc.so", RTLD_NOW);
|
||||
if (!libc_handle) {
|
||||
D("Could not dlopen() C library: %s\n", dlerror());
|
||||
return 0;
|
||||
}
|
||||
func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
|
||||
if (!func) {
|
||||
D("Could not find getauxval() in C library\n");
|
||||
} else {
|
||||
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
|
||||
ret = (uint32_t)(*func)(hwcap_type);
|
||||
}
|
||||
dlclose(libc_handle);
|
||||
return ret;
|
||||
}
|
||||
#endif // defined(HWCAPS_ANDROID_MIPS_OR_ARM)
|
||||
|
||||
#if defined(HWCAPS_SUPPORTED)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetHardwareCapabilities for Android and Linux
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fallback when getauxval is not available, retrieves hwcaps from
|
||||
// "/proc/self/auxv".
|
||||
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
|
||||
struct {
|
||||
uint32_t tag;
|
||||
uint32_t value;
|
||||
} entry;
|
||||
uint32_t result = 0;
|
||||
const char filepath[] = "/proc/self/auxv";
|
||||
const int fd = CpuFeatures_OpenFile(filepath);
|
||||
if (fd < 0) {
|
||||
D("Could not open %s\n", filepath);
|
||||
return 0;
|
||||
}
|
||||
for (;;) {
|
||||
const int ret = CpuFeatures_ReadFile(fd, (char*)&entry, sizeof entry);
|
||||
if (ret < 0) {
|
||||
D("Error while reading %s\n", filepath);
|
||||
break;
|
||||
}
|
||||
// Detect end of list.
|
||||
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
|
||||
break;
|
||||
}
|
||||
if (entry.tag == hwcap_type) {
|
||||
result = entry.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Retrieves hardware capabilities by first trying to call getauxval, if not
|
||||
// available falls back to reading "/proc/self/auxv".
|
||||
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
|
||||
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
|
||||
if (!hwcaps) {
|
||||
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
|
||||
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
|
||||
}
|
||||
return hwcaps;
|
||||
}
|
||||
|
||||
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||
HardwareCapabilities capabilities;
|
||||
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
|
||||
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
PlatformType kEmptyPlatformType;
|
||||
|
||||
PlatformType CpuFeatures_GetPlatformType(void) {
|
||||
PlatformType type = kEmptyPlatformType;
|
||||
char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
|
||||
char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
|
||||
|
||||
if (platform != NULL)
|
||||
CpuFeatures_StringView_CopyString(str(platform), type.platform,
|
||||
sizeof(type.platform));
|
||||
if (base_platform != NULL)
|
||||
CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
|
||||
sizeof(type.base_platform));
|
||||
return type;
|
||||
}
|
||||
#else // (defined(HWCAPS_SUPPORTED)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetHardwareCapabilities for unsupported platforms.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const HardwareCapabilities kEmptyHardwareCapabilities;
|
||||
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||
return kEmptyHardwareCapabilities;
|
||||
}
|
||||
#endif
|
||||
51
external/cpu_features/src/linux_features_aggregator.c
vendored
Normal file
51
external/cpu_features/src/linux_features_aggregator.c
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/linux_features_aggregator.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
void CpuFeatures_SetFromFlags(const size_t configs_size,
|
||||
const CapabilityConfig* configs,
|
||||
const StringView flags_line,
|
||||
void* const features) {
|
||||
size_t i = 0;
|
||||
for (; i < configs_size; ++i) {
|
||||
const CapabilityConfig config = configs[i];
|
||||
config.set_bit(features, CpuFeatures_StringView_HasWord(
|
||||
flags_line, config.proc_cpuinfo_flag));
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSet(const uint32_t mask, const uint32_t value) {
|
||||
return (value & mask) == mask;
|
||||
}
|
||||
|
||||
static bool IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||
const HardwareCapabilities hwcaps) {
|
||||
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) &&
|
||||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
|
||||
}
|
||||
|
||||
void CpuFeatures_OverrideFromHwCaps(const size_t configs_size,
|
||||
const CapabilityConfig* configs,
|
||||
const HardwareCapabilities hwcaps,
|
||||
void* const features) {
|
||||
size_t i = 0;
|
||||
for (; i < configs_size; ++i) {
|
||||
const CapabilityConfig* config = &configs[i];
|
||||
if (IsHwCapsSet(config->hwcaps_mask, hwcaps)) {
|
||||
config->set_bit(features, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
131
external/cpu_features/src/stack_line_reader.c
vendored
Normal file
131
external/cpu_features/src/stack_line_reader.c
vendored
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
|
||||
reader->view.ptr = reader->buffer;
|
||||
reader->view.size = 0;
|
||||
reader->skip_mode = false;
|
||||
reader->fd = fd;
|
||||
}
|
||||
|
||||
// Replaces the content of buffer with bytes from the file.
|
||||
static int LoadFullBuffer(StackLineReader* reader) {
|
||||
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
|
||||
STACK_LINE_READER_BUFFER_SIZE);
|
||||
assert(read >= 0);
|
||||
reader->view.ptr = reader->buffer;
|
||||
reader->view.size = read;
|
||||
return read;
|
||||
}
|
||||
|
||||
// Appends with bytes from the file to buffer, filling the remaining space.
|
||||
static int LoadMore(StackLineReader* reader) {
|
||||
char* const ptr = reader->buffer + reader->view.size;
|
||||
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
|
||||
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
|
||||
assert(read >= 0);
|
||||
assert(read <= (int)size_to_read);
|
||||
reader->view.size += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
static int IndexOfEol(StackLineReader* reader) {
|
||||
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
|
||||
}
|
||||
|
||||
// Relocate buffer's pending bytes at the beginning of the array and fills the
|
||||
// remaining space with bytes from the file.
|
||||
static int BringToFrontAndLoadMore(StackLineReader* reader) {
|
||||
if (reader->view.size && reader->view.ptr != reader->buffer) {
|
||||
memmove(reader->buffer, reader->view.ptr, reader->view.size);
|
||||
}
|
||||
reader->view.ptr = reader->buffer;
|
||||
return LoadMore(reader);
|
||||
}
|
||||
|
||||
// Loads chunks of buffer size from disks until it contains a newline character
|
||||
// or end of file.
|
||||
static void SkipToNextLine(StackLineReader* reader) {
|
||||
for (;;) {
|
||||
const int read = LoadFullBuffer(reader);
|
||||
if (read == 0) {
|
||||
break;
|
||||
} else {
|
||||
const int eol_index = IndexOfEol(reader);
|
||||
if (eol_index >= 0) {
|
||||
reader->view =
|
||||
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
|
||||
LineResult result;
|
||||
result.eof = eof;
|
||||
result.full_line = full_line;
|
||||
result.line = view;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
|
||||
static LineResult CreateEOFLineResult(StringView view) {
|
||||
return CreateLineResult(true, true, view);
|
||||
}
|
||||
|
||||
static LineResult CreateTruncatedLineResult(StringView view) {
|
||||
return CreateLineResult(false, false, view);
|
||||
}
|
||||
|
||||
static LineResult CreateValidLineResult(StringView view) {
|
||||
return CreateLineResult(false, true, view);
|
||||
}
|
||||
|
||||
LineResult StackLineReader_NextLine(StackLineReader* reader) {
|
||||
if (reader->skip_mode) {
|
||||
SkipToNextLine(reader);
|
||||
reader->skip_mode = false;
|
||||
}
|
||||
{
|
||||
const bool can_load_more =
|
||||
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
|
||||
int eol_index = IndexOfEol(reader);
|
||||
if (eol_index < 0 && can_load_more) {
|
||||
const int read = BringToFrontAndLoadMore(reader);
|
||||
if (read == 0) {
|
||||
return CreateEOFLineResult(reader->view);
|
||||
}
|
||||
eol_index = IndexOfEol(reader);
|
||||
}
|
||||
if (eol_index < 0) {
|
||||
reader->skip_mode = true;
|
||||
return CreateTruncatedLineResult(reader->view);
|
||||
}
|
||||
{
|
||||
StringView line =
|
||||
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
|
||||
reader->view =
|
||||
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||
return CreateValidLineResult(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
182
external/cpu_features/src/string_view.c
vendored
Normal file
182
external/cpu_features/src/string_view.c
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
|
||||
if (view.ptr && view.size) {
|
||||
const char* const found = (const char*)memchr(view.ptr, c, view.size);
|
||||
if (found) {
|
||||
return found - view.ptr;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||
const StringView sub_view) {
|
||||
if (sub_view.size) {
|
||||
StringView remainder = view;
|
||||
while (remainder.size >= sub_view.size) {
|
||||
const int found_index =
|
||||
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
|
||||
if (found_index < 0) break;
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
|
||||
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
|
||||
return remainder.ptr - view.ptr;
|
||||
}
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
|
||||
if (a.size == b.size) {
|
||||
return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
|
||||
return a.ptr && b.ptr && b.size && a.size >= b.size
|
||||
? memcmp(a.ptr, b.ptr, b.size) == 0
|
||||
: false;
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||
size_t count) {
|
||||
if (count > str_view.size) {
|
||||
return kEmptyStringView;
|
||||
}
|
||||
return view(str_view.ptr + count, str_view.size - count);
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||
size_t count) {
|
||||
if (count > str_view.size) {
|
||||
return kEmptyStringView;
|
||||
}
|
||||
return view(str_view.ptr, str_view.size - count);
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||
size_t count) {
|
||||
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
|
||||
}
|
||||
|
||||
char CpuFeatures_StringView_Front(const StringView view) {
|
||||
assert(view.size);
|
||||
assert(view.ptr);
|
||||
return view.ptr[0];
|
||||
}
|
||||
|
||||
char CpuFeatures_StringView_Back(const StringView view) {
|
||||
assert(view.size);
|
||||
return view.ptr[view.size - 1];
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
|
||||
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
|
||||
view = CpuFeatures_StringView_PopFront(view, 1);
|
||||
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
|
||||
view = CpuFeatures_StringView_PopBack(view, 1);
|
||||
return view;
|
||||
}
|
||||
|
||||
static int HexValue(const char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns -1 if view contains non digits.
|
||||
static int ParsePositiveNumberWithBase(const StringView view, int base) {
|
||||
int result = 0;
|
||||
StringView remainder = view;
|
||||
for (; remainder.size;
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
|
||||
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
|
||||
if (value < 0 || value >= base) return -1;
|
||||
result = (result * base) + value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
|
||||
if (view.size) {
|
||||
const StringView hex_prefix = str("0x");
|
||||
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
|
||||
const StringView span_no_prefix =
|
||||
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
|
||||
return ParsePositiveNumberWithBase(span_no_prefix, 16);
|
||||
}
|
||||
return ParsePositiveNumberWithBase(view, 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||
size_t dst_size) {
|
||||
if (dst_size > 0) {
|
||||
const size_t max_copy_size = dst_size - 1;
|
||||
const size_t copy_size =
|
||||
src.size > max_copy_size ? max_copy_size : src.size;
|
||||
memcpy(dst, src.ptr, copy_size);
|
||||
dst[copy_size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const char* const word_str) {
|
||||
const StringView word = str(word_str);
|
||||
StringView remainder = line;
|
||||
for (;;) {
|
||||
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
|
||||
if (index_of_word < 0) {
|
||||
return false;
|
||||
} else {
|
||||
const StringView before =
|
||||
CpuFeatures_StringView_KeepFront(line, index_of_word);
|
||||
const StringView after =
|
||||
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
|
||||
const bool valid_before =
|
||||
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
|
||||
const bool valid_after =
|
||||
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
|
||||
if (valid_before && valid_after) return true;
|
||||
remainder =
|
||||
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||
StringView* key,
|
||||
StringView* value) {
|
||||
const StringView sep = str(": ");
|
||||
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
|
||||
if (index_of_separator < 0) return false;
|
||||
*value = CpuFeatures_StringView_TrimWhitespace(
|
||||
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
|
||||
*key = CpuFeatures_StringView_TrimWhitespace(
|
||||
CpuFeatures_StringView_KeepFront(line, index_of_separator));
|
||||
return true;
|
||||
}
|
||||
237
external/cpu_features/src/utils/list_cpu_features.c
vendored
Normal file
237
external/cpu_features/src/utils/list_cpu_features.c
vendored
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "cpuinfo_aarch64.h"
|
||||
#include "cpuinfo_arm.h"
|
||||
#include "cpuinfo_mips.h"
|
||||
#include "cpuinfo_ppc.h"
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
static void PrintEscapedAscii(const char* str) {
|
||||
putchar('"');
|
||||
for (; str && *str; ++str) {
|
||||
switch (*str) {
|
||||
case '\"':
|
||||
case '\\':
|
||||
case '/':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
putchar('\\');
|
||||
}
|
||||
putchar(*str);
|
||||
}
|
||||
putchar('"');
|
||||
}
|
||||
|
||||
static void PrintVoid(void) {}
|
||||
static void PrintComma(void) { putchar(','); }
|
||||
static void PrintLineFeed(void) { putchar('\n'); }
|
||||
static void PrintOpenBrace(void) { putchar('{'); }
|
||||
static void PrintCloseBrace(void) { putchar('}'); }
|
||||
static void PrintOpenBracket(void) { putchar('['); }
|
||||
static void PrintCloseBracket(void) { putchar(']'); }
|
||||
static void PrintString(const char* field) { printf("%s", field); }
|
||||
static void PrintAlignedHeader(const char* field) { printf("%-15s : ", field); }
|
||||
static void PrintIntValue(int value) { printf("%d", value); }
|
||||
static void PrintDecHexValue(int value) {
|
||||
printf("%3d (0x%02X)", value, value);
|
||||
}
|
||||
static void PrintJsonHeader(const char* field) {
|
||||
PrintEscapedAscii(field);
|
||||
putchar(':');
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
void (*Start)(void);
|
||||
void (*ArrayStart)(void);
|
||||
void (*ArraySeparator)(void);
|
||||
void (*ArrayEnd)(void);
|
||||
void (*PrintString)(const char* value);
|
||||
void (*PrintValue)(int value);
|
||||
void (*EndField)(void);
|
||||
void (*StartField)(const char* field);
|
||||
void (*End)(void);
|
||||
} Printer;
|
||||
|
||||
static Printer getJsonPrinter(void) {
|
||||
return (Printer){
|
||||
.Start = &PrintOpenBrace,
|
||||
.ArrayStart = &PrintOpenBracket,
|
||||
.ArraySeparator = &PrintComma,
|
||||
.ArrayEnd = &PrintCloseBracket,
|
||||
.PrintString = &PrintEscapedAscii,
|
||||
.PrintValue = &PrintIntValue,
|
||||
.EndField = &PrintComma,
|
||||
.StartField = &PrintJsonHeader,
|
||||
.End = &PrintCloseBrace,
|
||||
};
|
||||
}
|
||||
|
||||
static Printer getTextPrinter(void) {
|
||||
return (Printer){
|
||||
.Start = &PrintVoid,
|
||||
.ArrayStart = &PrintVoid,
|
||||
.ArraySeparator = &PrintComma,
|
||||
.ArrayEnd = &PrintVoid,
|
||||
.PrintString = &PrintString,
|
||||
.PrintValue = &PrintDecHexValue,
|
||||
.EndField = &PrintLineFeed,
|
||||
.StartField = &PrintAlignedHeader,
|
||||
.End = &PrintVoid,
|
||||
};
|
||||
}
|
||||
|
||||
// Prints a named numeric value in both decimal and hexadecimal.
|
||||
static void PrintN(const Printer p, const char* field, int value) {
|
||||
p.StartField(field);
|
||||
p.PrintValue(value);
|
||||
p.EndField();
|
||||
}
|
||||
|
||||
// Prints a named string.
|
||||
static void PrintS(const Printer p, const char* field, const char* value) {
|
||||
p.StartField(field);
|
||||
p.PrintString(value);
|
||||
p.EndField();
|
||||
}
|
||||
|
||||
static int cmp(const void* p1, const void* p2) {
|
||||
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
|
||||
}
|
||||
|
||||
#define DEFINE_PRINT_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
|
||||
static void PrintFlags(const Printer p, const FeatureType* features) { \
|
||||
size_t i; \
|
||||
const char* ptrs[LastEnum] = {0}; \
|
||||
size_t count = 0; \
|
||||
for (i = 0; i < LastEnum; ++i) { \
|
||||
if (HasFeature(features, i)) { \
|
||||
ptrs[count] = FeatureName(i); \
|
||||
++count; \
|
||||
} \
|
||||
} \
|
||||
qsort(ptrs, count, sizeof(char*), cmp); \
|
||||
p.StartField("flags"); \
|
||||
p.ArrayStart(); \
|
||||
for (i = 0; i < count; ++i) { \
|
||||
if (i > 0) p.ArraySeparator(); \
|
||||
p.PrintString(ptrs[i]); \
|
||||
} \
|
||||
p.ArrayEnd(); \
|
||||
}
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
DEFINE_PRINT_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
|
||||
X86_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
DEFINE_PRINT_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
|
||||
ARM_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
DEFINE_PRINT_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
|
||||
Aarch64Features, AARCH64_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
DEFINE_PRINT_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
|
||||
MipsFeatures, MIPS_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||
DEFINE_PRINT_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
|
||||
PPC_LAST_)
|
||||
#endif
|
||||
|
||||
static void PrintFeatures(const Printer printer) {
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
char brand_string[49];
|
||||
const X86Info info = GetX86Info();
|
||||
FillX86BrandString(brand_string);
|
||||
PrintS(printer, "arch", "x86");
|
||||
PrintS(printer, "brand", brand_string);
|
||||
PrintN(printer, "family", info.family);
|
||||
PrintN(printer, "model", info.model);
|
||||
PrintN(printer, "stepping", info.stepping);
|
||||
PrintS(printer, "uarch",
|
||||
GetX86MicroarchitectureName(GetX86Microarchitecture(&info)));
|
||||
PrintFlags(printer, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
const ArmInfo info = GetArmInfo();
|
||||
PrintS(printer, "arch", "ARM");
|
||||
PrintN(printer, "implementer", info.implementer);
|
||||
PrintN(printer, "architecture", info.architecture);
|
||||
PrintN(printer, "variant", info.variant);
|
||||
PrintN(printer, "part", info.part);
|
||||
PrintN(printer, "revision", info.revision);
|
||||
PrintFlags(printer, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
const Aarch64Info info = GetAarch64Info();
|
||||
PrintS(printer, "arch", "aarch64");
|
||||
PrintN(printer, "implementer", info.implementer);
|
||||
PrintN(printer, "variant", info.variant);
|
||||
PrintN(printer, "part", info.part);
|
||||
PrintN(printer, "revision", info.revision);
|
||||
PrintFlags(printer, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
const MipsInfo info = GetMipsInfo();
|
||||
PrintS(printer, "arch", "mips");
|
||||
PrintFlags(printer, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||
const PPCInfo info = GetPPCInfo();
|
||||
const PPCPlatformStrings strings = GetPPCPlatformStrings();
|
||||
PrintS(printer, "arch", "ppc");
|
||||
PrintS(printer, "platform", strings.platform);
|
||||
PrintS(printer, "model", strings.model);
|
||||
PrintS(printer, "machine", strings.machine);
|
||||
PrintS(printer, "cpu", strings.cpu);
|
||||
PrintS(printer, "instruction set", strings.type.platform);
|
||||
PrintS(printer, "microarchitecture", strings.type.base_platform);
|
||||
PrintFlags(printer, &info.features);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void showUsage(const char* name) {
|
||||
printf(
|
||||
"\n"
|
||||
"Usage: %s [options]\n"
|
||||
" Options:\n"
|
||||
" -h | --help Show help message.\n"
|
||||
" -j | --json Format output as json instead of plain text.\n"
|
||||
"\n",
|
||||
name);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Printer printer = getTextPrinter();
|
||||
int i = 1;
|
||||
for (; i < argc; ++i) {
|
||||
const char* arg = argv[i];
|
||||
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
||||
printer = getJsonPrinter();
|
||||
} else {
|
||||
showUsage(argv[0]);
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
printer.Start();
|
||||
PrintFeatures(printer);
|
||||
printer.End();
|
||||
PrintLineFeed();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue