diff --git a/README.md b/README.md
index f45dfe5..d2ad7ac 100644
--- a/README.md
+++ b/README.md
@@ -141,13 +141,14 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
## What's supported
-| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
-|---------|:----:|:-------:|:-------:|:------:|:-------:|
-| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
-| iOS | N/A | not yet | not yet | N/A | N/A |
-| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
-| MacOs | yes² | N/A | not yet | N/A | no |
-| Windows | yes² | not yet | not yet | N/A | N/A |
+| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
+|---------|-:-:--|-:-:-----|-:-:-----|-:-:-----|-:-:-----|
+| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
+| iOS | N/A | not yet | not yet | N/A | N/A |
+| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
+| MacOs | yes² | N/A | not yet | N/A | no |
+| Windows | yes² | not yet | not yet | N/A | N/A |
+| FreeBSD | yes² | not yet | not yet | not yet | not yet |
1. **Features revealed from Linux.** We gather data from several sources
depending on availability:
diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h
index 15f7368..96acf6d 100644
--- a/include/cpu_features_macros.h
+++ b/include/cpu_features_macros.h
@@ -83,6 +83,10 @@
#define CPU_FEATURES_OS_DARWIN
#endif
+#if (defined(__freebsd__) || defined(__FreeBSD__))
+#define CPU_FEATURES_OS_FREEBSD
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// Compilers
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/cpuinfo_x86.c b/src/cpuinfo_x86.c
index 21c6dea..6452fc4 100644
--- a/src/cpuinfo_x86.c
+++ b/src/cpuinfo_x86.c
@@ -98,7 +98,8 @@
// microarchitectures.
#if defined(CPU_FEATURES_OS_WINDOWS)
#include // IsProcessorFeaturePresent
-#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) || \
+ defined(CPU_FEATURES_OS_FREEBSD)
#include "internal/filesystem.h" // Needed to parse /proc/cpuinfo
#include "internal/stack_line_reader.h" // Needed to parse /proc/cpuinfo
#include "internal/string_view.h" // Needed to parse /proc/cpuinfo
@@ -1330,6 +1331,45 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ // Handling FreeBSD platform through parsing /var/run/dmesg.boot.
+ const int fd = CpuFeatures_OpenFile("/var/run/dmesg.boot");
+ if (fd >= 0) {
+ StackLineReader reader;
+ StackLineReader_Initialize(&reader, fd);
+ for (;;) {
+ const LineResult result = StackLineReader_NextLine(&reader);
+ const StringView line = result.line;
+ const bool is_feature =
+ CpuFeatures_StringView_StartsWith(line, str(" Features="));
+ const bool is_feature2 =
+ CpuFeatures_StringView_StartsWith(line, str(" Features2="));
+ if (is_feature || is_feature2) {
+ // Lines of interests are of the following form:
+ // " Features=0x1783fbff"
+ // We replace '<', '>' and ',' with space so we can search by
+ // whitespace separated word.
+ // TODO: Fix CpuFeatures_StringView_HasWord to allow for different
+ // separators.
+ for (size_t i = 0; i < line.size; ++i) {
+ char* c = (char*)(&(line.ptr[i]));
+ if (*c == '<' || *c == '>' || *c == ',') *c = ' ';
+ }
+ if (is_feature) {
+ features->sse = CpuFeatures_StringView_HasWord(line, "SSE");
+ features->sse2 = CpuFeatures_StringView_HasWord(line, "SSE2");
+ }
+ if (is_feature2) {
+ features->sse3 = CpuFeatures_StringView_HasWord(line, "SSE3");
+ features->ssse3 = CpuFeatures_StringView_HasWord(line, "SSSE3");
+ features->sse4_1 = CpuFeatures_StringView_HasWord(line, "SSE4.1");
+ features->sse4_2 = CpuFeatures_StringView_HasWord(line, "SSE4.2");
+ }
+ }
+ if (result.eof) break;
+ }
+ CpuFeatures_CloseFile(fd);
+ }
#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
// Handling Linux platform through /proc/cpuinfo.
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc
index 9889f19..c75af14 100644
--- a/test/cpuinfo_x86_test.cc
+++ b/test/cpuinfo_x86_test.cc
@@ -666,21 +666,29 @@ TEST_F(CpuidX86Test, Nehalem) {
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
+#elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff
+ Features2=0x5eda2203
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(processor :
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
+#endif
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
@@ -723,13 +731,13 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#if !defined(CPU_FEATURES_OS_WINDOWS)
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
-#endif // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
@@ -743,21 +751,29 @@ TEST_F(CpuidX86Test, Atom) {
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_SSE3_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
+#elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff
+ Features2=0x5eda2203
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
+#endif
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
@@ -800,13 +816,13 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
EXPECT_TRUE(info.features.sse);
EXPECT_TRUE(info.features.sse2);
EXPECT_TRUE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#if !defined(CPU_FEATURES_OS_WINDOWS)
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_TRUE(info.features.ssse3);
EXPECT_TRUE(info.features.sse4_1);
EXPECT_TRUE(info.features.sse4_2);
-#endif // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
}
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
@@ -816,16 +832,23 @@ TEST_F(CpuidX86Test, P3) {
#if defined(CPU_FEATURES_OS_WINDOWS)
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
PF_XMMI_INSTRUCTIONS_AVAILABLE);
-#endif // CPU_FEATURES_OS_WINDOWS
-#if defined(CPU_FEATURES_OS_DARWIN)
+#elif defined(CPU_FEATURES_OS_DARWIN)
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
-#endif // CPU_FEATURES_OS_DARWIN
-#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
+#elif defined(CPU_FEATURES_OS_FREEBSD)
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/var/run/dmesg.boot", R"(
+ ---<>---
+Copyright (c) 1992-2020 The FreeBSD Project.
+FreeBSD is a registered trademark of The FreeBSD Foundation.
+ Features=0x1783fbff
+real memory = 2147418112 (2047 MB)
+)");
+#elif defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
auto& fs = GetEmptyFilesystem();
fs.CreateFile("/proc/cpuinfo", R"(
flags : fpu mmx sse
)");
-#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
+#endif
g_fake_cpu->SetLeaves({
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
@@ -848,13 +871,13 @@ flags : fpu mmx sse
EXPECT_TRUE(info.features.sse);
EXPECT_FALSE(info.features.sse2);
EXPECT_FALSE(info.features.sse3);
-#ifndef CPU_FEATURES_OS_WINDOWS
+#if !defined(CPU_FEATURES_OS_WINDOWS)
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
// feature detection > sse3.
EXPECT_FALSE(info.features.ssse3);
EXPECT_FALSE(info.features.sse4_1);
EXPECT_FALSE(info.features.sse4_2);
-#endif // CPU_FEATURES_OS_WINDOWS
+#endif // !defined(CPU_FEATURES_OS_WINDOWS)
}
// TODO(user): test what happens when xsave/osxsave are not present.