cpuident.c
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:12k
- /* ***** BEGIN LICENSE BLOCK *****
- * Source last modified: $Id: cpuident.c,v 1.12.32.4 2004/07/09 01:48:15 hubbe Exp $
- *
- * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file,
- * are subject to the current version of the RealNetworks Public
- * Source License (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the current version of the RealNetworks Community
- * Source License (the "RCSL") available at
- * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
- * will apply. You may also obtain the license terms directly from
- * RealNetworks. You may not use this file except in compliance with
- * the RPSL or, if you have a valid RCSL with RealNetworks applicable
- * to this file, the RCSL. Please see the applicable RPSL or RCSL for
- * the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL") in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your version of
- * this file only under the terms of the GPL, and not to allow others
- * to use your version of this file under the terms of either the RPSL
- * or RCSL, indicate your decision by deleting the provisions above
- * and replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient may
- * use your version of this file under the terms of any one of the
- * RPSL, the RCSL or the GPL.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the
- * portions it created.
- *
- * This file, and the files included with this file, is distributed
- * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
- * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
- * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
- * ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hlxclib/string.h" // memset
- #include "cpuident.h"
- /*
- * check if this cpu supports the cpuid instruction.
- * returns: 1 if support, 0 else
- */
- static int hasCPUID(void)
- {
- int has_cpuid = 0 ;
- #if defined(_M_IX86) && defined(_MSC_VER)
- /* we are compiling under MSVC, on x86 */
- __asm {
- pushfd // Get original EFLAGS
- pop eax // Get original EFLAGS
- mov ecx, eax // save original EFLAGS
- xor eax, 0x200000 // Flip ID bit in EFLAGS
- push eax // Save new EFLAGS value on stack
- popfd // Replace current EFLAGS value
- pushfd // Get new EFLAGS
- pop eax // Get new EFLAGS
- xor eax, ecx // did state toggle?
- and eax, 0x200000
- mov has_cpuid, eax
- }
- #endif
- #if defined(__i386) && defined(__GNUC__)
- /* we are compiling under gcc */
- __asm__ __volatile (
- "pushfl;"
- "popl %%eax;"
- "movl %%eax, %%ecx;"
- "xorl $0x200000, %%eax;"
- "pushl %%eax;"
- "popfl;"
- "pushfl;"
- "popl %%eax;"
- "xorl %%ecx, %%eax;"
- "andl $0x200000, %%eax;"
- "movl %%eax,%0;"
- :"=m" (has_cpuid)
- : /*no input*/
- : "eax","ecx","cc"
- );
- #endif
- return (has_cpuid != 0) ;
- }
- /*
- * Issue a cpuid instruction
- */
- #if defined(_M_IX86) || defined(__i386)
- static void cpuid(long cmd, long* a, long *b, long *c, long *d)
- {
- long la=0,lb=0,lc=0,ld=0 ;
- #if defined(_MSC_VER)
- /* we are compiling under MSVC, on x86 */
- __asm {
- mov eax,cmd
- push ebx /* save ebx */
- __emit 0x0F /* cpuid was not supported by MSVC5, thus emit it */
- __emit 0xA2
- mov ebx,esi
- pop ebx /* restore ebx */
- mov la,eax
- mov lb,esi
- mov lc,ecx
- mov ld,edx
- }
- #endif /* MSVC */
- #if defined(__GNUC__)
- /* we are compiling under gcc */
- __asm__ __volatile (
- "movl %4, %%eax;"
- "push %%ebx;"
- "cpuid;"
- "movl %%ebx,%%esi;"
- "popl %%ebx;"
- "movl %%eax, %0;"
- "movl %%esi, %1;"
- "movl %%ecx, %2;"
- "movl %%edx, %3;"
- : "=m" (la), "=m" (lb), "=m" (lc), "=m" (ld)
- : "m" (cmd)
- : "eax","ecx","edx","esi","cc"
- );
- #endif /* GNUC */
- *a = la ; *b = lb ; *c = lc ; *d = ld ;
- }
- #endif /* x86 architecture */
- #if defined(_ARM)
- #if defined(__linux)
- #define has_cpuid() 0 /* we can't currently cpuid under ARM/linux */
- #else
- #define has_cpuid() 1
- #endif
- #if defined (__GNUC__)
- static int cpu_id(void)
- {
- int ret ;
- #if defined(__MARM_THUMB__)
- ret = 0x4180720; // XXXNH: until we fix this assembly
- #else
- __asm__ ("mrc p15, 0, %0, c0, c0, 0" : "=r" (ret)) ;
- #endif
- return ret ;
- }
- #endif /* GNUC */
- #if defined(_MSC_VER)
- /* cpu_id is defined in an assembly file */
- extern int cpu_id(void);
- #endif
- #endif /* ARM */
- /*
- * routines to check for operating system support for the SSE floating point
- * instructions.
- * Intel recommends to check for OS support by executing an instruction which
- * will fault (SIGILL) and throw an exception in the absence of OS support.
- * Catching the exception signals lack of support.
- *
- * An alternative method would be to check CR4.OSFXSR, but alas, that can only
- * be done if you run in ring 0. Duh.
- */
- #if defined __i386 && defined __linux
- /* to catch the exception caused by SSE instructions on an OS that does not support
- saving the additional SSE CPU state, we need a signal handler here. If called
- as a result of SIGILL, it will modify eax, and return to the code that caused
- the trap, jumping past the offending instruction.
- */
- #include <signal.h>
- static void myHandler(int signal, struct sigcontext sc)
- {
- // signal "no SSE support" by modifying eax (it is 1 on entry)
- sc.eax = 0 ;
- // we get here because orps xmm0,xmm0 has raised an exception. To avoid
- // repeating this instruction, we increment the PC by three before
- // returning.
- sc.eip += 3 ;
- }
- #endif
- static int bOSHasSSEsupport(void)
- {
- #if defined(_WIN32) && defined(_M_IX86)
- int bSSE = 1 ;
- // this is a little tricky. For Windows, we use __try/__except.
- // Stack unwinding does not need to be enabled because we
- // catch all exceptions; you can ignore the compiler warning.
- #pragma warning(disable:4530)
- __try {
- // Use opcode bytes for the instruction because MSVC and gcc
- // compilers can't compile it yet.
- // __asm orps xmm0,xmm0
- __asm {
- _emit 0x0f
- _emit 0x56
- _emit 0xc0
- }
- }
- __except ( 1 /* EXCEPTION_EXECUTE_HANDLER */ )
- {
- // if an exception occurred, no OS support for xmm register save
- // and restore so don't use SSE nor SSE2 instructions
- bSSE = 0 ;
- }
- #pragma warning(default:4530)
- return bSSE ;
- #elif defined(__i386) && defined(__linux)
- // On linux, we use an exception handler
- struct sigaction savedSIGILLHandler ;
- struct sigaction newSIGILLHandler ;
- int bSSE ;
- memset (&newSIGILLHandler, 0, sizeof newSIGILLHandler);
- sigemptyset (&newSIGILLHandler.sa_mask);
- newSIGILLHandler.sa_handler = (void (*)(int))myHandler;
- // install new signal handler
- sigaction(SIGILL, &newSIGILLHandler, &savedSIGILLHandler) ;
- // execute an MME instruction. If it fails, the exception handler
- // will be called, which will modify eax (bSSE)
- __asm__ __volatile ("mov $1,%0nt"
- ".byte 0x0f,0x56,0xc0nt" /* xorps xmm0,xmm0 */
- : "=a" (bSSE)) ;
- // restore signal handler
- sigaction(SIGILL,&savedSIGILLHandler,NULL) ;
- return bSSE ;
- #else
- return 0 ; // no OS SSE support detectable
- #endif
- }
- enum
- {
- ulBitMM = 1<<23,
- ulBitEM = 1<<2, /* emulation enabled / disabled */
- ulBitMSR = 1<<5,
- ulBitTSC = 1<<4,
- ulBitXMM = 1<<25,/* Streaming SIMD Extensions-enabled? */
- ulBitSSE2 = 1<<26
- } ;
- void
- CPUIdentify(CPUInformation* pInfo)
- {
- int id;
- memset(pInfo, 0, sizeof(*pInfo)) ;
- pInfo->architecture = ulArchitectureUNKNOWN ;
- #if defined(_M_IX86) || defined(__i386)
- /* we assume we are running at least on 386 or compatible */
- pInfo->architecture = ulArchitectureIntel ;
- pInfo->specific.m_x86.family = ulFamily80386 ;
- if (hasCPUID())
- {
- long a,b,c,d ;
- /* if we have cpuid, we are at least 486 */
- pInfo->specific.m_x86.family = ulFamily80486 ;
- /* First, invoke cpuid(0, ....). eax (returned in a) tells us
- the maximum p which we can call cpuid(p, ...) with. Pentium
- and later will have p >= 1. */
- cpuid (0,&a,&b,&c,&d) ;
- /* cpuid(1,...) checks for additional processor features. */
- if (a >= 1)
- {
- cpuid (1,&a,&b,&c,&d) ;
- pInfo->specific.m_x86.family = (a & 0xf00) >> 8 ;
- pInfo->specific.m_x86.model = (a & 0x0f0) >> 4 ;
- pInfo->specific.m_x86.stepping = (a & 0x00f) ;
- pInfo->specific.m_x86.hasPMC = (pInfo->specific.m_x86.family == 6) ;
- pInfo->specific.m_x86.hasMSR = (d & ulBitMSR) ;
- pInfo->specific.m_x86.hasTSC = (d & ulBitTSC) ;
- if (d & ulBitMM)
- {
- pInfo->specific.m_x86.hasPMC = 1 ;
- pInfo->specific.m_x86.hasMMX = 1 ;
- pInfo->specific.m_x86.hasSSE = (d & ulBitXMM) ;
- pInfo->specific.m_x86.hasSSE2 = (d & ulBitSSE2) ;
- }
- }
- }
- if (pInfo->specific.m_x86.hasSSE || pInfo->specific.m_x86.hasSSE2)
- {
- // SSE / SSE2 floating point instructions require OS FXSAVE
- // and FXRSTOR support.
- pInfo->specific.m_x86.hasSSE_OSSupport = bOSHasSSEsupport() ;
- }
- #endif // if defined i386
- #ifdef _ARM
- if (!has_cpuid())
- return ;
- id = cpu_id() ;
- switch (id & 0xf000)
- {
- case 0x0<<12: // pre-ARM7
- pInfo->specific.m_arm.family = ulFamily_PREARM7 ;
- pInfo->specific.m_arm.implementor = ARM_IMPL_ARM ;
- switch (id >> 4) {
- case 0x4156030: pInfo->architecture = ulArchitectureARM_ARCH2 ; break ;
- case 0x4156060:
- case 0x4156061:
- case 0x4156062:
- pInfo->architecture = ulArchitectureARM_ARCH3 ; break ;
- default:
- pInfo->architecture = ulArchitectureUNKNOWN ; break ;
- }
- break ;
- case 0x7<<12: // ARM7
- pInfo->specific.m_arm.family = ulFamily_ARM7 ;
- pInfo->architecture = ((id >> 23) & 1) ? ulArchitectureARM_ARCH4T : ulArchitectureARM_ARCH3 ;
- pInfo->specific.m_arm.implementor = id >> 24 ;
- pInfo->specific.m_arm.variant = (id >> 16) & 0x7f ;
- pInfo->specific.m_arm.primaryPartNo = (id >> 4) & 0xfff ;
- pInfo->specific.m_arm.revision = id & 0xf ;
- default: // post-ARM7
- pInfo->specific.m_arm.family = ulFamily_POSTARM7 ;
- pInfo->specific.m_arm.implementor = id >> 24 ;
- pInfo->specific.m_arm.variant = (id >> 20) & 0xf ;
- pInfo->architecture = (CPUArchitecture)(((id >> 16) & 0xf) - 1 + ulArchitectureARM_ARCH4);
- pInfo->specific.m_arm.primaryPartNo = (id >> 4) & 0xfff ;
- pInfo->specific.m_arm.revision = id & 0xf ;
- if (pInfo->specific.m_arm.implementor == ARM_IMPL_Intel &&
- pInfo->architecture == ulArchitectureARM_ARCH5TE &&
- (id >> 13) & 7 == 1)
- {
- // XScale
- pInfo->specific.m_arm.specific.XScale.coreGeneration = (id >> 13) & 7 ; // "1"
- pInfo->specific.m_arm.specific.XScale.coreRevision = (id >> 10) & 7 ;
- pInfo->specific.m_arm.specific.XScale.productNumber = (id >> 4) & 63 ;
- }
- break ;
- }
- #endif /* _ARM */
- }