/* * Copyright (C) 2018 Simon Fels * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * */ #include "anbox/cmds/check_features.h" #include "anbox/utils.h" #include "cpu_features_macros.h" #if defined(CPU_FEATURES_ARCH_X86) #include "cpuinfo_x86.h" #endif namespace { std::vector cpu_whitelist = { // QEMU does not necessarily expose correctly that it supports SSE and friends even // when started with `-cpu qemu64,+ssse3,+sse4.1,+sse4.2,+x2apic` "QEMU", // The following CPUs do not support AVX and without it cpu_features can't detect // if SSE & friends are supported. See https://github.com/google/cpu_features/issues/4 // Intel Core i7 M620 "M 620", // Intel Core i5 M460 "M 460", // Intel Celeron N2840 "N2840", // Intel Core i7 Q720 "Q 720", // Intel Pentium T4500 "T4500", // Intel Core i7 Q720 "Q 720", // Intel Xeon E5520 "E5520" // Intel Core2 Duo T6500 "T6500" }; } // namespace anbox::cmds::CheckFeatures::CheckFeatures() : CommandWithFlagsAndAction{ cli::Name{"check-features"}, cli::Usage{"check-features"}, cli::Description{"Check that the host system supports all necessary features"}} { action([this](const cli::Command::Context&) { #if defined(CPU_FEATURES_ARCH_X86) const auto info = cpu_features::GetX86Info(); std::vector missing_features; #define CHECK_BOOL(x, name) \ if (!x) \ missing_features.push_back(name) CHECK_BOOL(info.features.sse4_1, "SSE 4.1"); CHECK_BOOL(info.features.sse4_2, "SSE 4.2"); CHECK_BOOL(info.features.ssse3, "SSSE 3"); char brand_string[49]; cpu_features::FillX86BrandString(brand_string); std::string brand(brand_string); // Check if we have a CPU which's features we can't detect correctly auto is_whitelisted = false; for (const auto &entry : cpu_whitelist) { if (brand.find(entry) != std::string::npos) { is_whitelisted = true; break; } } if (missing_features.size() > 0 && !is_whitelisted && !sanity_check_for_features()) { std::cerr << "The CPU of your computer (" << brand_string << ") does not support all" << std::endl << "features Anbox requires." << std::endl << "It is missing support for the following features: "; for (size_t n = 0; n < missing_features.size(); n++) { const auto feature = missing_features[n]; std::cerr << feature; if (n < missing_features.size() - 1) std::cerr << ", "; } std::cerr << std::endl; std::cerr << "You can for example find more information about SSE" << std::endl << "here https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions" << std::endl; return EXIT_FAILURE; } std::cout << "Your computer does meet all requirements to run Anbox" << std::endl; return EXIT_SUCCESS; #else std::cerr << "You're running Anbox on a not yet supported architecture" << std::endl; return EXIT_FAILURE; #endif }); } // In case that the CPU supports AVX we take the decision as from our analysis // of the output from the cpu_features library. If it does not we have to check // further via the compiler builtins if we the CPU supports all mandatory features // or not. In case that any is missing we will fail the test. // // This uses the compiler builtin function __builtin_cpu_supports which allows us // to detect certain CPU features. // See https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html bool anbox::cmds::CheckFeatures::sanity_check_for_features() { #if defined(CPU_FEATURES_ARCH_X86) if (__builtin_cpu_supports("avx")) return true; std::vector missing_features; #define CHECK_FEATURE(name) \ if (!__builtin_cpu_supports(name)) \ missing_features.push_back(name); CHECK_FEATURE("sse4.1"); CHECK_FEATURE("sse4.2"); CHECK_FEATURE("ssse3"); return missing_features.empty(); #else return true; #endif }