From dc038c099d0c53c31d14908de704e736f22cb697 Mon Sep 17 00:00:00 2001 From: Wenchao Wang Date: Thu, 1 Oct 2020 11:59:06 +0800 Subject: [PATCH] Implement check tool for HAXM It is required that the host operating system to meet the environmental requirements to execute HAXM. This utility is used to check the system environment for HAXM. It supports: * To check below system status: - Intel CPU vendor - Long (64-bit) mode support status - VMX support status - VMX enabling status - EPT support status - NX support status - NX enabling status - Hyper-V disabling status - OS version - OS architecture - Guest occupancy status * Running on Windows and macOS. Signed-off-by: Wenchao Wang --- CheckTool/.clang-format | 7 + CheckTool/.gitignore | 6 + CheckTool/CMakeLists.txt | 54 +++++++ CheckTool/CMakeSettings.json | 59 ++++++++ CheckTool/Info.plist | 49 ++++++ CheckTool/README.md | 136 +++++++++++++++++ CheckTool/arg_parser.cpp | 66 ++++++++ CheckTool/arg_parser.h | 57 +++++++ CheckTool/common.cpp | 86 +++++++++++ CheckTool/common.h | 61 ++++++++ CheckTool/cpuid.cpp | 123 +++++++++++++++ CheckTool/cpuid.h | 65 ++++++++ CheckTool/feature_detector.cpp | 269 +++++++++++++++++++++++++++++++++ CheckTool/feature_detector.h | 72 +++++++++ CheckTool/main.cpp | 56 +++++++ CheckTool/os.h | 75 +++++++++ CheckTool/os_darwin.cpp | 139 +++++++++++++++++ CheckTool/os_darwin.h | 58 +++++++ CheckTool/os_windows.cpp | 239 +++++++++++++++++++++++++++++ CheckTool/os_windows.h | 60 ++++++++ CheckTool/version.rc | 76 ++++++++++ 21 files changed, 1813 insertions(+) create mode 100644 CheckTool/.clang-format create mode 100644 CheckTool/.gitignore create mode 100644 CheckTool/CMakeLists.txt create mode 100644 CheckTool/CMakeSettings.json create mode 100644 CheckTool/Info.plist create mode 100644 CheckTool/README.md create mode 100644 CheckTool/arg_parser.cpp create mode 100644 CheckTool/arg_parser.h create mode 100644 CheckTool/common.cpp create mode 100644 CheckTool/common.h create mode 100644 CheckTool/cpuid.cpp create mode 100644 CheckTool/cpuid.h create mode 100644 CheckTool/feature_detector.cpp create mode 100644 CheckTool/feature_detector.h create mode 100644 CheckTool/main.cpp create mode 100644 CheckTool/os.h create mode 100644 CheckTool/os_darwin.cpp create mode 100644 CheckTool/os_darwin.h create mode 100644 CheckTool/os_windows.cpp create mode 100644 CheckTool/os_windows.h create mode 100644 CheckTool/version.rc diff --git a/CheckTool/.clang-format b/CheckTool/.clang-format new file mode 100644 index 00000000..912f947f --- /dev/null +++ b/CheckTool/.clang-format @@ -0,0 +1,7 @@ +# Refer to: +# https://android.googlesource.com/platform/external/qemu/+/emu-master-dev/android/.clang-format + +BasedOnStyle: Chromium +IndentWidth: 4 +ContinuationIndentWidth: 8 +AccessModifierOffset: -4 diff --git a/CheckTool/.gitignore b/CheckTool/.gitignore new file mode 100644 index 00000000..539f86a8 --- /dev/null +++ b/CheckTool/.gitignore @@ -0,0 +1,6 @@ +# Windows +*.obj + +# macOS +*.o + diff --git a/CheckTool/CMakeLists.txt b/CheckTool/CMakeLists.txt new file mode 100644 index 00000000..745d979b --- /dev/null +++ b/CheckTool/CMakeLists.txt @@ -0,0 +1,54 @@ +# Minimum requirement for CMake version +cmake_minimum_required(VERSION 3.4) + +# Project information +project(checktool) + +set(CMAKE_CXX_STANDARD 11) + +set(COMMON_SRCS) +list(APPEND COMMON_SRCS + ${PROJECT_SOURCE_DIR}/arg_parser.cpp + ${PROJECT_SOURCE_DIR}/common.cpp + ${PROJECT_SOURCE_DIR}/cpuid.cpp + ${PROJECT_SOURCE_DIR}/feature_detector.cpp + ${PROJECT_SOURCE_DIR}/main.cpp +) + +set(PLATFORM_SRCS) +if(WIN32) + list(APPEND PLATFORM_SRCS + ${PROJECT_SOURCE_DIR}/os_windows.cpp + ) + # Replace MDd/MD with MTd/MT to use a multi-threaded statically-linked + # runtime library for building a standalone executable. + set(CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + ) + foreach(flag ${CXX_FLAGS}) + string(REPLACE "/MD" "/MT" ${flag} "${${flag}}") + endforeach() +elseif(APPLE) + list(APPEND PLATFORM_SRCS + ${PROJECT_SOURCE_DIR}/os_darwin.cpp + ) +else() + message(FATAL_ERROR "Unsupported Platform") +endif() + +if(WIN32) + set(RESOURCES) + list(APPEND RESOURCES + ${PROJECT_SOURCE_DIR}/version.rc + ) +endif() + +# Target +add_executable(checktool ${COMMON_SRCS} ${PLATFORM_SRCS} ${RESOURCES}) + +if(APPLE) + target_link_options(checktool PRIVATE + LINKER:-sectcreate,__TEXT,__info_plist,${PROJECT_SOURCE_DIR}/Info.plist + ) +endif() diff --git a/CheckTool/CMakeSettings.json b/CheckTool/CMakeSettings.json new file mode 100644 index 00000000..7780c154 --- /dev/null +++ b/CheckTool/CMakeSettings.json @@ -0,0 +1,59 @@ +{ + "configurations": [ + { + "name": "x86-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ + "msvc_x86" + ], + "buildRoot": "${projectDir}\\build\\${name}", + "installRoot": "${projectDir}\\build\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, + + { + "name": "x86-Release", + "generator": "Ninja", + "configurationType": "Release", + "inheritEnvironments": [ + "msvc_x86" + ], + "buildRoot": "${projectDir}\\build\\${name}", + "installRoot": "${projectDir}\\build\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, + + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ + "msvc_x64_x64" + ], + "buildRoot": "${projectDir}\\build\\${name}", + "installRoot": "${projectDir}\\build\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, + + { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "Release", + "inheritEnvironments": [ + "msvc_x64_x64" + ], + "buildRoot": "${projectDir}\\build\\${name}", + "installRoot": "${projectDir}\\build\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + } + ] +} diff --git a/CheckTool/Info.plist b/CheckTool/Info.plist new file mode 100644 index 00000000..d9ebd842 --- /dev/null +++ b/CheckTool/Info.plist @@ -0,0 +1,49 @@ + + + + + + CFBundleName + checktool + CFBundleIconFile + + CFBundleVersion + 1 + NSHumanReadableCopyright + © 2020 Intel Corporation + CFBundleGetInfoString + Intel® HAXM Check Tool 1.0.0 + CFBundleLongVersionString + 1.0.0.0 + CFBundleShortVersionString + 1.0.0 + + diff --git a/CheckTool/README.md b/CheckTool/README.md new file mode 100644 index 00000000..ff4ac2bb --- /dev/null +++ b/CheckTool/README.md @@ -0,0 +1,136 @@ +# Check Tool for Intel Hardware Accelerated Execution Manager + +It is required that the host operating system to meet the environmental +requirements to install HAXM. These requirements include Intel CPU verdor, +enabling VMX, disabling Hyper-V, etc. Only when all the requirements are met, +HAXM can be installed and executed properly. These wiki pages (installation +instructions on [Windows][install-on-windows] and [macOS][install-on-macos]) +describe the configuration methods of HAXM installation prerequisites. + +This utility is a command line tool for system checking for HAXM. It is used to +help user to check the status of each condition in the current system +environment, so as to determine whether the hardware configuration meets the +requirements or which system settings need to be changed. This software +currently supports running on Windows and macOS. + +## Downloads + +The latest release of HAXM **Check Tool** for Windows and macOS hosts are +available [here][checktool-release]. + +## Windows + +### Usage + +1. `cd X:\path\to\CheckTool` +1. `checktool.exe --verbose` + +The output will be as below. + + CPU vendor * GenuineIntel + Intel64 supported * Yes + VMX supported * Yes + VMX enabled * Yes + EPT supported * Yes + NX supported * Yes + NX enabled * Yes + Hyper-V disabled - No + OS version * Windows 10.0.18363 + OS architecture * x86_64 + Guest unoccupied * Yes. 0 guest(s) + +"*" represents the item is passed, while "-" represents the item is failed. + +### Build + +#### Prerequisites + +[Visual Studio][visualstudio] 2017 or later + +Install the following components: **Desktop development with C++** (**C++ CMake +tools for Windows** is included) + +#### Build steps + +**Option A (Visual Studio)** + +1. Open _CheckTool_ project in Visual Studio. + + **File** > **Open** > **Folder...** > **Select Folder** "CheckTool" + (containing _CMakeLists.txt_) +1. Select proper configuration, e.g., "x86-Debug". +1. Build project. + + **Build** > **Build All** + +The executable program (_checktool.exe_) will be generated in +_X:\path\to\CheckTool\build\x86-Debug\\_. The 32-bit executable can run on both +32-bit and 64-bit Windows, while the 64-bit executable can run on 64-bit Windows +only. + +**Option B (CMake)** + +1. `set PATH=C:\Program Files (x86)\Microsoft Visual ` +`Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;%PATH%` +1. `cd X:\path\to\CheckTool` +1. `mkdir build && cd build && cmake .. && cmake --build .` + +The executable program (_checktool.exe_) will be generated in +_X:\path\to\CheckTool\build\Debug\\_. It is easy to clean the build just by +removing the _build_ folder manually. + +The full matrix for building 32-bit/64-bit Windows with Debug/Release +configuration can be referred as below. + +| | 32-bit Build | 64-bit Build +----------- | -------------------------------------------- | ------------------------------------------ +| | `cmake -A Win32 -B build\Win32` | `cmake -A x64 -B build\x64` +**Debug** | `cmake --build build\Win32 --config Debug` | `cmake --build build\x64 --config Debug` +**Release** | `cmake --build build\Win32 --config Release` | `cmake --build build\x64 --config Release` + +The path in the first step is the CMake default extension path installed in +Visual Studio 2019. If [CMake][cmake] (3.17 or later) has been installed +independently and added to the system path, the first step of setting path can +be omitted. + +## macOS + +### Usage + +1. `cd /path/to/CheckTool` +1. `./checktool --verbose` + +### Build + +#### Prerequisites + +* [Xcode][xcode] 7.2.1 or later +* [CMake][cmake] 3.17 or later + +#### Build steps + +1. `cd /path/to/CheckTool` +1. `mkdir build && cd build && cmake .. && make` + +The binary (_checktool_) will be generated in _/path/to/CheckTool/build/_. It is +easy to clean the build just by removing the _build_ folder manually. + +The full list for building Debug/Release configuration can be referred as +below. + +| Debug +| :-------------------------------------------------- +| `cmake -DCMAKE_BUILD_TYPE=Debug -B build/Debug` +| `make -C build/Debug` +| **Release** +| `cmake -DCMAKE_BUILD_TYPE=Release -B build/Release` +| `make -C build/Release` + +[checktool-release]: https://github.com/intel/haxm/releases/tag/checktool-v1.0.0 +[cmake]: https://cmake.org/download/ +[install-on-macos]: +https://github.com/intel/haxm/wiki/Installation-Instructions-on-macOS +[install-on-windows]: +https://github.com/intel/haxm/wiki/Installation-Instructions-on-Windows +[visualstudio]: https://www.visualstudio.com/downloads/ +[xcode]: https://developer.apple.com/xcode/ diff --git a/CheckTool/arg_parser.cpp b/CheckTool/arg_parser.cpp new file mode 100644 index 00000000..e4d411fd --- /dev/null +++ b/CheckTool/arg_parser.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "arg_parser.h" + +namespace haxm { +namespace check_util { + +ArgParser::ArgParser(int &argc, char *argv[], + const std::vector &valid_options) { + valid_options_ = valid_options; + + for (int i = 1; i < argc; ++i) { + args_.push_back(std::string(argv[i])); + } +} + +bool ArgParser::Verify() { + for (std::vector::const_iterator it = args_.begin(); + it != args_.end(); ++it) { + if (std::find(valid_options_.begin(), valid_options_.end(), *it) + == valid_options_.end()) { + error_ = *it; + return false; + } + } + return true; +} + +bool ArgParser::Test(const std::string &option) const { + return std::find(args_.begin(), args_.end(), option) != args_.end(); +} + +std::string ArgParser::error() const { + return error_; +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/arg_parser.h b/CheckTool/arg_parser.h new file mode 100644 index 00000000..f23efc9c --- /dev/null +++ b/CheckTool/arg_parser.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_ARG_PARSER_H_ +#define HAXM_CHECK_ARG_PARSER_H_ + +#include +#include + +namespace haxm { +namespace check_util { + +class ArgParser { +public: + ArgParser(int &argc, char *argv[], + const std::vector &valid_options); + bool Verify(); + bool Test(const std::string &option) const; + std::string error() const; + +private: + std::vector valid_options_; + std::vector args_; + std::string error_; +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_ARG_PARSER_H_ diff --git a/CheckTool/common.cpp b/CheckTool/common.cpp new file mode 100644 index 00000000..1c80dd22 --- /dev/null +++ b/CheckTool/common.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "arg_parser.h" +#include "common.h" +#include "feature_detector.h" + +namespace haxm { +namespace check_util { + +CheckResult ParseArguments(int &argc, char* argv[], bool &is_verbose) { + haxm::check_util::ArgParser arg_parser(argc, argv, {"-h", "--help", "-v", + "--verbose"}); + + if (!arg_parser.Verify()) { + std::cout << "checktool unknown option: " << arg_parser.error() + << std::endl; + std::cout << "Usage: checktool [-h | --help] [-v | --verbose]" + << std::endl; + return haxm::check_util::kError; + } + + if (arg_parser.Test("-h") || arg_parser.Test("--help")) { + std::cout << "CheckTool version " << APP_VERSION << std::endl; + std::cout << "-v, --verbose Show detailed system information" + << std::endl; + return haxm::check_util::kFail; + } + + if (arg_parser.Test("-v") || arg_parser.Test("--verbose")) { + is_verbose = true; + } + + return haxm::check_util::kPass; +} + +int Check(bool is_verbose) { + int ret = 0; + + haxm::check_util::FeatureDetector fd; + haxm::check_util::CheckResult detect_res = fd.Detect(); + + if (detect_res == haxm::check_util::kError) { + ret = -1; + } else if (detect_res == haxm::check_util::kFail) { + ret = 1; + } + + if (is_verbose) { + fd.Print(); + } + + return ret; +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/common.h b/CheckTool/common.h new file mode 100644 index 00000000..5b21c1ce --- /dev/null +++ b/CheckTool/common.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_COMMON_H_ +#define HAXM_CHECK_COMMON_H_ + +#include + +namespace haxm { +namespace check_util { + +#define APP_VERSION "1.0.0" + +enum CheckResult { + kUnknown = 0, + kPass, + kFail, + kNotApplicable, // e.g., CheckHypervDisabled() on macOS + kError, +}; + +// Source: +// https://github.com/google/cpu_features/blob/master/include/internal/bit_utils.h +inline static bool IsBitSet(uint32_t reg, int bit) { + return (reg >> bit) & 0x1; +} + +CheckResult ParseArguments(int &argc, char* argv[], bool &is_verbose); +int Check(bool is_verbose); + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_COMMON_H_ diff --git a/CheckTool/cpuid.cpp b/CheckTool/cpuid.cpp new file mode 100644 index 00000000..2585eace --- /dev/null +++ b/CheckTool/cpuid.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpuid.h" + +// To check the current compilers +// https://github.com/google/cpu_features/blob/7806502271dfe79b417f636839dd9de41a0be16f/include/cpu_features_macros.h#L83 +#if defined(__GNUC__) || defined(__clang__) // GCC or Clang +#include +#elif defined(_MSC_VER) // MSVC +#include +#else // !defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER_) +#error "Unsupported compiler, only support either GCC, Clang or MSVC." +#endif // defined(__GNUC__) || defined(__clang__) + +#include "common.h" + +namespace haxm { +namespace check_util { + +Cpuid::Cpuid() { + max_leaf0_ = Run(0).eax; + max_leaf8_ = Run(0x80000000).eax; +} + +// To wrap the CPUID instruction +CpuidResult Cpuid::Run(uint32_t eax) { + CpuidResult leaf; +#if defined(__GNUC__) || defined(__clang__) // GCC or Clang + __cpuid(eax, leaf.eax, leaf.ebx, leaf.ecx, leaf.edx); + +#elif defined(_MSC_VER) // MSVC + int data[4]; + __cpuid(data, eax); + leaf.eax = data[0]; + leaf.ebx = data[1]; + leaf.ecx = data[2]; + leaf.edx = data[3]; +#else // !defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER) +#error "Unsupported compiler, only support either GCC, Clang or MSVC." +#endif // defined(__GNUC__) || defined(__clang__) + return leaf; +} + +std::string Cpuid::GetCpuVendor() const { + CpuidResult leaf = Run(0); + + char vendor_temp[13] = {0}; + *reinterpret_cast(vendor_temp) = leaf.ebx; + *reinterpret_cast(vendor_temp + 4) = leaf.edx; + *reinterpret_cast(vendor_temp + 8) = leaf.ecx; + vendor_temp[12] = '\0'; + + std::string vendor = vendor_temp; + + return vendor; +} + +bool Cpuid::IsVmxSupported() const { + if (max_leaf0_ < 1) { + return false; + } + CpuidResult leaf = Run(1); + + return IsBitSet(leaf.ecx, 5); +} + +bool Cpuid::IsNxSupported() const { + if (max_leaf8_ < 0x80000001) { + return false; + } + CpuidResult leaf = Run(0x80000001); + + return IsBitSet(leaf.edx, 20); +} + +bool Cpuid::IsLongModeSupported() const { + if (max_leaf8_ < 0x80000001) { + return false; + } + CpuidResult leaf = Run(0x80000001); + + return IsBitSet(leaf.edx, 29); +} + +bool Cpuid::IsHypervisorPresent() const { + if (max_leaf0_ < 1) { + return false; + } + CpuidResult leaf = Run(1); + + return IsBitSet(leaf.ecx, 31); +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/cpuid.h b/CheckTool/cpuid.h new file mode 100644 index 00000000..1555b3f0 --- /dev/null +++ b/CheckTool/cpuid.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_CPUID_H_ +#define HAXM_CHECK_CPUID_H_ + +#include +#include + +namespace haxm { +namespace check_util { + +struct CpuidResult { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; +}; + +class Cpuid { +public: + Cpuid(); + static CpuidResult Run(uint32_t eax); + std::string GetCpuVendor() const; + bool IsVmxSupported() const; + bool IsNxSupported() const; + bool IsLongModeSupported() const; + bool IsHypervisorPresent() const; + +private: + uint32_t max_leaf0_; // highest basic information leaf + uint32_t max_leaf8_; // highest extended information leaf +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_CPUID_H_ diff --git a/CheckTool/feature_detector.cpp b/CheckTool/feature_detector.cpp new file mode 100644 index 00000000..daeabf72 --- /dev/null +++ b/CheckTool/feature_detector.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "common.h" +#include "cpuid.h" +#include "feature_detector.h" +#if defined(_WIN32) || defined(_WIN64) +#include "os_windows.h" +#elif defined(__APPLE__) +#include "os_darwin.h" +#endif + +namespace haxm { +namespace check_util { + +FeatureDetector::FeatureDetector() { + os_ = new OsImpl(); +} + +FeatureDetector::~FeatureDetector() { + delete os_; +} + +CheckResult FeatureDetector::CheckCpuVendor(std::string* vendor) const { + std::string temp; + temp = cpuid_.GetCpuVendor(); + + if (vendor != nullptr) { + *vendor = temp; + } + + return temp == "GenuineIntel" ? kPass : kFail; +} + +CheckResult FeatureDetector::CheckLongModeSupported() const { + return cpuid_.IsLongModeSupported() ? kPass : kFail; +} + +CheckResult FeatureDetector::CheckVmxSupported() const { + return cpuid_.IsVmxSupported() ? kPass : kFail; +} + +CheckResult FeatureDetector::CheckVmxEnabled() const { + return os_->CheckVmxEnabled(); +} + +CheckResult FeatureDetector::CheckEptSupported() const { + return os_->CheckEptSupported(); +} + +CheckResult FeatureDetector::CheckNxSupported() const { + return cpuid_.IsNxSupported() ? kPass : kFail; +} + +CheckResult FeatureDetector::CheckNxEnabled() const { + return os_->CheckNxEnabled(); +} + +CheckResult FeatureDetector::CheckHyperVDisabled() const { + return os_->CheckHyperVDisabled(); +} + +CheckResult FeatureDetector::CheckOsVersion(OsVersion* os_ver) const { + return os_->CheckVersion(os_ver); +} + +CheckResult FeatureDetector::CheckOsArchitecture( + OsArchitecture* os_arch) const { + return os_->CheckArchitecture(os_arch); +} + +CheckResult FeatureDetector::CheckGuestOccupied(uint32_t* occupied_count) + const { + return os_->CheckGuestOccupied(occupied_count); +} + +std::string FeatureDetector::ToString(CheckResult res) { + switch (res) { + case kUnknown: + return "Unknown"; + case kPass: + return "Yes"; + case kFail: + return "No"; + case kNotApplicable: + return "Not Applicable"; + case kError: + return "An error occurred"; + default: + assert(false); + return nullptr; + } +} + +std::string FeatureDetector::ToString(OsArchitecture os_arch) { + switch (os_arch) { + case kX86: + return "x86"; + case kX86_64: + return "x86_64"; + default: + return "Unrecognized"; + } +} + +std::string FeatureDetector::ToString(OsType os_type) { + switch (os_type) { + case kWindows: + return "Windows"; + case kDarwin: + return "macOS"; + default: + return "Unrecognized"; + } +} + +CheckResult FeatureDetector::Detect() const { + CheckResult res[11]; + + res[0] = CheckCpuVendor(); + res[1] = CheckLongModeSupported(); + res[2] = CheckNxSupported(); + res[3] = CheckNxEnabled(); + res[4] = CheckOsVersion(); + res[5] = CheckOsArchitecture(); + res[6] = CheckGuestOccupied(); + res[7] = CheckHyperVDisabled(); + res[8] = CheckVmxSupported(); + res[9] = CheckVmxEnabled(); + res[10] = CheckEptSupported(); + + int check_num = 11; + // When Hyper-V is enabled, it will affect the checking results of VMX + // supported, VMX enabled and EPT supported, so only the first 8 items are + // checked. When Hyper-V is disabled, all items are checked. + if (res[7] == kFail) { + check_num = 8; + } + + int detector[5] = {}; + + for (int i = 0; i < check_num; ++i) { + ++detector[static_cast(res[i])]; + } + + if (detector[static_cast(kError)] > 0) { + return kError; + } + + if (detector[static_cast(kUnknown)] > 0) { + return kUnknown; + } + + if (detector[static_cast(kFail)] > 0) { + return kFail; + } + + return kPass; +} + +void FeatureDetector::Print() const { + CheckResult res; + std::string item; + const int kCol = 20; + + std::string vendor; + res = CheckCpuVendor(&vendor); + item = "CPU vendor"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << vendor << std::endl; + + res = CheckLongModeSupported(); + item = "Intel64 supported"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckVmxSupported(); + item = "VMX supported"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckVmxEnabled(); + item = "VMX enabled"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckEptSupported(); + item = "EPT supported"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckNxSupported(); + item = "NX supported"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckNxEnabled(); + item = "NX enabled"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) + << std::endl; + + res = CheckHyperVDisabled(); + item = "Hyper-V disabled"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res != kFail ? '*' : '-') << " " << ToString(res) + << std::endl; + + OsVersion os_ver; + res = CheckOsVersion(&os_ver); + item = "OS version"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(os_ver.type) + << " " << os_ver.major << "." << os_ver.minor << "." + << os_ver.build_number << std::endl; + + OsArchitecture os_arch; + res = CheckOsArchitecture(&os_arch); + item = "OS architecture"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(os_arch) + << std::endl; + + uint32_t occupied_count; + res = CheckGuestOccupied(&occupied_count); + item = "Guest unoccupied"; + std::cout << item << std::string(kCol - item.size(), ' ') + << (res == kPass ? '*' : '-') << " " << ToString(res) << ". " + << occupied_count << " guest(s)" << std::endl; +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/feature_detector.h b/CheckTool/feature_detector.h new file mode 100644 index 00000000..060f35f9 --- /dev/null +++ b/CheckTool/feature_detector.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_FEATURE_DETECTOR_H_ +#define HAXM_CHECK_FEATURE_DETECTOR_H_ + +#include + +#include "common.h" +#include "cpuid.h" +#include "os.h" + +namespace haxm { +namespace check_util { + +class FeatureDetector { +public: + FeatureDetector(); + ~FeatureDetector(); + CheckResult Detect() const; + void Print() const; + +private: + CheckResult CheckCpuVendor(std::string* vendor = nullptr) const; + CheckResult CheckLongModeSupported() const; // Long Mode = Intel64 + CheckResult CheckVmxSupported() const; + CheckResult CheckVmxEnabled() const; + CheckResult CheckEptSupported() const; + CheckResult CheckNxSupported() const; + CheckResult CheckNxEnabled() const; + CheckResult CheckHyperVDisabled() const; + CheckResult CheckOsVersion(OsVersion* os_ver = nullptr) const; + CheckResult CheckOsArchitecture(OsArchitecture* os_arch = nullptr) const; + CheckResult CheckGuestOccupied(uint32_t* occupied_count = nullptr) const; + static std::string ToString(CheckResult res); + static std::string ToString(OsType os_type); + static std::string ToString(OsArchitecture os_arch); + Cpuid cpuid_; + Os* os_; +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_FEATURE_DETECTOR_H_ diff --git a/CheckTool/main.cpp b/CheckTool/main.cpp new file mode 100644 index 00000000..7b1849fc --- /dev/null +++ b/CheckTool/main.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "common.h" + +int main(int argc, char* argv[]) { + int ret = 0; + haxm::check_util::CheckResult result; + bool is_verbose = false; + + result = haxm::check_util::ParseArguments(argc, argv, is_verbose); + + switch (result) { + case haxm::check_util::kPass: { + ret = haxm::check_util::Check(is_verbose); + break; + } + case haxm::check_util::kError: { + ret = -1; + break; + } + default: { + ret = 0; + break; + } + } + + return ret; +} diff --git a/CheckTool/os.h b/CheckTool/os.h new file mode 100644 index 00000000..7e63d310 --- /dev/null +++ b/CheckTool/os.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_OS_H_ +#define HAXM_CHECK_OS_H_ + +#include "common.h" + +namespace haxm { +namespace check_util { + +enum OsType { + kWindows = 0, + kDarwin, + kOtherOs, +}; + +struct OsVersion { + OsType type; + int major; + int minor; + int build_number; +}; + +enum OsArchitecture { + kX86 = 0, + kX86_64, + kOtherArch, +}; + +class Os { // abstract class +public: + virtual ~Os() {} + virtual CheckResult CheckVmxEnabled() const = 0; + virtual CheckResult CheckEptSupported() const = 0; + virtual CheckResult CheckNxEnabled() const = 0; + virtual CheckResult CheckHyperVDisabled() const = 0; + virtual CheckResult CheckVersion(OsVersion* os_ver = nullptr) const = 0; + virtual CheckResult CheckArchitecture( + OsArchitecture* os_arch = nullptr) const = 0; + virtual CheckResult CheckGuestOccupied(uint32_t* occupied_count = nullptr) + const = 0; +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_OS_H_ diff --git a/CheckTool/os_darwin.cpp b/CheckTool/os_darwin.cpp new file mode 100644 index 00000000..b68a5f5b --- /dev/null +++ b/CheckTool/os_darwin.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "os_darwin.h" + +namespace haxm { +namespace check_util { + +OsImpl::OsImpl() {} + +CheckResult OsImpl::CheckHvfSupported() const { + static CheckResult hvf_supported = kNotApplicable; + + if (hvf_supported != kNotApplicable) { + return hvf_supported; + } + + FILE* hvf_pipe; + char hvf_buffer[256]; + + hvf_pipe = popen("sysctl kern.hv_support", "r"); + + if (hvf_pipe == NULL) { + return kError; + } + + if (fgets(hvf_buffer, sizeof(hvf_buffer), hvf_pipe) == NULL) { + return kError; + } + + pclose(hvf_pipe); + + std::string hvf_status(hvf_buffer); + hvf_status = hvf_status[hvf_status.size() - 2]; + + hvf_supported = hvf_status == "1" ? kPass : kUnknown; + + return hvf_supported; +} + +CheckResult OsImpl::CheckVmxEnabled() const { + return CheckHvfSupported(); +} + +CheckResult OsImpl::CheckEptSupported() const { + return CheckHvfSupported(); +} + +CheckResult OsImpl::CheckNxEnabled() const { + return CheckHvfSupported(); +} + +CheckResult OsImpl::CheckHyperVDisabled() const { + return kNotApplicable; +} + +CheckResult OsImpl::CheckVersion(OsVersion* os_ver) const { + OsVersion temp_os_ver = {kDarwin, 0, 0, 0}; + FILE* os_ver_pipe; + char os_ver_buffer[256]; + + os_ver_pipe = popen("sw_vers -productVersion", "r"); + + if (os_ver_pipe == NULL) { + return kError; + } + + if (fgets(os_ver_buffer, sizeof(os_ver_buffer), os_ver_pipe) == NULL) { + return kError; + } + + const char* os_ver_info = static_cast(os_ver_buffer); + + std::sscanf(os_ver_info, "%d.%d.%d", &temp_os_ver.major, &temp_os_ver.minor, + &temp_os_ver.build_number); + + if (os_ver != nullptr) { + *os_ver = temp_os_ver; + } + + if (temp_os_ver.major < 10) { + return kFail; + } + + if (temp_os_ver.major == 10 && temp_os_ver.minor < 10) { + return kFail; + } + + return kPass; +} + +CheckResult OsImpl::CheckArchitecture(OsArchitecture* os_arch) const { + if (os_arch != nullptr) { + *os_arch = kX86_64; + } + + return kPass; +} + +CheckResult OsImpl::CheckGuestOccupied(uint32_t* occupied_count) const { + if (occupied_count != nullptr) { + *occupied_count = 0; + } + + return kPass; +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/os_darwin.h b/CheckTool/os_darwin.h new file mode 100644 index 00000000..e1ed8cf4 --- /dev/null +++ b/CheckTool/os_darwin.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_OSIMPL_MAC_H_ +#define HAXM_CHECK_OSIMPL_MAC_H_ + +#include "common.h" +#include "os.h" + +namespace haxm { +namespace check_util { + +class OsImpl : public Os { +public: + OsImpl(); + CheckResult CheckVmxEnabled() const override; + CheckResult CheckEptSupported() const override; + CheckResult CheckNxEnabled() const override; + CheckResult CheckHyperVDisabled() const override; + CheckResult CheckVersion(OsVersion* os_ver) const override; + CheckResult CheckArchitecture(OsArchitecture* os_arch) const override; + CheckResult CheckGuestOccupied(uint32_t* occupied_count) const override; + +private: + CheckResult CheckHvfSupported() const; +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_OSIMPL_MAC_H_ diff --git a/CheckTool/os_windows.cpp b/CheckTool/os_windows.cpp new file mode 100644 index 00000000..0ccc6278 --- /dev/null +++ b/CheckTool/os_windows.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "cpuid.h" +#include "os_windows.h" + +namespace haxm { +namespace check_util { + +#define HAX_DEVICE_TYPE 0x4000 +#define HAX_IOCTL_CAPABILITY \ + CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// The definition of hax_capability refers to the source code of HAXM project. +// /include/hax_interface.h +struct hax_capabilityinfo { + int16_t wstatus; + uint16_t winfo; + uint32_t win_refcount; + uint64_t mem_quota; +}; + +OsImpl::OsImpl() {} + +CheckResult OsImpl::CheckVmxEnabled() const { + bool vmx_enabled_res = IsVirtFeaturePresent(PF_VIRT_FIRMWARE_ENABLED); + + return vmx_enabled_res ? kPass : kFail; +} + +CheckResult OsImpl::CheckEptSupported() const { + bool ept_supported_res = + IsVirtFeaturePresent(PF_SECOND_LEVEL_ADDRESS_TRANSLATION); + + return ept_supported_res ? kPass : kFail; +} + +CheckResult OsImpl::CheckNxEnabled() const { + bool nx_enabled_res = IsVirtFeaturePresent(PF_NX_ENABLED); + + return nx_enabled_res ? kPass : kFail; +} + +CheckResult OsImpl::CheckHyperVDisabled() const { + // Check whether hypervisor is present or not + if (!cpuid_.IsHypervisorPresent()) { + // Hypervisor is not present + return kPass; + } + + // Hypervisor is present + CpuidResult leaf = cpuid_.Run(0x40000000); + uint32_t max_leaf4_ = leaf.eax; + + // TO check if hypervisor vendor is "MicrosoftHv" + // Leaf = 0x40000000 EBX = "Micr" ECX = "osof" EDX = "t HV" + // According to: Hypervisor Top Level Functional Specification v5.0C page 5 + char vendor_temp[13] = {0}; + *reinterpret_cast(vendor_temp) = leaf.ebx; + *reinterpret_cast(vendor_temp + 4) = leaf.ecx; + *reinterpret_cast(vendor_temp + 8) = leaf.edx; + vendor_temp[12] = '\0'; + + std::string vendor_str = vendor_temp; + + if (vendor_str != "Microsoft Hv") { + return kPass; + } + + if (max_leaf4_ < 0x40000003) { + return kPass; + } + + // CPUID function 0x40000003 will return Hypervisor feature + // identification + leaf = cpuid_.Run(0x40000003); + + // EBX includes information of flags specified at partition creation. + // Partition privileges must be identical for all virtual processors in + // a partition and "CreatePartitions" can make any other hypercall that + // is restricted to operating on children. + // So EBX[0] whose description is CreatePartitions can indicate Hyper-V + // enabled. + // According to: Requirements for Implementing the Microsoft Hypervisor + // Interface + // According to: Hypervisor Top Level Functional Specification v5.0C page + // 34 Also refer to: + // http://jason-x64.itwn.intel.com:8080/sdk/xref/emu-master-dev/external/qemu/android/android-emu/android/emulation/CpuAccelerator.cpp#1054 + return IsBitSet(leaf.ebx, 0) ? kFail : kPass; +} + +typedef NTSTATUS (WINAPI *RtlGetVersionFunc)(PRTL_OSVERSIONINFOW); + +CheckResult OsImpl::CheckVersion(OsVersion* os_ver) const { + CheckResult res; + HMODULE module; + + // Refer to the table: + // https://docs.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version + res = IsWindows7SP1OrGreater() ? kPass : kFail; + if (os_ver == nullptr) + return res; + + module = ::GetModuleHandle(TEXT("ntdll.dll")); + + if (module == NULL) + return kError; + + RtlGetVersionFunc RtlGetVersion = + (RtlGetVersionFunc)::GetProcAddress(module, "RtlGetVersion"); + + if (RtlGetVersion == NULL) + return kError; + + RTL_OSVERSIONINFOW rovi = {0}; + rovi.dwOSVersionInfoSize = sizeof(rovi); + + RtlGetVersion(&rovi); + + os_ver->type = kWindows; + os_ver->major = rovi.dwMajorVersion; + os_ver->minor = rovi.dwMinorVersion; + os_ver->build_number = rovi.dwBuildNumber; + + return res; +} + +CheckResult OsImpl::CheckArchitecture(OsArchitecture* os_arch) const { + SYSTEM_INFO si; + OsArchitecture os_arch_temp; + + GetNativeSystemInfo(&si); + + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + os_arch_temp = kX86_64; + } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { + os_arch_temp = kX86; + } else { + os_arch_temp = kOtherArch; + } + + if (os_arch != nullptr) { + *os_arch = os_arch_temp; + } + + return os_arch_temp == kOtherArch ? kFail : kPass; +} + +CheckResult OsImpl::CheckGuestOccupied(uint32_t* occupied_count) const { + int ret; + HANDLE hax_handle; + DWORD size = 0; + hax_capabilityinfo ci = {0, 0, 0, 0}; + + if (occupied_count != nullptr) { + *occupied_count = 0; + } + + hax_handle = CreateFile("\\\\.\\HAX", GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hax_handle == INVALID_HANDLE_VALUE) { + return kPass; + } + + ret = DeviceIoControl(hax_handle, HAX_IOCTL_CAPABILITY, NULL, 0, &ci, + sizeof(ci), &size, NULL); + + CloseHandle(hax_handle); + + if (!ret) { + return kError; + } + + if (occupied_count != nullptr) { + // Subtracting one here is in order not to count the occupancy of this + // program itself. + *occupied_count = ci.win_refcount - 1; + } + + if (ci.win_refcount > 1) { + return kFail; + } + + return kPass; +} + +bool OsImpl::IsVirtFeaturePresent(uint32_t virt_feature) const { + OsVersion os_ver; + + CheckVersion(&os_ver); + if (os_ver.major == 6 && os_ver.minor == 1) { + // The following processor features of IsProcessorFeaturePresent are + // not supported by Windows 7. + // An alternative command line tool Coreinfo from Microsoft can be + // referred currently. + // https://docs.microsoft.com/en-us/sysinternals/downloads/coreinfo + if (virt_feature == PF_VIRT_FIRMWARE_ENABLED || + virt_feature == PF_SECOND_LEVEL_ADDRESS_TRANSLATION) + return true; + } + + return IsProcessorFeaturePresent(virt_feature); +} + +} // namespace check_util +} // namespace haxm diff --git a/CheckTool/os_windows.h b/CheckTool/os_windows.h new file mode 100644 index 00000000..8df36b57 --- /dev/null +++ b/CheckTool/os_windows.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HAXM_CHECK_OSIMPL_WIN_H_ +#define HAXM_CHECK_OSIMPL_WIN_H_ + +#include "common.h" +#include "cpuid.h" +#include "os.h" + +namespace haxm { +namespace check_util { + +class OsImpl : public Os { +public: + OsImpl(); + CheckResult CheckVmxEnabled() const override; + CheckResult CheckEptSupported() const override; + CheckResult CheckNxEnabled() const override; + CheckResult CheckHyperVDisabled() const override; + CheckResult CheckVersion(OsVersion* os_ver) const override; + CheckResult CheckArchitecture(OsArchitecture* os_arch) const override; + CheckResult CheckGuestOccupied(uint32_t* occupied_count) const override; + +private: + bool IsVirtFeaturePresent(uint32_t virt_feature) const; + Cpuid cpuid_; +}; + +} // namespace check_util +} // namespace haxm + +#endif // HAXM_CHECK_OSIMPL_WIN_H_ diff --git a/CheckTool/version.rc b/CheckTool/version.rc new file mode 100644 index 00000000..1925c849 --- /dev/null +++ b/CheckTool/version.rc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#define FILE_VERSION 1,0,0,0 +#define FILE_VERSION_STR "1.0.0.0" + +#define PRODUCT_VERSION 7,6,5,0 +#define PRODUCT_VERSION_STR "7.6.5.0" + +#ifdef DEBUG +#define FILE_FLAGS (VS_FF_PRIVATEBUILD | VS_FF_PRERELEASE | VERSION_DEBUG) +#else +#define FILE_FLAGS 0 +#endif + +VS_VERSION_INFO VERSIONINFO +FILEVERSION FILE_VERSION +PRODUCTVERSION PRODUCT_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS FILE_FLAGS +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +FILESUBTYPE 0x0L + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Intel Corporation" + VALUE "FileDescription", "System check tool for Intel\xAE " + "Hardware Accelerated Execution Manager" + VALUE "FileVersion", FILE_VERSION_STR + VALUE "InternalName", "check_tool" + VALUE "LegalCopyright", "\xA9 2020 Intel Corporation" + VALUE "OriginalFilename", "checktool.exe" + VALUE "ProductName", "Intel\xAE Hardware Accelerated " + "Execution Manager" + VALUE "ProductVersion", PRODUCT_VERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END