cpuident.c
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:11k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hlxclib/string.h" // memset
  36. #include "cpuident.h"
  37. /*
  38.  * check if this cpu supports the cpuid instruction.
  39.  * returns: 1 if support, 0 else
  40.  */
  41. static int hasCPUID(void)
  42. {
  43.     int has_cpuid = 0 ;
  44. #if defined(_M_IX86) && defined(_MSC_VER)
  45.     /* we are compiling under MSVC, on x86 */
  46.     __asm {
  47.         pushfd                  // Get original EFLAGS
  48.         pop eax                 // Get original EFLAGS
  49.         mov ecx,    eax         // save original EFLAGS
  50.         xor eax,    0x200000     // Flip ID bit in EFLAGS
  51.         push        eax         // Save new EFLAGS value on stack
  52.         popfd                   // Replace current EFLAGS value
  53.         pushfd                  // Get new EFLAGS
  54.         pop eax                 // Get new EFLAGS
  55.         xor eax,    ecx         // did state toggle?
  56.         and eax,    0x200000
  57.         mov has_cpuid, eax
  58.     }
  59. #endif
  60. #if defined(__i386) && defined(__GNUC__)
  61.     /* we are compiling under gcc */
  62.     __asm__ __volatile (
  63.       "pushfl;"
  64.       "popl %%eax;"
  65.       "movl %%eax, %%ecx;"
  66.       "xorl $0x200000, %%eax;"
  67.       "pushl %%eax;"
  68.       "popfl;"
  69.       "pushfl;"
  70.       "popl %%eax;"
  71.       "xorl %%ecx, %%eax;"
  72.       "andl $0x200000, %%eax;"
  73.       "movl %%eax,%0;"
  74.     :"=m" (has_cpuid)
  75.     : /*no input*/
  76.     : "eax","ecx","cc"
  77.     );
  78. #endif
  79.     return (has_cpuid != 0) ;
  80. }
  81. /*
  82.  * Issue a cpuid instruction
  83.  */
  84. #if defined(_M_IX86) || defined(__i386)
  85. static void cpuid(long cmd, long* a, long *b, long *c, long *d)
  86. {
  87.     long la=0,lb=0,lc=0,ld=0 ;
  88. #if defined(_MSC_VER)
  89.     /* we are compiling under MSVC, on x86 */
  90.     __asm {
  91.         mov eax,cmd
  92.         push ebx /* save ebx */
  93.         __emit 0x0F /* cpuid was not supported by MSVC5, thus emit it */
  94.         __emit 0xA2
  95.         mov ebx,esi
  96.         pop ebx /* restore ebx */
  97.         mov la,eax
  98.         mov lb,esi
  99.         mov lc,ecx
  100.         mov ld,edx
  101.     }
  102. #endif /* MSVC */
  103. #if defined(__GNUC__)
  104.     /* we are compiling under gcc */
  105.     __asm__ __volatile (
  106.       "movl %4, %%eax;"
  107.       "push %%ebx;"
  108.       "cpuid;"
  109.       "movl %%ebx,%%esi;"
  110.       "popl %%ebx;"
  111.       "movl %%eax, %0;"
  112.       "movl %%esi, %1;"
  113.       "movl %%ecx, %2;"
  114.       "movl %%edx, %3;"
  115.     : "=m" (la), "=m" (lb), "=m" (lc), "=m" (ld)
  116.     : "m" (cmd)
  117.     : "eax","ecx","edx","esi","cc"
  118.     );
  119. #endif /* GNUC */
  120.     *a = la ; *b = lb ; *c = lc ; *d = ld ;
  121. }
  122. #endif /* x86 architecture */
  123. #if defined(_ARM)
  124. #if defined(__linux)
  125. #define has_cpuid() 0 /* we can't currently cpuid under ARM/linux */
  126. #else
  127. #define has_cpuid() 1
  128. #endif
  129. #if defined (__GNUC__)
  130. static int cpu_id(void)
  131. {
  132.     int ret ;
  133. #if defined(__MARM_THUMB__)
  134.     ret = 0x4180720; // XXXNH: until we fix this assembly
  135. #else
  136.     __asm__ ("mrc p15, 0, %0, c0, c0, 0" : "=r" (ret)) ;
  137. #endif
  138.     return ret ;
  139. }
  140. #endif /* GNUC */
  141. #if defined(_MSC_VER)
  142. /* cpu_id is defined in an assembly file */
  143. extern int cpu_id(void);
  144. #endif
  145. #endif /* ARM */
  146. /*
  147.  * routines to check for operating system support for the SSE floating point
  148.  * instructions.
  149.  * Intel recommends to check for OS support by executing an instruction which
  150.  * will fault (SIGILL) and throw an exception in the absence of OS support.
  151.  * Catching the exception signals lack of support.
  152.  *
  153.  * An alternative method would be to check CR4.OSFXSR, but alas, that can only
  154.  * be done if you run in ring 0. Duh.
  155.  */
  156. #if defined __i386 && defined __linux
  157. /* to catch the exception caused by SSE instructions on an OS that does not support
  158.    saving the additional SSE CPU state, we need a signal handler here. If called
  159.    as a result of SIGILL, it will modify eax, and return to the code that caused
  160.    the trap, jumping past the offending instruction.
  161.    */
  162. #include <signal.h>
  163. static void myHandler(int signal, struct sigcontext sc)
  164. {
  165.     // signal "no SSE support" by modifying eax (it is 1 on entry)
  166.     sc.eax = 0 ;
  167.     // we get here because orps xmm0,xmm0 has raised an exception. To avoid
  168.     // repeating this instruction, we increment the PC by three before
  169.     // returning.
  170.     sc.eip += 3 ;
  171. }
  172. #endif
  173. static int bOSHasSSEsupport(void)
  174. {
  175. #if defined(_WIN32) && defined(_M_IX86)
  176.     int bSSE = 1 ;
  177.     // this is a little tricky. For Windows, we use __try/__except.
  178.     // Stack unwinding does not need to be enabled because we
  179.     // catch all exceptions; you can ignore the compiler warning.
  180. #pragma warning(disable:4530)
  181.     __try {
  182.         // Use opcode bytes for the instruction because MSVC and gcc
  183.         // compilers can't compile it yet.
  184.         // __asm orps xmm0,xmm0
  185.         __asm {
  186.     _emit 0x0f
  187.     _emit 0x56
  188.     _emit 0xc0
  189.       }
  190.     }
  191.     __except ( 1 /* EXCEPTION_EXECUTE_HANDLER */ )
  192.     {
  193.         // if an exception occurred, no OS support for xmm register save
  194.         // and restore so don't use SSE nor SSE2 instructions
  195.         bSSE = 0 ;
  196.     }
  197. #pragma warning(default:4530)
  198.     return bSSE ;
  199. #elif defined(__i386) && defined(__linux)
  200.     // On linux, we use an exception handler
  201.     struct sigaction savedSIGILLHandler ;
  202.     struct sigaction newSIGILLHandler ;
  203.     int bSSE ;
  204.     memset (&newSIGILLHandler, 0, sizeof newSIGILLHandler);
  205.     sigemptyset (&newSIGILLHandler.sa_mask);
  206.     newSIGILLHandler.sa_handler =  (void (*)(int))myHandler;
  207.     // install new signal handler
  208.     sigaction(SIGILL, &newSIGILLHandler, &savedSIGILLHandler) ;
  209.     // execute an MME instruction. If it fails, the exception handler
  210.     // will be called, which will modify eax (bSSE)
  211.     __asm__ __volatile ("mov $1,%0nt"
  212. ".byte 0x0f,0x56,0xc0nt" /* xorps xmm0,xmm0 */
  213. : "=a" (bSSE)) ;
  214.     // restore signal handler
  215.     sigaction(SIGILL,&savedSIGILLHandler,NULL) ;
  216.     return bSSE ;
  217. #else
  218.     return 0 ; // no OS SSE support detectable
  219. #endif
  220. }
  221. enum
  222. {
  223.     ulBitMM = 1<<23,
  224.     ulBitEM = 1<<2, /* emulation enabled / disabled */
  225.     ulBitMSR = 1<<5,
  226.     ulBitTSC = 1<<4,
  227.     ulBitXMM = 1<<25,/* Streaming SIMD Extensions-enabled? */
  228.     ulBitSSE2 = 1<<26
  229. } ;
  230. void
  231. CPUIdentify(CPUInformation* pInfo)
  232. {
  233.     int id;
  234.     memset(pInfo, 0, sizeof(*pInfo)) ;
  235.     pInfo->architecture = ulArchitectureUNKNOWN ;
  236. #if defined(_M_IX86) || defined(__i386)
  237.     /* we assume we are running at least on 386 or compatible */
  238.     pInfo->architecture = ulArchitectureIntel ;
  239.     pInfo->specific.m_x86.family = ulFamily80386 ;
  240.     if (hasCPUID())
  241.     {
  242.         long a,b,c,d ;
  243.         /* if we have cpuid, we are at least 486 */
  244.         pInfo->specific.m_x86.family = ulFamily80486 ;
  245.         /* First, invoke cpuid(0, ....). eax (returned in a) tells us
  246.            the maximum p which we can call cpuid(p, ...) with. Pentium
  247.            and later will have p >= 1. */
  248.         cpuid (0,&a,&b,&c,&d) ;
  249.         /* cpuid(1,...) checks for additional processor features. */
  250.         if (a >= 1)
  251.         {
  252.             cpuid (1,&a,&b,&c,&d) ;
  253.             pInfo->specific.m_x86.family   = (a & 0xf00) >> 8 ;
  254.             pInfo->specific.m_x86.model    = (a & 0x0f0) >> 4 ;
  255.             pInfo->specific.m_x86.stepping = (a & 0x00f) ;
  256.             pInfo->specific.m_x86.hasPMC = (pInfo->specific.m_x86.family == 6)  ;
  257.             pInfo->specific.m_x86.hasMSR = (d & ulBitMSR) ;
  258.             pInfo->specific.m_x86.hasTSC = (d & ulBitTSC) ;
  259.             if (d & ulBitMM)
  260.             {
  261.                 pInfo->specific.m_x86.hasPMC  = 1 ;
  262.                 pInfo->specific.m_x86.hasMMX  = 1 ;
  263.                 pInfo->specific.m_x86.hasSSE  = (d & ulBitXMM)  ;
  264.                 pInfo->specific.m_x86.hasSSE2 = (d & ulBitSSE2) ;
  265.             }
  266.         }
  267.     }
  268. if (pInfo->specific.m_x86.hasSSE || pInfo->specific.m_x86.hasSSE2)
  269. {
  270. // SSE / SSE2 floating point instructions require OS FXSAVE
  271.         // and FXRSTOR support.
  272.         pInfo->specific.m_x86.hasSSE_OSSupport = bOSHasSSEsupport() ;
  273. }
  274. #endif // if defined i386
  275. #ifdef _ARM
  276.     if (!has_cpuid())
  277.         return ;
  278.     id = cpu_id() ;
  279.     switch (id & 0xf000)
  280.     {
  281.     case 0x0<<12: // pre-ARM7
  282.         pInfo->specific.m_arm.family = ulFamily_PREARM7 ;
  283. pInfo->specific.m_arm.implementor = ARM_IMPL_ARM ;
  284. switch (id >> 4) {
  285. case 0x4156030: pInfo->architecture = ulArchitectureARM_ARCH2 ; break ;
  286. case 0x4156060:
  287. case 0x4156061:
  288. case 0x4156062:
  289.     pInfo->architecture = ulArchitectureARM_ARCH3 ; break ;
  290. default:
  291.     pInfo->architecture = ulArchitectureUNKNOWN ; break ;
  292. }
  293. break ;
  294.     case 0x7<<12: // ARM7
  295.         pInfo->specific.m_arm.family        = ulFamily_ARM7 ;
  296. pInfo->architecture  = ((id >> 23) & 1) ? ulArchitectureARM_ARCH4T : ulArchitectureARM_ARCH3 ;
  297. pInfo->specific.m_arm.implementor   = id >> 24 ;
  298. pInfo->specific.m_arm.variant       = (id >> 16) & 0x7f ;
  299. pInfo->specific.m_arm.primaryPartNo = (id >> 4) & 0xfff ;
  300. pInfo->specific.m_arm.revision      = id & 0xf ;
  301.     default: // post-ARM7
  302. pInfo->specific.m_arm.family        = ulFamily_POSTARM7 ;
  303. pInfo->specific.m_arm.implementor   = id >> 24 ;
  304. pInfo->specific.m_arm.variant       = (id >> 20) & 0xf ;
  305. pInfo->architecture  = ((id >> 16) & 0xf) - 1 + ulArchitectureARM_ARCH4 ;
  306. pInfo->specific.m_arm.primaryPartNo = (id >> 4) & 0xfff ;
  307. pInfo->specific.m_arm.revision      = id & 0xf ;
  308. if (pInfo->specific.m_arm.implementor == ARM_IMPL_Intel &&
  309.             pInfo->architecture == ulArchitectureARM_ARCH5TE &&
  310.             (id >> 13) & 7 == 1)
  311. {
  312.             // XScale
  313.             pInfo->specific.m_arm.specific.XScale.coreGeneration = (id >> 13) & 7 ; // "1"
  314.             pInfo->specific.m_arm.specific.XScale.coreRevision   = (id >> 10) & 7 ;
  315.             pInfo->specific.m_arm.specific.XScale.productNumber  = (id >> 4) & 63 ;
  316. }
  317. break ;
  318.     }
  319. #endif /* _ARM */
  320. }