blob: 65e5267db743a249d01277b3408553d7584f028a [file] [log] [blame]
// Copyright (c) 2014, Intel Corporation
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/utils/x86_cpuid.h"
#include <stdio.h>
#include <gtest/gtest.h>
namespace android {
namespace utils {
// Applicable when calling CPUID with EAX=0x80000001
// Long mode, which is one of the features that distinguish x86_64 from x86
static const uint32_t CPUID_EDX_LM = 1 << 29;
// Prints to stdout a line stating whether a feature is supported or not.
static void PrintCpuFeatureTestResult(const char *feature,
bool supported) {
printf("%s -%s supported\n", feature, supported ? "" : " not");
}
// Not really a test. Prints a summary of the host CPU's ABI compatibility for
// manual verification.
TEST(x86_cpuid, Default) {
uint32_t ecx = 0, edx = 0;
// Call CPUID with EAX=1 and ECX=0 to get CPU feature bits.
android_get_x86_cpuid(1, 0, NULL, NULL, &ecx, &edx);
if (!ecx && !edx) {
// Both output variables are unchanged, which probably means that
// android_get_x86_cpuid(..) was compiled to a no-op.
printf("Host CPU architecture is neither x86 nor x86_64!\n");
} else {
// EDX returned by CPUID (EAX=1) should never be zero.
EXPECT_TRUE(edx);
uint32_t edx2 = 0;
// Call CPUID with EAX=0x80000001 and ECX=0 to get extended CPU feature
// bits.
android_get_x86_cpuid(0x80000001, 0, NULL, NULL, NULL, &edx2);
// Long mode is a distinguishing feature of x86_64.
bool isX86_64 = edx2 & CPUID_EDX_LM;
printf("Host CPU architecture is %s.\n", isX86_64 ? "x86_64" : "x86");
printf("ABI compatibility:\n");
// See Table 1 in section 'ABI Management' of NDK Programmer's Guide
// (Android NDK r10c) for the features required by x86/x86_64 ABIs.
PrintCpuFeatureTestResult("MMX", edx & CPUID_EDX_MMX);
PrintCpuFeatureTestResult("SSE", edx & CPUID_EDX_SSE);
PrintCpuFeatureTestResult("SSE2", edx & CPUID_EDX_SSE2);
PrintCpuFeatureTestResult("SSE3", ecx & CPUID_ECX_SSE3);
PrintCpuFeatureTestResult("SSSE3", ecx & CPUID_ECX_SSSE3);
if (isX86_64) {
PrintCpuFeatureTestResult("SSE4.1", ecx & CPUID_ECX_SSE41);
PrintCpuFeatureTestResult("SSE4.2", ecx & CPUID_ECX_SSE42);
PrintCpuFeatureTestResult("POPCNT", ecx & CPUID_ECX_POPCNT);
}
}
}
TEST(x86_cpuid, android_get_x86_cpuid_vendor_id_is_vmhost) {
EXPECT_TRUE(android_get_x86_cpuid_vendor_id_is_vmhost("KVMKVMKVM"));
EXPECT_TRUE(android_get_x86_cpuid_vendor_id_is_vmhost("Microsoft Hv"));
EXPECT_TRUE(android_get_x86_cpuid_vendor_id_is_vmhost("VMwareVMware"));
EXPECT_TRUE(android_get_x86_cpuid_vendor_id_is_vmhost("XenVMMXenVMM"));
EXPECT_FALSE(android_get_x86_cpuid_vendor_id_is_vmhost("GenuineIntel"));
}
TEST(x86_cpuid, android_get_x86_cpuid_vmx_support) {
// These might fail if you have an AMD, Atom processor or an incredibly
// old Intel processor
EXPECT_LE(0x80000001, android_get_x86_cpuid_extended_function_max());
EXPECT_TRUE(android_get_x86_cpuid_vmx_support() ||
android_get_x86_cpuid_svm_support());
EXPECT_TRUE(android_get_x86_cpuid_nx_support());
}
TEST(x86_cpuid, android_get_x86_cpuid_vendor_id_type) {
EXPECT_EQ(VENDOR_ID_AMD,
android_get_x86_cpuid_vendor_id_type("AuthenticAMD"));
EXPECT_EQ(VENDOR_ID_INTEL,
android_get_x86_cpuid_vendor_id_type("GenuineIntel"));
EXPECT_EQ(VENDOR_ID_VM,
android_get_x86_cpuid_vendor_id_type("KVMKVMKVM"));
EXPECT_EQ(VENDOR_ID_OTHER,
android_get_x86_cpuid_vendor_id_type("any other string"));
}
TEST(x86_cpuid, android_get_x86_cpuid_vendor_vmhost_type) {
EXPECT_EQ(VENDOR_VM_VMWARE,
android_get_x86_cpuid_vendor_vmhost_type("VMWareVMWare"));
EXPECT_EQ(VENDOR_VM_HYPERV,
android_get_x86_cpuid_vendor_vmhost_type("Microsoft Hv"));
EXPECT_EQ(VENDOR_VM_KVM,
android_get_x86_cpuid_vendor_vmhost_type("KVMKVMKVM"));
EXPECT_EQ(VENDOR_VM_VBOX,
android_get_x86_cpuid_vendor_vmhost_type("VBoxVBoxVBox"));
EXPECT_EQ(VENDOR_VM_NOTVM,
android_get_x86_cpuid_vendor_vmhost_type(""));
EXPECT_EQ(VENDOR_VM_OTHER,
android_get_x86_cpuid_vendor_vmhost_type("blah"));
}
} // namespace utils
} // namespace android