* Copyright (c) 2015 Google, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Google, Inc. 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 VMWARE, INC. 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 "tools.h"
#include <stdio.h>
#ifdef WINDOWS
# include <windows.h>
#endif
#define CPUID_INTEL_EBX 0x756e6547
#define CPUID_INTEL_EDX 0x49656e69
#define CPUID_INTEL_ECX 0x6c65746e
#define CPUID_AMD_EBX 0x68747541
#define CPUID_AMD_EDX 0x69746e65
#define CPUID_AMD_ECX 0x444d4163
#define FEAT_EDX_MMX (1 << 23)
#define FEAT_EDX_SSE (1 << 25)
#define FEAT_EDX_SSE2 (1 << 26)
#define FEAT_ECX_SSE3 (1 << 0)
#define FEAT_ECX_SSSE3 (1 << 9)
#define FEAT_ECX_SSE41 (1 << 19)
#define FEAT_ECX_SSE42 (1 << 20)
#define FEAT_ECX_AVX (1 << 28)
#ifdef UNIX
# ifdef X64
# define XDI "rdi"
# else
# define XDI "edi"
# endif
#endif
static void
invoke_cpuid(uint output[4], uint eax)
{
#ifdef UNIX
__asm__("mov %0, %%" XDI "; mov %1, %%eax; cpuid; mov %%eax, (%%" XDI "); "
"mov %%ebx, 4(%%" XDI "); mov %%ecx, 8(%%" XDI "); mov %%edx, 12(%%" XDI ")"
:
: "g"(output), "g"(eax)
: "%eax", "%ebx", "%ecx", "%edx", "%" XDI "");
#else
__cpuid(output, eax);
#endif
}
static void
invoke_cpuid_ecx(uint output[4], uint eax, uint ecx)
{
#ifdef UNIX
__asm__("mov %0, %%" XDI "; mov %1, %%eax; mov %2, %%ecx; cpuid; mov %%eax, (%%" XDI
"); "
"mov %%ebx, 4(%%" XDI "); mov %%ecx, 8(%%" XDI "); mov %%edx, 12(%%" XDI ")"
:
: "g"(output), "g"(eax), "g"(ecx)
: "%eax", "%ebx", "%ecx", "%edx", "%" XDI "");
#else
__cpuidex(output, eax, ecx);
#endif
}
int
main(int argc, char **argv)
{
uint cpuid_val[4];
uint max_eax, max_ext_eax;
uint family, model;
uint feat_edx, feat_ecx;
uint ext_edx = 0, ext_ecx = 0, sext_ebx = 0;
invoke_cpuid(cpuid_val, 0);
max_eax = cpuid_val[0];
if (cpuid_val[1] == CPUID_INTEL_EBX && cpuid_val[2] == CPUID_INTEL_ECX &&
cpuid_val[3] == CPUID_INTEL_EDX)
print("Running on an Intel processor\n");
else if (cpuid_val[1] == CPUID_AMD_EBX && cpuid_val[2] == CPUID_AMD_ECX &&
cpuid_val[3] == CPUID_AMD_EDX)
print("Running on an AMD processor\n");
else
print("Running on an unknown processor\n");
invoke_cpuid(cpuid_val, 1);
family = (cpuid_val[0] >> 8) & 0xf;
model = (cpuid_val[0] >> 4) & 0xf;
if (family == 6 || family == 15) {
uint ext_model = (cpuid_val[0] >> 16) & 0xf;
model += (ext_model << 4);
if (family == 15) {
uint ext_family = (cpuid_val[0] >> 20) & 0xff;
family += ext_family;
}
}
print("Type = %d, family = %d, model = %d, stepping = %d\n",
(cpuid_val[0] >> 12) & 0x3, family, model, cpuid_val[0] & 0xf);
feat_edx = cpuid_val[3];
feat_ecx = cpuid_val[2];
invoke_cpuid(cpuid_val, 0x80000000);
max_ext_eax = cpuid_val[0];
if (max_ext_eax >= 0x80000001) {
invoke_cpuid(cpuid_val, 0x80000001);
ext_edx = cpuid_val[3];
ext_ecx = cpuid_val[2];
}
if (max_eax >= 7) {
invoke_cpuid_ecx(cpuid_val, 7, 0);
sext_ebx = cpuid_val[1];
}
print("Raw features:\n edx = 0x%08x\n ecx = 0x%08x\n", feat_edx, feat_ecx);
print(" ext_edx = 0x%08x\n ext_ecx = 0x%08x\n", ext_edx, ext_ecx);
print(" sext_ebx = 0x%08x\n", sext_ebx);
print("Major ISA features:\n");
if (TEST(FEAT_EDX_MMX, feat_edx))
print(" MMX\n");
if (TEST(FEAT_EDX_SSE, feat_edx))
print(" SSE\n");
if (TEST(FEAT_EDX_SSE2, feat_edx))
print(" SSE2\n");
if (TEST(FEAT_ECX_SSE3, feat_ecx))
print(" SSE3\n");
if (TEST(FEAT_ECX_SSSE3, feat_ecx))
print(" SSSE3\n");
if (TEST(FEAT_ECX_SSE41, feat_ecx))
print(" SSE41\n");
if (TEST(FEAT_ECX_SSE42, feat_ecx))
print(" SSE42\n");
if (TEST(FEAT_ECX_AVX, feat_ecx))
print(" AVX\n");
}