From 119943707c42f42a5f2344f0c0ac12bc2190b3d8 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Fri, 2 Jul 2021 15:37:03 +0200 Subject: [PATCH] Add support for FreeBSD on x86 (#163) --- README.md | 15 ++++---- include/cpu_features_macros.h | 4 +++ src/cpuinfo_x86.c | 42 +++++++++++++++++++++- test/cpuinfo_x86_test.cc | 65 ++++++++++++++++++++++++----------- 4 files changed, 97 insertions(+), 29 deletions(-) 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.