diff --git a/BUILD.bazel b/BUILD.bazel index 69259445..031eb630 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -2,7 +2,7 @@ load("@bazel_skylib//lib:selects.bzl", "selects") load("//:bazel/platforms.bzl", "PLATFORM_CPU_ARM", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_MIPS", "PLATFORM_CPU_PPC", "PLATFORM_CPU_RISCV32", "PLATFORM_CPU_RISCV64", "PLATFORM_CPU_X86_64") -load("//:bazel/platforms.bzl", "PLATFORM_OS_MACOS") +load("//:bazel/platforms.bzl", "PLATFORM_OS_MACOS", "PLATFORM_OS_LINUX", "PLATFORM_OS_FREEBSD", "PLATFORM_OS_ANDROID") package( default_visibility = ["//visibility:public"], @@ -169,11 +169,18 @@ cc_library( cc_library( name = "hwcaps", - srcs = ["src/hwcaps.c"], + srcs = [ + "src/hwcaps.c", + "src/hwcaps_freebsd.c", + "src/hwcaps_linux_or_android.c", + ], copts = C99_FLAGS, defines = selects.with_or({ PLATFORM_OS_MACOS: ["HAVE_DLFCN_H"], - "//conditions:default": ["HAVE_STRONG_GETAUXVAL"], + PLATFORM_OS_FREEBSD: ["HAVE_STRONG_ELF_AUX_INFO"], + PLATFORM_OS_LINUX: ["HAVE_STRONG_GETAUXVAL"], + PLATFORM_OS_ANDROID: ["HAVE_STRONG_GETAUXVAL"], + "//conditions:default": [], }), includes = INCLUDES, textual_hdrs = ["include/internal/hwcaps.h"], @@ -189,6 +196,8 @@ cc_library( testonly = 1, srcs = [ "src/hwcaps.c", + "src/hwcaps_freebsd.c", + "src/hwcaps_linux_or_android.c", "test/hwcaps_for_testing.cc", ], hdrs = [ @@ -218,9 +227,11 @@ cc_library( ], PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"], PLATFORM_CPU_ARM64: [ + "src/impl_aarch64_cpuid.c", "src/impl_aarch64_linux_or_android.c", "src/impl_aarch64_macos_or_iphone.c", "src/impl_aarch64_windows.c", + "src/impl_aarch64_freebsd.c", ], PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"], PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"], @@ -234,7 +245,10 @@ cc_library( "include/internal/windows_utils.h", ], PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"], - PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"], + PLATFORM_CPU_ARM64: [ + "include/cpuinfo_aarch64.h", + "include/internal/cpuid_aarch64.h", + ], PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"], PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"], PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"], @@ -278,9 +292,11 @@ cc_library( ], PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"], PLATFORM_CPU_ARM64: [ + "src/impl_aarch64_cpuid.c", "src/impl_aarch64_linux_or_android.c", "src/impl_aarch64_macos_or_iphone.c", "src/impl_aarch64_windows.c", + "src/impl_aarch64_freebsd.c", ], PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"], PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"], @@ -294,7 +310,10 @@ cc_library( "include/internal/windows_utils.h", ], PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"], - PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"], + PLATFORM_CPU_ARM64: [ + "include/cpuinfo_aarch64.h", + "include/internal/cpuid_aarch64.h" + ], PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"], PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"], PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"], diff --git a/CMakeLists.txt b/CMakeLists.txt index 42c964ca..5b513493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,7 @@ macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h) elseif(PROCESSOR_IS_AARCH64) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h) + list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_aarch64.h) list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h) elseif(PROCESSOR_IS_X86) list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h) @@ -146,6 +147,8 @@ setup_include_and_definitions(utils) if(UNIX) add_library(unix_based_hardware_detection OBJECT ${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h + ${PROJECT_SOURCE_DIR}/src/hwcaps_linux_or_android.c + ${PROJECT_SOURCE_DIR}/src/hwcaps_freebsd.c ${PROJECT_SOURCE_DIR}/src/hwcaps.c ) setup_include_and_definitions(unix_based_hardware_detection) @@ -154,9 +157,13 @@ if(UNIX) target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H) endif() check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL) + check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_STRONG_ELF_AUX_INFO) if(HAVE_STRONG_GETAUXVAL) target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL) endif() + if(HAVE_STRONG_ELF_AUX_INFO) + target_compile_definitions(unix_based_hardware_detection PUBLIC HAVE_STRONG_ELF_AUX_INFO) + endif() endif() # diff --git a/bazel/platforms.bzl b/bazel/platforms.bzl index eb025cec..7ced3d1d 100644 --- a/bazel/platforms.bzl +++ b/bazel/platforms.bzl @@ -16,3 +16,9 @@ PLATFORM_CPU_RISCV64 = ("@platforms//cpu:riscv64") PLATFORM_OS_MACOS = ("@platforms//os:macos") + +PLATFORM_OS_LINUX = ("@platforms//os:linux") + +PLATFORM_OS_ANDROID = ("@platforms//os:android") + +PLATFORM_OS_FREEBSD = ("@platforms//os:freebsd") diff --git a/include/internal/cpuid_aarch64.h b/include/internal/cpuid_aarch64.h new file mode 100644 index 00000000..a09a4c8a --- /dev/null +++ b/include/internal/cpuid_aarch64.h @@ -0,0 +1,28 @@ +// Copyright 2023 Google LLC +// +// 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. + +#ifndef CPU_FEATURES_INCLUDE_CPUID_AARCH64_H_ +#define CPU_FEATURES_INCLUDE_CPUID_AARCH64_H_ + +#include + +#include "cpu_features_macros.h" + +CPU_FEATURES_START_CPP_NAMESPACE + +uint64_t GetMidrEl1(void); + +CPU_FEATURES_END_CPP_NAMESPACE + +#endif // CPU_FEATURES_INCLUDE_CPUID_AARCH64_H_ diff --git a/src/hwcaps.c b/src/hwcaps.c index f44f6c39..6e2e9a85 100644 --- a/src/hwcaps.c +++ b/src/hwcaps.c @@ -14,12 +14,7 @@ #include "internal/hwcaps.h" -#include -#include - -#include "cpu_features_macros.h" -#include "internal/filesystem.h" -#include "internal/string_view.h" +#include static bool IsSet(const uint32_t mask, const uint32_t value) { if (mask == 0) return false; @@ -31,139 +26,3 @@ bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask, return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) || IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2); } - -#ifdef CPU_FEATURES_TEST -// In test mode, hwcaps_for_testing will define the following functions. -HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); -const char* CpuFeatures_GetPlatformPointer(void); -const char* CpuFeatures_GetBasePlatformPointer(void); -#else - -// Debug facilities -#if defined(NDEBUG) -#define D(...) -#else -#include -#define D(...) \ - do { \ - printf(__VA_ARGS__); \ - fflush(stdout); \ - } while (0) -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Implementation of GetElfHwcapFromGetauxval -//////////////////////////////////////////////////////////////////////////////// - -#define AT_HWCAP 16 -#define AT_HWCAP2 26 -#define AT_PLATFORM 15 -#define AT_BASE_PLATFORM 24 - -#if defined(HAVE_STRONG_GETAUXVAL) -#include -static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) { - return getauxval(hwcap_type); -} -#elif defined(HAVE_DLFCN_H) -// 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 18. -// -// 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. - -#include - -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; -} -#else -#error "This platform does not provide hardware capabilities." -#endif - -// Implementation of GetHardwareCapabilities for OS that provide -// GetElfHwcapFromGetauxval(). - -// 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; -} - -const char *CpuFeatures_GetPlatformPointer(void) { - return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM); -} - -const char *CpuFeatures_GetBasePlatformPointer(void) { - return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM); -} - -#endif // CPU_FEATURES_TEST diff --git a/src/hwcaps_freebsd.c b/src/hwcaps_freebsd.c new file mode 100644 index 00000000..eb227504 --- /dev/null +++ b/src/hwcaps_freebsd.c @@ -0,0 +1,54 @@ +// Copyright 2023 Google LLC +// +// 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 "cpu_features_macros.h" + +#ifdef CPU_FEATURES_OS_FREEBSD + +#include "internal/hwcaps.h" + +#ifdef CPU_FEATURES_TEST +// In test mode, hwcaps_for_testing will define the following functions. +HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); +const char* CpuFeatures_GetPlatformPointer(void); +const char* CpuFeatures_GetBasePlatformPointer(void); +#else + +#ifdef HAVE_STRONG_ELF_AUX_INFO +#include +#include + +static unsigned long GetElfHwcapFromElfAuxInfo(int hwcap_type) { + unsigned long hwcap; + elf_aux_info(hwcap_type, &hwcap, sizeof(hwcap)); + return hwcap; +} + +HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) { + HardwareCapabilities capabilities; + capabilities.hwcaps = GetElfHwcapFromElfAuxInfo(AT_HWCAP); + capabilities.hwcaps2 = GetElfHwcapFromElfAuxInfo(AT_HWCAP2); + return capabilities; +} + +const char *CpuFeatures_GetPlatformPointer(void) { return NULL; } + +const char *CpuFeatures_GetBasePlatformPointer(void) { return NULL; } + +#else +#error "FreeBSD needs support for elf_aux_info" +#endif // HAVE_STRONG_ELF_AUX_INFO + +#endif // CPU_FEATURES_TEST +#endif // CPU_FEATURES_OS_FREEBSD diff --git a/src/hwcaps_linux_or_android.c b/src/hwcaps_linux_or_android.c new file mode 100644 index 00000000..4de5b348 --- /dev/null +++ b/src/hwcaps_linux_or_android.c @@ -0,0 +1,161 @@ +// Copyright 2023 Google LLC +// +// 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 "cpu_features_macros.h" + +#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) + +#include +#include + +#include "cpu_features_macros.h" +#include "internal/filesystem.h" +#include "internal/hwcaps.h" +#include "internal/string_view.h" + +#ifdef CPU_FEATURES_TEST +// In test mode, hwcaps_for_testing will define the following functions. +HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void); +const char* CpuFeatures_GetPlatformPointer(void); +const char* CpuFeatures_GetBasePlatformPointer(void); +#else + +// Debug facilities +#if defined(NDEBUG) +#define D(...) +#else +#include +#define D(...) \ + do { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } while (0) +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of GetElfHwcapFromGetauxval +//////////////////////////////////////////////////////////////////////////////// + +#if defined(HAVE_STRONG_GETAUXVAL) +#include +static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) { + return getauxval(hwcap_type); +} +#elif defined(HAVE_DLFCN_H) +// 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 18. +// +// 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. + +#include + +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; +} +#else +#error "This platform does not provide hardware capabilities." +#endif + +// Implementation of GetHardwareCapabilities for OS that provide +// GetElfHwcapFromGetauxval(). + +// 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; +} + +const char *CpuFeatures_GetPlatformPointer(void) { + return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM); +} + +const char *CpuFeatures_GetBasePlatformPointer(void) { + return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM); +} + +bool CpuFeatures_IsHwCapCpuidSupported() { + return GetElfHwcapFromGetauxval(AARCH64_HWCAP_CPUID); +} + +#endif // CPU_FEATURES_TEST +#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID) diff --git a/src/impl_aarch64_cpuid.c b/src/impl_aarch64_cpuid.c new file mode 100644 index 00000000..1ca56cd4 --- /dev/null +++ b/src/impl_aarch64_cpuid.c @@ -0,0 +1,40 @@ +// Copyright 2023 Google LLC +// +// 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 "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_AARCH64 +#if (defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) || \ + defined(CPU_FEATURES_OS_ANDROID)) +#if (defined(CPU_FEATURES_COMPILER_GCC) || defined(CPU_FEATURES_COMPILER_CLANG)) + +#include "internal/cpuid_aarch64.h" + +#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64 +// Implementation will be provided by test/cpuinfo_aarch64_test.cc. +#else +uint64_t GetMidrEl1(void) { + uint64_t midr_el1; + __asm("mrs %0, MIDR_EL1" : "=r"(midr_el1)); + return midr_el1; +} +#endif // CPU_FEATURES_MOCK_CPUID_AARCH64 + +#else +#error "Unsupported compiler, aarch64 cpuid requires either GCC or Clang." +#endif // (defined(CPU_FEATURES_COMPILER_GCC) || + // defined(CPU_FEATURES_COMPILER_CLANG)) +#endif // (defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) + // || defined(CPU_FEATURES_OS_ANDROID)) +#endif // CPU_FEATURES_ARCH_AARCH64 diff --git a/src/impl_aarch64_freebsd.c b/src/impl_aarch64_freebsd.c new file mode 100644 index 00000000..d1696408 --- /dev/null +++ b/src/impl_aarch64_freebsd.c @@ -0,0 +1,46 @@ +// Copyright 2023 Google LLC +// +// 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 "cpu_features_macros.h" + +#ifdef CPU_FEATURES_ARCH_AARCH64 +#ifdef CPU_FEATURES_OS_FREEBSD + +#include "cpuinfo_aarch64.h" +#include "impl_aarch64__base_implementation.inl" +#include "internal/cpuid_aarch64.h" +#include "internal/hwcaps.h" + +static const Aarch64Info kEmptyAarch64Info; + +Aarch64Info GetAarch64Info(void) { + Aarch64Info info = kEmptyAarch64Info; + const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities(); + for (size_t i = 0; i < AARCH64_LAST_; ++i) { + if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) { + kSetters[i](&info.features, true); + } + } + if (info.features.cpuid) { + const uint64_t midr_el1 = GetMidrEl1(); + info.implementer = (int)ExtractBitRange(midr_el1, 31, 24); + info.variant = (int)ExtractBitRange(midr_el1, 23, 20); + info.part = (int)ExtractBitRange(midr_el1, 15, 4); + info.revision = (int)ExtractBitRange(midr_el1, 3, 0); + } + return info; +} + +#endif // CPU_FEATURES_OS_FREEBSD +#endif // CPU_FEATURES_ARCH_AARCH64 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f21ff985..d2177f22 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,7 +22,11 @@ add_library(stack_line_reader_for_test ../src/stack_line_reader.c) target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16) target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing) ##------------------------------------------------------------------------------ -add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c) +add_library(all_libraries + ../src/hwcaps.c + ../src/hwcaps_linux_or_android.c + ../src/hwcaps_freebsd.c + ../src/stack_line_reader.c) target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view) # @@ -73,9 +77,11 @@ endif() if(PROCESSOR_IS_AARCH64) add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc + ../src/impl_aarch64_cpuid.c ../src/impl_aarch64_linux_or_android.c ../src/impl_aarch64_windows.c ../src/impl_aarch64_macos_or_iphone.c + ../src/impl_aarch64_freebsd.c ) if(APPLE) target_compile_definitions(cpuinfo_aarch64_test PUBLIC CPU_FEATURES_MOCK_SYSCTL_AARCH64) diff --git a/test/cpuinfo_aarch64_test.cc b/test/cpuinfo_aarch64_test.cc index 6aefa6ba..7836d949 100644 --- a/test/cpuinfo_aarch64_test.cc +++ b/test/cpuinfo_aarch64_test.cc @@ -22,11 +22,20 @@ #if defined(CPU_FEATURES_OS_WINDOWS) #include "internal/windows_utils.h" #endif // CPU_FEATURES_OS_WINDOWS +#if defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) +#include "internal/cpuid_aarch64.h" +#endif // defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) namespace cpu_features { class FakeCpuAarch64 { -#if defined(CPU_FEATURES_OS_LINUX) - // No particular implementation for Linux as we use /proc/cpuinfo +#if defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) + public: + uint64_t GetMidrEl1() const { return _midr_el1; } + + void SetMidrEl1(uint64_t midr_el1) { _midr_el1 = midr_el1; } + + private: + uint64_t _midr_el1; #elif defined(CPU_FEATURES_OS_MACOS) std::set darwin_sysctlbyname_; std::map darwin_sysctlbynamevalue_; @@ -80,8 +89,8 @@ static FakeCpuAarch64& cpu() { } // Define OS dependent mock functions -#if defined(CPU_FEATURES_OS_LINUX) -// No particular functions to implement for Linux as we use /proc/cpuinfo +#if defined(CPU_FEATURES_OS_FREEBSD) || defined(CPU_FEATURES_OS_LINUX) +extern "C" uint64_t GetMidrEl1(void) { return cpu().GetMidrEl1(); } #elif defined(CPU_FEATURES_OS_MACOS) extern "C" bool GetDarwinSysCtlByName(const char* name) { return cpu().GetDarwinSysCtlByName(name); @@ -127,8 +136,8 @@ TEST_F(CpuidAarch64Test, Aarch64FeaturesEnum) { } } -// OS dependent tests -#if defined(CPU_FEATURES_OS_LINUX) +// AT_HWCAP tests +#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_FREEBSD) TEST_F(CpuidAarch64Test, FromHardwareCap) { ResetHwcaps(); SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0); @@ -196,7 +205,10 @@ TEST_F(CpuidAarch64Test, FromHardwareCap2) { EXPECT_FALSE(info.features.dgh); EXPECT_FALSE(info.features.rng); } +#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_FREEBSD) +// OS dependent tests +#if defined(CPU_FEATURES_OS_LINUX) TEST_F(CpuidAarch64Test, ARMCortexA53) { ResetHwcaps(); auto& fs = GetEmptyFilesystem(); @@ -383,6 +395,37 @@ TEST_F(CpuidAarch64Test, WINDOWS_AARCH64_RPI4) { EXPECT_FALSE(info.features.jscvt); EXPECT_FALSE(info.features.lrcpc); } -#endif // CPU_FEATURES_OS_WINDOWS +#elif defined(CPU_FEATURES_OS_FREEBSD) +TEST_F(CpuidAarch64Test, MrsMidrEl1_RPI4) { + ResetHwcaps(); + SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_CPUID, 0); + cpu().SetMidrEl1(0x410FD083); + const auto info = GetAarch64Info(); + + EXPECT_EQ(info.implementer, 0x41); + EXPECT_EQ(info.variant, 0); + EXPECT_EQ(info.part, 0xD08); + EXPECT_EQ(info.revision, 0x3); + + EXPECT_TRUE(info.features.fp); + + EXPECT_FALSE(info.features.dcpodp); + EXPECT_FALSE(info.features.sveaes); + EXPECT_FALSE(info.features.svepmull); + EXPECT_FALSE(info.features.svebitperm); + EXPECT_FALSE(info.features.svesha3); + EXPECT_FALSE(info.features.svesm4); + EXPECT_FALSE(info.features.flagm2); + EXPECT_FALSE(info.features.frint); + EXPECT_FALSE(info.features.svei8mm); + EXPECT_FALSE(info.features.svef32mm); + EXPECT_FALSE(info.features.svef64mm); + EXPECT_FALSE(info.features.svebf16); + EXPECT_FALSE(info.features.i8mm); + EXPECT_FALSE(info.features.bf16); + EXPECT_FALSE(info.features.dgh); + EXPECT_FALSE(info.features.rng); +} +#endif // CPU_FEATURES_OS_FREEBSD } // namespace } // namespace cpu_features