cpuident.c
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:12k
源码类别:

Symbian

开发平台:

Visual C++

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