2 * Copyright (C) 2018 Simon Fels <morphis@gravedo.de>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "anbox/cmds/check_features.h"
19 #include "anbox/utils.h"
21 #include "cpu_features_macros.h"
22 #if defined(CPU_FEATURES_ARCH_X86)
23 #include "cpuinfo_x86.h"
27 std::vector<std::string> cpu_whitelist = {
28 // QEMU does not necessarily expose correctly that it supports SSE and friends even
29 // when started with `-cpu qemu64,+ssse3,+sse4.1,+sse4.2,+x2apic`
32 // The following CPUs do not support AVX and without it cpu_features can't detect
33 // if SSE & friends are supported. See https://github.com/google/cpu_features/issues/4
39 // Intel Celeron N2840
43 // Intel Pentium T4500
49 // Intel Core2 Duo T6500
54 anbox::cmds::CheckFeatures::CheckFeatures()
55 : CommandWithFlagsAndAction{
56 cli::Name{"check-features"}, cli::Usage{"check-features"},
57 cli::Description{"Check that the host system supports all necessary features"}} {
59 action([this](const cli::Command::Context&) {
60 #if defined(CPU_FEATURES_ARCH_X86)
61 const auto info = cpu_features::GetX86Info();
62 std::vector<std::string> missing_features;
64 #define CHECK_BOOL(x, name) \
66 missing_features.push_back(name)
68 CHECK_BOOL(info.features.sse4_1, "SSE 4.1");
69 CHECK_BOOL(info.features.sse4_2, "SSE 4.2");
70 CHECK_BOOL(info.features.ssse3, "SSSE 3");
72 char brand_string[49];
73 cpu_features::FillX86BrandString(brand_string);
74 std::string brand(brand_string);
76 // Check if we have a CPU which's features we can't detect correctly
77 auto is_whitelisted = false;
78 for (const auto &entry : cpu_whitelist) {
79 if (brand.find(entry) != std::string::npos) {
80 is_whitelisted = true;
85 if (missing_features.size() > 0 && !is_whitelisted && !sanity_check_for_features()) {
86 std::cerr << "The CPU of your computer (" << brand_string << ") does not support all" << std::endl
87 << "features Anbox requires." << std::endl
88 << "It is missing support for the following features: ";
90 for (size_t n = 0; n < missing_features.size(); n++) {
91 const auto feature = missing_features[n];
93 if (n < missing_features.size() - 1)
96 std::cerr << std::endl;
97 std::cerr << "You can for example find more information about SSE" << std::endl
98 << "here https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions" << std::endl;
103 std::cout << "Your computer does meet all requirements to run Anbox" << std::endl;
107 std::cerr << "You're running Anbox on a not yet supported architecture" << std::endl;
113 // In case that the CPU supports AVX we take the decision as from our analysis
114 // of the output from the cpu_features library. If it does not we have to check
115 // further via the compiler builtins if we the CPU supports all mandatory features
116 // or not. In case that any is missing we will fail the test.
118 // This uses the compiler builtin function __builtin_cpu_supports which allows us
119 // to detect certain CPU features.
120 // See https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html
121 bool anbox::cmds::CheckFeatures::sanity_check_for_features() {
122 #if defined(CPU_FEATURES_ARCH_X86)
123 if (__builtin_cpu_supports("avx"))
126 std::vector<std::string> missing_features;
128 #define CHECK_FEATURE(name) \
129 if (!__builtin_cpu_supports(name)) \
130 missing_features.push_back(name);
132 CHECK_FEATURE("sse4.1");
133 CHECK_FEATURE("sse4.2");
134 CHECK_FEATURE("ssse3");
136 return missing_features.empty();