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:
parent
494d9657ef
commit
89a3f0358a
29
BUILD.bazel
29
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"],
|
||||
|
@ -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()
|
||||
|
||||
#
|
||||
|
@ -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")
|
||||
|
28
include/internal/cpuid_aarch64.h
Normal file
28
include/internal/cpuid_aarch64.h
Normal 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_
|
143
src/hwcaps.c
143
src/hwcaps.c
@ -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
54
src/hwcaps_freebsd.c
Normal 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
|
161
src/hwcaps_linux_or_android.c
Normal file
161
src/hwcaps_linux_or_android.c
Normal 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
40
src/impl_aarch64_cpuid.c
Normal 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
|
46
src/impl_aarch64_freebsd.c
Normal file
46
src/impl_aarch64_freebsd.c
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user