LCOV - code coverage report
Current view: directory - src/trusted/cpu_features/arch/x86 - cpu_x86.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 138 126 91.3 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h"
       8                 : 
       9                 : /*
      10                 :  * cpu_x86.c
      11                 :  * Retrieve and decode CPU model specific feature mask.
      12                 :  */
      13                 : #if NACL_WINDOWS
      14                 : #include <intrin.h>  /* __cpuid intrinsic */
      15                 : #endif  /* NACL_WINDOWS  */
      16                 : 
      17                 : #include <stdio.h>
      18                 : #include <string.h>
      19                 : #include <assert.h>
      20                 : #include <stdlib.h>
      21                 : 
      22                 : #include "native_client/src/include/portability_io.h"
      23                 : #include "native_client/src/shared/platform/nacl_log.h"
      24                 : 
      25                 : /*
      26                 :  * TODO(bradchen): consolidate to use one debug print mechanism.
      27                 :  */
      28                 : 
      29                 : #define CPUID_EDX_x87        0x00000001  /* x87 FPU support */
      30                 : #define CPUID_EDX_VME        0x00000002  /* Virtual 8086 Mode Enhancement */
      31                 : #define CPUID_EDX_DEB        0x00000004  /* Debugging Extensions */
      32                 : #define CPUID_EDX_PSE        0x00000008  /* Page Size Extensions */
      33                 : #define CPUID_EDX_TSC        0x00000010  /* Time Stamp Counter */
      34                 : #define CPUID_EDX_MSR        0x00000020  /* RDMSR and WRMSR */
      35                 : #define CPUID_EDX_PAE        0x00000040  /* Physical Address Extensions */
      36                 : #define CPUID_EDX_MCE        0x00000080  /* Machine Check Exception */
      37                 : #define CPUID_EDX_CX8        0x00000100  /* CMPXCHG8B Instruction */
      38                 : #define CPUID_EDX_APIC       0x00000200  /* APIC on chip */
      39                 : /* 0x00000400 reserved */
      40                 : #define CPUID_EDX_SEP        0x00000800  /* SYSENTER and SYSEXIT */
      41                 : #define CPUID_EDX_MTRR       0x00001000  /* Memory Type Range Registers */
      42                 : #define CPUID_EDX_PGE        0x00002000  /* PTE Global Bit */
      43                 : #define CPUID_EDX_MCA        0x00004000  /* Machine Check Architecture */
      44                 : #define CPUID_EDX_CMOV       0x00008000  /* CMOV instruction */
      45                 : #define CPUID_EDX_PAT        0x00010000  /* Page Attribute Table */
      46                 : #define CPUID_EDX_PSE36      0x00020000  /* Page Size Extension bis */
      47                 : #define CPUID_EDX_PSN        0x00040000  /* Processor Serial Number */
      48                 : #define CPUID_EDX_CLFLUSH    0x00080000  /* CLFLUSH instruction */
      49                 : /* 0x00100000 reserved */
      50                 : #define CPUID_EDX_DS         0x00200000  /* Debug Store */
      51                 : #define CPUID_EDX_ACPI       0x00400000  /* Thermal Monitor and Clock Ctrl */
      52                 : #define CPUID_EDX_MMX        0x00800000  /* MMX extensions */
      53                 : #define CPUID_EDX_FXSR       0x01000000  /* FXSAVE/FXRSTOR instructions */
      54                 : #define CPUID_EDX_SSE        0x02000000  /* SSE extensions */
      55                 : #define CPUID_EDX_SSE2       0x04000000  /* SSE2 extensions */
      56                 : #define CPUID_EDX_SS         0x08000000  /* Self snoop */
      57                 : #define CPUID_EDX_HTT        0x10000000  /* Hyper-threading */
      58                 : #define CPUID_EDX_TM         0x20000000  /* Thermal monitor */
      59                 : /* 0x40000000 reserved */
      60                 : #define CPUID_EDX_PBE        0x80000000  /* Pending Break Enable */
      61                 : 
      62                 : #define CPUID_ECX_SSE3       0x00000001  /* SSE3 extensions */
      63                 : #define CPUID_ECX_CLMUL      0x00000002  /* PCLMULQDQ instruction */
      64                 : #define CPUID_ECX_DTES64     0x00000004  /* 64-bit DS Area */
      65                 : #define CPUID_ECX_MON        0x00000008  /* MONITOR/MWAIT instructions */
      66                 : #define CPUID_ECX_DSCPL      0x00000010  /* CPL Qualified Debug Store */
      67                 : #define CPUID_ECX_VMX        0x00000020  /* Virtual Machine Extensions */
      68                 : #define CPUID_ECX_SMX        0x00000040  /* Safer Mode Extensions */
      69                 : #define CPUID_ECX_EST        0x00000080  /* Enahcned SpeedStep */
      70                 : #define CPUID_ECX_TM2        0x00000100  /* Thermal Monitor 2 */
      71                 : #define CPUID_ECX_SSSE3      0x00000200  /* SS_S_E3 extensions */
      72                 : #define CPUID_ECX_CXID       0x00000400  /* L1 context ID */
      73                 : /* 0x00000800 reserved */
      74                 : #define CPUID_ECX_FMA        0x00001000  /* FMA instructions */
      75                 : #define CPUID_ECX_CX16       0x00002000  /* CMPXCHG16B instruction */
      76                 : #define CPUID_ECX_XTPR       0x00004000  /* xTPR update control */
      77                 : #define CPUID_ECX_PDCM       0x00008000  /* Perf/Debug Capability MSR */
      78                 : /* 0x00010000 reserved */
      79                 : #define CPUID_ECX_PCID       0x00020000  /* Process-context identifiers */
      80                 : #define CPUID_ECX_DCA        0x00040000  /* Direct Cache Access */
      81                 : #define CPUID_ECX_SSE41      0x00080000  /* SSE4.1 extensions */
      82                 : #define CPUID_ECX_SSE42      0x00100000  /* SSE4.2 extensions */
      83                 : #define CPUID_ECX_x2APIC     0x00800000  /* x2APIC feature */
      84                 : #define CPUID_ECX_MOVBE      0x00400000  /* MOVBE instruction */
      85                 : #define CPUID_ECX_POPCNT     0x00800000  /* POPCNT instruction */
      86                 : #define CPUID_ECX_TSCDDLN    0xx1000000  /* TSC-Deadline */
      87                 : #define CPUID_ECX_AES        0x02000000  /* AES instructions */
      88                 : #define CPUID_ECX_XSAVE      0x04000000  /* XSAVE/XRSTOR/XSETBV/XGETBV */
      89                 : #define CPUID_ECX_OSXSAVE    0x08000000  /* XSAVE et al enabled by OS */
      90                 : #define CPUID_ECX_AVX        0x10000000  /* AVX instructions */
      91                 : #define CPUID_ECX_F16C       0x20000000  /* 16bit floating-point instructions */
      92                 : #define CPUID_ECX_RDRAND     0x40000000  /* RDRAND instruction */
      93                 : /* 0x80000000 reserved */
      94                 : 
      95                 : /* Function 07h main leaf (ecx = 0) */
      96                 : #define CPUID_EBX_FSGSBASE   0x00000001  /* RD/WR FS/GS BASE instructions */
      97                 : /* 0x00000002 reserved */
      98                 : /* 0x00000004 reserved */
      99                 : #define CPUID_EBX_BMI1       0x00000008  /* BMI1 instructions */
     100                 : #define CPUID_EBX_HLE        0x00000010  /* HLE instructions */
     101                 : #define CPUID_EBX_AVX2       0x00000020  /* AVX2 instructions */
     102                 : #define CPUID_EBX_SMEP       0x00000040  /* Supervisor Mode Exec-Protection */
     103                 : /* 0x00000080 reserved */
     104                 : #define CPUID_EBX_BMI2       0x00000100  /* BMI2 instructions */
     105                 : #define CPUID_EBX_ERMS       0x00000200  /* Enhanced REP MOVSB/STOSB */
     106                 : #define CPUID_EBX_INVPCID    0x00000400  /* Invalidate Processor Context ID */
     107                 : #define CPUID_EBX_RTM        0x00000800  /* Restricted Transactional Memory */
     108                 : /* 0xFFFFF000 reserved */
     109                 : 
     110                 : /* AMD-specific masks - most are the same as in eax == 1 subfunction */
     111                 : /* 0x00000001 duplicates CPUID_EDX_x87 */
     112                 : /* 0x00000002 duplicates CPUID_EDX_VME */
     113                 : /* 0x00000004 duplicates CPUID_EDX_DEB */
     114                 : /* 0x00000008 duplicates CPUID_EDX_PSE */
     115                 : /* 0x00000010 duplicates CPUID_EDX_TSC */
     116                 : /* 0x00000020 duplicates CPUID_EDX_MSR */
     117                 : /* 0x00000040 duplicates CPUID_EDX_PAE */
     118                 : /* 0x00000080 duplicates CPUID_EDX_MCE */
     119                 : /* 0x00000100 duplicates CPUID_EDX_CX8 */
     120                 : /* 0000000200 duplicates CPUID_EDX_APIC */
     121                 : /* 0x00000400 reserved */
     122                 : #define CPUID_EDX_SYSCALL    0x00000800  /* SYSCALL/SYSRET instructions */
     123                 : /* 0x00001000 duplicates CPUID_EDX_MTRR */
     124                 : /* 0x00002000 duplicates CPUID_EDX_PGE */
     125                 : /* 0x00004000 duplicates CPUID_EDX_MCA */
     126                 : /* 0x00008000 duplicates CPUID_EDX_CMOV */
     127                 : /* 0x00010000 duplicates CPUID_EDX_PAT */
     128                 : /* 0x00020000 duplicates CPUID_EDX_PSE36 */
     129                 : /* 0x00040000 reserved */
     130                 : /* 0x00080000 reserved */
     131                 : #define CPUID_EDX_NX         0x00100000  /* Execute Disable Bit available */
     132                 : /* 0x00200000 reserved */
     133                 : #define CPUID_EDX_EMMX       0x00400000  /* Extensions to MMX instructions */
     134                 : /* 0x00800000 duplicates CPUID_EDX_MMX */
     135                 : /* 0x01000000 duplicates CPUID_EDX_FXSR */
     136                 : #define CPUID_EDX_FFFXSR     0x02000000  /* FXSAVE/FXRSTOR optimizations */
     137                 : #define CPUID_EDX_1GBPAGES   0x04000000  /* 1-GB large page support */
     138                 : #define CPUID_EDX_TSCP       0x08000000  /* RDTSCP instruction */
     139                 : /* 0x10000000 reserved */
     140                 : #define CPUID_EDX_LM         0x20000000  /* Longmode (AKA x86-64 mode) */
     141                 : #define CPUID_EDX_E3DN       0x40000000  /* Extensions to 3DNow! instructions */
     142                 : #define CPUID_EDX_3DN        0x80000000  /* 3DNow! instructions */
     143                 : 
     144                 : #define CPUID_ECX_LAHF       0x00000001  /* LAHF/SAHF in x86-64 mode */
     145                 : #define CPUID_ECX_CMPLEGACY  0x00000002  /* Core Multi-Processing legacy mode */
     146                 : #define CPUID_ECX_SVM        0x00000004  /* Secure Virtual Machine */
     147                 : #define CPUID_ECX_EXTAPIC    0x00000008  /* Extended APIC space */
     148                 : #define CPUID_ECX_ALTMOVCR8  0x00000010  /* LOCK MOV CR0 means MOV CR8 */
     149                 : #define CPUID_ECX_ABM        0x00000020  /* LZCNT instruction */
     150                 : #define CPUID_ECX_SSE4A      0x00000040  /* SSRE4A instructions */
     151                 : #define CPUID_ECX_MISALGNSSE 0x00000080  /* Misalign SSE mode */
     152                 : #define CPUID_ECX_PRE        0x00000100  /* 3DNow! prefetch */
     153                 : #define CPUID_ECX_OSVW       0x00000200  /* OS visible workaround */
     154                 : #define CPUID_ECX_IBS        0x00000400  /* Instruction Based Sampling */
     155                 : #define CPUID_ECX_XOP        0x00000800  /* XOP instructions */
     156                 : #define CPUID_ECX_SKINIT     0x00001000  /* SKINIT/STGI are always supported */
     157                 : #define CPUID_ECX_WDT        0x00002000  /* Watchdog timer support */
     158                 : /* 0x00004000 reserved */
     159                 : #define CPUID_ECX_LWP        0x00008000  /* Lightweight profiling support */
     160                 : #define CPUID_ECX_FMA4       0x00010000  /* FMA4 instructions */
     161                 : /* 0x00020000 reserved */
     162                 : /* 0x00040000 reserved */
     163                 : #define CPUID_ECX_NODEID     0x00080000  /* MSRC001_100C[NodeId, NodesPerCPU] */
     164                 : /* 0x00100000 reserved */
     165                 : #define CPUID_ECX_TBM        0x00200000  /* Trailing bit manipulations */
     166                 : #define CPUID_ECX_TOPOLOGY   0x00400000  /* Topology extensions support */
     167                 : /* 0xFF800000 reserved */
     168                 : #define CPUID_NONE           0x00000000 /* bogus value */
     169                 : 
     170                 : typedef enum {
     171                 :   CFReg_EAX_I=0,  /* eax == 1 */
     172                 :   CFReg_EBX_I,    /* eax == 1 */
     173                 :   CFReg_ECX_I,    /* eax == 1 */
     174                 :   CFReg_EDX_I,    /* eax == 1 */
     175                 :   CFReg_EAX_7,    /* eax == 7; ecx == 0 */
     176                 :   CFReg_EBX_7,    /* eax == 7; ecx == 0 */
     177                 :   CFReg_ECX_7,    /* eax == 7; ecx == 0 */
     178                 :   CFReg_EDX_7,    /* eax == 7; ecx == 0 */
     179                 :   CFReg_EAX_A,    /* eax == 0x80000001 */
     180                 :   CFReg_EBX_A,    /* eax == 0x80000001 */
     181                 :   CFReg_ECX_A,    /* eax == 0x80000001 */
     182                 :   CFReg_EDX_A,    /* eax == 0x80000001 */
     183                 :   CFReg_NONE      /* bogus value */
     184                 : } CPUFeatureReg;
     185                 : 
     186                 : enum {
     187                 :   kFeatureFixedOff,
     188                 :   kFeatureFixedOn
     189                 : };
     190                 : 
     191                 : typedef struct cpufeature {
     192                 :   uint8_t reg;
     193                 :   uint8_t fixedFeature;
     194                 :   uint32_t mask;
     195                 :   const char *name;
     196                 : } CPUFeature;
     197                 : 
     198                 : static const CPUFeature CPUFeatureDescriptions[(int)NaClCPUFeatureX86_Max] = {
     199                 : #define NACL_X86_CPU_FEATURE(id, reg, idx, fix, ven, str)       \
     200                 :   {                                                             \
     201                 :     NACL_CONCAT(CFReg_, reg),                                   \
     202                 :     NACL_CONCAT(kFeature, fix),                                 \
     203                 :     NACL_CONCAT(CPUID_, idx),                                   \
     204                 :     str,                                                        \
     205                 :   },
     206                 : #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86_features.h"
     207                 : #undef NACL_X86_CPU_FEATURE
     208                 : };
     209                 : 
     210                 : #define /* static const int */ kVendorIDLength 13
     211                 : static const char Intel_CPUID0[kVendorIDLength]   = "GenuineIntel";
     212                 : static const char AMD_CPUID0[kVendorIDLength]     = "AuthenticAMD";
     213                 : #ifdef NOTYET
     214                 : static const char UMC_CPUID0[kVendorIDLength]     = "UMC UMC UMC ";
     215                 : static const char Cyrix_CPUID0[kVendorIDLength]   = "CyrixInstead";
     216                 : static const char NexGen_CPUID0[kVendorIDLength]  = "NexGenDriven";
     217                 : static const char Cantaur_CPUID0[kVendorIDLength] = "CentaurHauls";
     218                 : static const char Rise_CPUID0[kVendorIDLength]    = "RiseRiseRise";
     219                 : static const char SiS_CPUID0[kVendorIDLength]     = "SiS SiS SiS ";
     220                 : static const char TM_CPUID0[kVendorIDLength]      = "GenuineTMx86";
     221                 : static const char NSC_CPUID0[kVendorIDLength]     = "Geode by NSC";
     222                 : #endif
     223                 : 
     224                 : static int asm_HasCPUID(void) {
     225             565 :   volatile int before, after, result;
     226                 : #if NACL_BUILD_SUBARCH == 64
     227                 :   /* Note: If we are running in x86-64, then cpuid must be defined,
     228                 :    * since CPUID dates from DX2 486, and x86-64 was added after this.
     229                 :    */
     230             565 :   return 1;
     231                 : /* TODO(bradchen): split into separate Windows, etc., files */
     232                 : #elif defined(__GNUC__)
     233                 :   __asm__ volatile("pushfl                \n\t" /* save EFLAGS to eax */
     234                 :                    "pop %%eax             \n\t"
     235                 :                    "movl %%eax, %0        \n\t" /* remember EFLAGS in %0 */
     236                 :                    "xor $0x00200000, %%eax\n\t" /* toggle bit 21 */
     237                 :                    "push %%eax            \n\t" /* write eax to EFLAGS */
     238                 :                    "popfl                 \n\t"
     239                 :                    "pushfl                \n\t" /* save EFLAGS to %1 */
     240                 :                    "pop %1                \n\t"
     241                 :                    /*
     242                 :                     * We use "r" constraints here, forcing registers,
     243                 :                     * because a memory reference using the stack
     244                 :                     * pointer wouldn't be safe since we're moving the
     245                 :                     * stack pointer around in between the
     246                 :                     * instructions.  We need to inform the compiler
     247                 :                     * that we're clobbering %eax as a scratch register.
     248                 :                     */
     249                 :                    : "=r" (before), "=r" (after) : : "eax");
     250                 : #elif NACL_WINDOWS
     251                 :   __asm {
     252                 :     pushfd
     253                 :     pop eax
     254                 :     mov before, eax
     255                 :     xor eax, 0x00200000
     256                 :     push eax
     257                 :     popfd
     258                 :     pushfd
     259                 :     pop after
     260                 :   }
     261                 : #else
     262                 : # error Unsupported platform
     263                 : #endif
     264                 :   result = (before ^ after) & 0x0200000;
     265                 :   return result;
     266                 : }
     267                 : 
     268            1695 : static void asm_CPUID(uint32_t op, volatile uint32_t reg[4]) {
     269                 : #if defined(__GNUC__)
     270                 : #if NACL_BUILD_SUBARCH == 64
     271            1695 :  __asm__ volatile("push %%rbx       \n\t" /* save %ebx */
     272                 : #else
     273                 :  __asm__ volatile("pushl %%ebx      \n\t"
     274                 : #endif
     275                 :                    "cpuid            \n\t"
     276                 :                    "movl %%ebx, %1   \n\t"
     277                 :                    /* save what cpuid just put in %ebx */
     278                 : #if NACL_BUILD_SUBARCH == 64
     279                 :                    "pop %%rbx        \n\t"
     280                 : #else
     281                 :                    "popl %%ebx       \n\t" /* restore the old %ebx */
     282                 : #endif
     283                 :                    : "=a"(reg[0]), "=S"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
     284                 :                    : "a"(op)
     285                 :                    : "cc");
     286                 : #elif NACL_WINDOWS
     287                 :   __cpuid((uint32_t*)reg, op);
     288                 : #else
     289                 : # error Unsupported platform
     290                 : #endif
     291            1695 : }
     292                 : 
     293                 : /*
     294                 :  * Historically CPUID only used eax to select "CPUID function". Function 07h
     295                 :  * broke this tradition: it's now required to specify "leaf" in ECX register.
     296                 :  *
     297                 :  * We can specify leaf in all cases (older "CPUID functions" will just ignore
     298                 :  * it), but there is a catch: MSVC 2005 or below don't include __cpuidex
     299                 :  * intrinsic required to call CPUID with leaf support!
     300                 :  *
     301                 :  * Thus we have two functions: asm_CPUID (for "CPUID functions" without leaves)
     302                 :  * and asm_CPUIDx (for "CPUID functions" with leaves). If code is compiled using
     303                 :  * MSVC 2005 or MSVC 2008 then features detected using function 07h will not be
     304                 :  * available.
     305                 :  *
     306                 :  * Note: MSVC 2008 is particularly problematic: MSVC 2008 does not support
     307                 :  * __cpuidex while MSVC 2008 SP1 does. Unfortunatelly there are no easy way
     308                 :  * to distinguish MSVC 2008 SP1 from MSVC 2008 using ifdef's thus we disable
     309                 :  * __cpuidex for MSVC 2008 unconditionally.
     310                 :  */
     311             565 : static void asm_CPUIDx(uint32_t op, volatile uint32_t reg[4], uint32_t ecx) {
     312                 : #if defined(__GNUC__)
     313                 : #if NACL_BUILD_SUBARCH == 64
     314             565 :  __asm__ volatile("push %%rbx       \n\t" /* save %ebx */
     315                 : #else
     316                 :  __asm__ volatile("pushl %%ebx      \n\t"
     317                 : #endif
     318                 :                    "cpuid            \n\t"
     319                 :                    "movl %%ebx, %1   \n\t"
     320                 :                    /* save what cpuid just put in %ebx */
     321                 : #if NACL_BUILD_SUBARCH == 64
     322                 :                    "pop %%rbx        \n\t"
     323                 : #else
     324                 :                    "popl %%ebx       \n\t" /* restore the old %ebx */
     325                 : #endif
     326                 :                    : "=a"(reg[0]), "=S"(reg[1]), "=c"(reg[2]), "=d"(reg[3])
     327                 :                    : "a"(op), "c"(ecx)
     328                 :                    : "cc");
     329                 : #elif NACL_WINDOWS
     330                 : #ifdef _MSC_VER
     331                 : #if _MSC_VER < 1600
     332                 :   reg[0] = 0;
     333                 :   reg[1] = 0;
     334                 :   reg[2] = 0;
     335                 :   reg[3] = 0;
     336                 : #else
     337                 :   __cpuidex((uint32_t*)reg, op, ecx);
     338                 : #endif
     339                 : #else /* NACL_WINDOWS, but _MSC_VER is not defined */
     340                 : /* This is Windows but not MSVC: who knows if __cpuidex is available?  */
     341                 : # error Unsupported compiler
     342                 : #endif
     343                 : #else
     344                 : # error Unsupported platform
     345                 : #endif
     346             565 : }
     347                 : 
     348             565 : static void CacheCPUVersionID(NaClCPUData* data) {
     349             565 :   uint32_t reg[4] = {0, 0, 0, 0 };
     350             565 :   asm_CPUID(0, reg);
     351             565 :   data->_vidwords[0] = reg[1];
     352             565 :   data->_vidwords[1] = reg[3];
     353             565 :   data->_vidwords[2] = reg[2];
     354             565 :   data->_vidwords[3] = 0;
     355             565 : }
     356                 : 
     357                 : /* Defines the (cached) cpu version id */
     358                 : #define CPUVersionID(data) ((char*) (data)->_vidwords)
     359                 : 
     360                 : 
     361                 : /* Cache feature vector as array of uint32_t [ecx, edx] */
     362             565 : static void CacheCPUFeatureVector(NaClCPUData* data) {
     363             565 :   int i;
     364           14690 :   for (i = 0; i < kMaxCPUFeatureReg; ++i) {
     365            6780 :     data->_featurev[i] = 0;
     366            6780 :   }
     367             565 :   asm_CPUID(1, data->_featurev);
     368                 :   /* This is for for model-specific instructions from AMD and Intel after
     369                 :      AMD's Bulldozer (introduced BMI1 set) and Intel's Haswell (introduced
     370                 :      AVX2, BMI2, HLE, RTM, and RD/WR FS/GS BASE instructions).  */
     371             565 :   asm_CPUIDx(7, &data->_featurev[CFReg_EAX_7], 0);
     372                 :   /* this is for AMD CPUs */
     373             565 :   asm_CPUID(0x80000001, &data->_featurev[CFReg_EAX_A]);
     374                 : #if 0
     375                 :   /* print feature vector */
     376                 :   printf("CPUID:  %08x  %08x  %08x  %08x\n",
     377                 :          data->_featurev[0],
     378                 :          data->_featurev[1],
     379                 :          data->_featurev[2],
     380                 :          data->_featurev[3]);
     381                 :   printf("CPUID:  %08x  %08x  %08x  %08x\n",
     382                 :          data->_featurev[4],
     383                 :          data->_featurev[5],
     384                 :          data->_featurev[6],
     385                 :          data->_featurev[7]);
     386                 : #endif
     387             565 : }
     388                 : 
     389                 : /* CacheGetCPUIDString creates an ASCII string that identfies this CPU's */
     390                 : /* vendor ID, family, model, and stepping, as per the CPUID instruction */
     391             565 : static void CacheGetCPUIDString(NaClCPUData* data) {
     392             565 :   char *cpuversionid = CPUVersionID(data);
     393             565 :   uint32_t *fv = data->_featurev;
     394             565 :   char* wlid = data->_wlid;
     395                 :   /* Subtract 1 in this assert to avoid counting two null characters. */
     396                 :   assert(9 + kVendorIDLength - 1 == kCPUIDStringLength);
     397            1695 :   memcpy(wlid, cpuversionid, kVendorIDLength-1);
     398             565 :   SNPRINTF(&(wlid[kVendorIDLength-1]), 9, "%08x", (int)fv[CFReg_EAX_I]);
     399             565 : }
     400                 : 
     401             269 : char *GetCPUIDString(NaClCPUData* data) {
     402             269 :   return data->_wlid;
     403                 : }
     404                 : 
     405                 : /* Returns true if the given feature is defined by the CPUID. */
     406           11813 : static int CheckCPUFeature(NaClCPUData* data, NaClCPUFeatureX86ID fid) {
     407           11813 :   const CPUFeature *f = &CPUFeatureDescriptions[fid];
     408           11813 :   uint32_t *fv = data->_featurev;
     409           23330 :   if ((fid == NaClCPUFeatureX86_CPUIDSupported) ||
     410                 :       (fid == NaClCPUFeatureX86_CPUSupported)) {
     411                 :     /* CPUIDSupported and CPUSupported aren't actually in CPUID,
     412                 :        CPUFeatureDescriptions therefore doesn't contain actual reg/mask for
     413                 :        them. */
     414             592 :     return 1;
     415                 :   }
     416           11221 :   if (fv[f->reg] & f->mask) {
     417            5624 :     return 1;
     418                 :   } else {
     419            5597 :     return 0;
     420                 :   }
     421           11813 : }
     422                 : 
     423                 : uint64_t NaClXGETBV(uint32_t);
     424                 : 
     425                 : /* Cache XCR vector */
     426             565 : static void CacheCPUXCRVector(NaClCPUData* data) {
     427             565 :   if (CheckCPUFeature(data, NaClCPUFeatureX86_OSXSAVE)) {
     428               0 :     int i;
     429               0 :     for (i = 0; i < kMaxCPUXCRReg; ++i) {
     430               0 :       data->_xcrv[i] = NaClXGETBV(i);
     431               0 :     }
     432               0 :   } else {
     433             565 :     int i;
     434            2260 :     for (i = 0; i < kMaxCPUXCRReg; ++i) {
     435             565 :       data->_xcrv[i] = 0;
     436             565 :     }
     437                 :   }
     438             565 : }
     439                 : 
     440                 : /* Check that we have a supported 386 architecture. NOTE:
     441                 :  * As as side effect, the given cpu features is cleared before
     442                 :  * setting the appropriate fields.
     443                 :  */
     444             296 : static void CheckNaClArchFeatures(NaClCPUData *data,
     445             296 :                                   NaClCPUFeaturesX86 *features) {
     446             296 :   const size_t kCPUID0Length = 12;
     447             296 :   char *cpuversionid;
     448             296 :   if (data->_has_CPUID) {
     449             296 :     NaClSetCPUFeatureX86(features, NaClCPUFeatureX86_CPUIDSupported, 1);
     450             296 :   }
     451             296 :   cpuversionid = CPUVersionID(data);
     452             296 :   if (strncmp(cpuversionid, Intel_CPUID0, kCPUID0Length) == 0) {
     453             296 :     NaClSetCPUFeatureX86(features, NaClCPUFeatureX86_CPUSupported, 1);
     454             296 :   } else if (strncmp(cpuversionid, AMD_CPUID0, kCPUID0Length) == 0) {
     455               0 :     NaClSetCPUFeatureX86(features, NaClCPUFeatureX86_CPUSupported, 1);
     456               0 :   }
     457             296 : }
     458                 : 
     459             574 : void NaClSetAllCPUFeaturesX86(NaClCPUFeatures *f) {
     460                 :   /* TODO(jfb) Use a safe cast in this interface. */
     461             574 :   NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) f;
     462                 :   /* Be a little more pedantic than using memset because we don't know exactly
     463                 :    * how the structure is laid out.  If we use memset, fields may be initialized
     464                 :    * to 0xff instead of 1 ... this isn't the end of the world but it can
     465                 :    * create a skew if the structure is hashed, etc.
     466                 :    */
     467             574 :   int id;
     468                 :   /* Ensure any padding is zeroed. */
     469             574 :   NaClClearCPUFeaturesX86(features);
     470           44772 :   for (id = 0; id < NaClCPUFeatureX86_Max; ++id) {
     471           21812 :     NaClSetCPUFeatureX86(features, id, 1);
     472           21812 :   }
     473             574 : }
     474                 : 
     475                 : /* WARNING: This routine and subroutines it uses are not threadsafe.
     476                 :  * However, if races occur, they are short lived, and at worst, will
     477                 :  * result in defining fewer features than are actually supported by
     478                 :  * the hardware. Hence, if a race occurs, the validator may reject
     479                 :  * some features that should not be rejected.
     480                 :  */
     481             296 : static void GetCPUFeatures(NaClCPUData* data, NaClCPUFeaturesX86 *cpuf) {
     482             296 :   int id;
     483             296 :   NaClClearCPUFeaturesX86(cpuf);
     484             296 :   CheckNaClArchFeatures(data, cpuf);
     485             296 :   if (!NaClGetCPUFeatureX86(cpuf, NaClCPUFeatureX86_CPUIDSupported)) {
     486               0 :     return;
     487                 :   }
     488                 : 
     489           23088 :   for (id = 0; id < NaClCPUFeatureX86_Max; ++id) {
     490           11248 :     NaClSetCPUFeatureX86(cpuf, id, CheckCPUFeature(data, id));
     491           11248 :   }
     492                 : 
     493                 :   /*
     494                 :    * If the operating system doesn't maintain the YMM state,
     495                 :    * pretend we don't have the instructions available at all.
     496                 :    */
     497             296 :   if (!(NaClGetCPUFeatureX86(cpuf, NaClCPUFeatureX86_OSXSAVE)
     498                 :         && (data->_xcrv[0] & 6) == 6)) {
     499             296 :     NaClSetCPUFeatureX86(cpuf, NaClCPUFeatureX86_AVX, 0);
     500             296 :     NaClSetCPUFeatureX86(cpuf, NaClCPUFeatureX86_F16C, 0);
     501             296 :     NaClSetCPUFeatureX86(cpuf, NaClCPUFeatureX86_FMA, 0);
     502             296 :     NaClSetCPUFeatureX86(cpuf, NaClCPUFeatureX86_FMA4, 0);
     503             296 :   }
     504             296 : }
     505                 : 
     506             565 : void NaClCPUDataGet(NaClCPUData* data) {
     507             565 :   data->_has_CPUID = asm_HasCPUID();
     508             565 :   CacheCPUVersionID(data);
     509             565 :   CacheCPUFeatureVector(data);
     510             565 :   CacheCPUXCRVector(data);
     511             565 :   CacheGetCPUIDString(data);
     512             565 : }
     513                 : 
     514             296 : void NaClGetCurrentCPUFeaturesX86(NaClCPUFeatures *f) {
     515                 :   /* TODO(jfb) Use a safe cast in this interface. */
     516             296 :   NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) f;
     517             296 :   NaClCPUData cpu_data;
     518             296 :   NaClCPUDataGet(&cpu_data);
     519             296 :   GetCPUFeatures(&cpu_data, features);
     520             296 : }
     521                 : 
     522                 : /* The CPUFeaturesDescriptions struct defines the CPU feature model for
     523                 :  * fixed-feature CPU mode. We currently require the same set of features
     524                 :  * for both 32- and 64-bit x86 CPUs, intended to be supported by
     525                 :  * most/all post-Pentium III CPUs. This set may be something we need to
     526                 :  * revisit in the future.
     527                 :  */
     528               2 : int NaClFixCPUFeaturesX86(NaClCPUFeatures *f) {
     529                 :   /* TODO(jfb) Use a safe cast in this interface. */
     530               2 :   NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) f;
     531               2 :   NaClCPUFeatureX86ID fid;
     532               2 :   int rvalue = 1;
     533                 : 
     534             156 :   for (fid = 0; fid < NaClCPUFeatureX86_Max; fid++) {
     535              76 :     if (CPUFeatureDescriptions[fid].fixedFeature) {
     536              22 :       if (!NaClGetCPUFeatureX86(features, fid)) {
     537                 :         /* This CPU is missing a required feature. */
     538               0 :         NaClLog(LOG_ERROR,
     539                 :                 "This CPU is missing a feature required by fixed-mode: %s\n",
     540               0 :                 NaClGetCPUFeatureX86Name(fid));
     541               0 :         rvalue = 0;  /* set return value to indicate failure */
     542               0 :       }
     543              22 :     } else {
     544                 :       /* Feature is not in the fixed model.
     545                 :        * Ensure features does not have it either.
     546                 :        */
     547              54 :       NaClSetCPUFeatureX86(features, fid, 0);
     548                 :     }
     549              76 :   }
     550               2 :   return rvalue;
     551                 : }
     552                 : 
     553              33 : const char* NaClGetCPUFeatureX86Name(NaClCPUFeatureX86ID id) {
     554              33 :   return CPUFeatureDescriptions[id].name;
     555                 : }
     556                 : 
     557           34892 : void NaClSetCPUFeatureX86(NaClCPUFeaturesX86 *f, NaClCPUFeatureX86ID id,
     558           34892 :                           int state) {
     559           34892 :   f->data[id] = (char) state;
     560           34892 : }
     561                 : 
     562            2009 : void NaClClearCPUFeaturesX86(NaClCPUFeaturesX86 *features) {
     563            6027 :   memset(features, 0, sizeof(*features));
     564            2009 : }
     565                 : 
     566             569 : void NaClCopyCPUFeaturesX86(NaClCPUFeaturesX86 *target,
     567             569 :                             const NaClCPUFeaturesX86 *source) {
     568            1707 :   memcpy(target, source, sizeof(*target));
     569             569 : }
     570                 : 
     571            1415 : int NaClArchSupportedX86(const NaClCPUFeaturesX86 *f) {
     572            1415 :   return (NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUIDSupported) &&
     573            1415 :           NaClGetCPUFeatureX86(f, NaClCPUFeatureX86_CPUSupported));
     574            1415 : }

Generated by: LCOV version 1.7