Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FreeBSD Arm64 support #295

Merged
merged 10 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down Expand Up @@ -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"],
Expand All @@ -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 = [
Expand Down Expand Up @@ -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"],
Expand All @@ -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"],
Expand Down Expand Up @@ -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"],
Expand All @@ -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"],
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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()

#
Expand Down
6 changes: 6 additions & 0 deletions bazel/platforms.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this may look weird that we have to provide this file and not use @platforms//... directly but this comes from the fact that we have internal definitions for these cpu/platforms that are different from upstream Bazel. I hope we'll be able to remove this technical debt one day.

28 changes: 28 additions & 0 deletions include/internal/cpuid_aarch64.h
Original file line number Diff line number Diff line change
@@ -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 changes: 1 addition & 142 deletions src/hwcaps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 changes: 54 additions & 0 deletions src/hwcaps_freebsd.c
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading