1
0
mirror of https://github.com/google/cpu_features.git synced 2025-04-27 23:22:31 +02:00

Add FreeBSD Arm64 support (#295)

* Add FreeBSD Arm64 detection

Getting all the features is handled by reading /var/run/dmesg.boot. Feature detections were taken from the freebsd kernel code sys/arm64/arm64/identcpu.c

* Add FreeBSD Arm64 tests

* Add flagm, flagm2 and rng detection

* Add HWCAP FreeBSD AArch64

* Update include to use linux hwcaps for powerpc

* Add FreeBSD aarch64 impl

* Separate Hwacps to freebsd and linux implementation

* Add aarch64 midr_el1 implementation

* Add detection hwcap cpuid to hwcaps.h

* Add MIDR_EL1 tests
This commit is contained in:
Mykola Hohsadze 2023-09-19 12:02:25 +03:00 committed by GitHub
parent 494d9657ef
commit 89a3f0358a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 424 additions and 155 deletions

View File

@ -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"],

View File

@ -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()
#

View File

@ -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")

View File

@ -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 <stdint.h>
#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_

View File

@ -14,12 +14,7 @@
#include "internal/hwcaps.h"
#include <stdlib.h>
#include <string.h>
#include "cpu_features_macros.h"
#include "internal/filesystem.h"
#include "internal/string_view.h"
#include <stdbool.h>
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 <stdio.h>
#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 <sys/auxv.h>
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 <dlfcn.h>
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

54
src/hwcaps_freebsd.c Normal file
View File

@ -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 <stddef.h>
#include <sys/auxv.h>
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

View File

@ -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 <stdlib.h>
#include <string.h>
#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 <stdio.h>
#define D(...) \
do { \
printf(__VA_ARGS__); \
fflush(stdout); \
} while (0)
#endif
////////////////////////////////////////////////////////////////////////////////
// Implementation of GetElfHwcapFromGetauxval
////////////////////////////////////////////////////////////////////////////////
#if defined(HAVE_STRONG_GETAUXVAL)
#include <sys/auxv.h>
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 <dlfcn.h>
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)

40
src/impl_aarch64_cpuid.c Normal file
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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<std::string> darwin_sysctlbyname_;
std::map<std::string, int> 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