You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arts/flow/cpuinfo.cc

233 lines
7.9 KiB

/*
Copyright (C) 2001 Malte Starostik <malte@kde.org>
2001 Darian Lanx <bio@gmx.net>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <config.h>
#include "startupmanager.h"
#include "cpuinfo.h"
#include <setjmp.h>
#include <signal.h>
using namespace Arts;
int CpuInfo::s_flags = 0;
namespace Arts
{
class CpuInfoStartup : public StartupClass
{
public:
virtual void startup();
private:
static jmp_buf s_sseCheckEnv;
static void sseCheckHandler(int);
};
}
jmp_buf CpuInfoStartup::s_sseCheckEnv;
void CpuInfoStartup::sseCheckHandler(int)
{
longjmp(s_sseCheckEnv, 1);
}
void CpuInfoStartup::startup()
{
#ifdef HAVE_X86_SSE
/*
* Taken with thanks from mmx.h:
*
* MultiMedia eXtensions GCC interface library for IA32.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/* Returns 1 if MMX instructions are supported,
* 3 if Cyrix MMX and Extended MMX instructions are supported
* 5 if AMD MMX and 3DNow! instructions are supported
* 9 if MMX and Intel ISSE instructions are supported
* 0 if hardware does not support any of these
*/
__asm__ __volatile__ (
"pushl %%ebx \n\t"
"pushl %%ecx \n\t"
"pushl %%edx \n\t"
// See if CPUID instruction is supported ...
// ... Get copies of EFLAGS into eax and ecx
"pushf \n\t"
"popl %%eax \n\t"
"movl %%eax, %%ecx \n\t"
// ... Toggle the ID bit in one copy and store
// to the EFLAGS reg
"xorl $0x00200000, %%eax \n\t"
"push %%eax \n\t"
"popf \n\t"
// ... Get the (hopefully modified) EFLAGS
"pushf \n\t"
"popl %%eax \n\t"
// ... Compare and test result
"xorl %%eax, %%ecx \n\t"
"testl $0x00200000, %%ecx \n\t"
"jz NotSupported \n\t"
// Get standard CPUID information, and
// go to a specific vendor section
"movl $0, %%eax \n\t"
"cpuid \n\t"
// Check for Intel
"cmpl $0x756e6547, %%ebx \n\t" // Genu
"jne TryAMD \n\t"
"cmpl $0x49656e69, %%edx \n\t" // ineI
"jne TryAMD \n\t"
"cmpl $0x6c65746e, %%ecx \n\t" // ntel
"jne TryAMD \n\t"
"jmp Intel \n\t"
// Check for AMD
"TryAMD: \n\t"
"cmpl $0x68747541, %%ebx \n\t" // Auth
"jne TryCyrix \n\t"
"cmpl $0x69746e65, %%edx \n\t" // enti
"jne TryCyrix \n\t"
"cmpl $0x444d4163, %%ecx \n\t" // cAMD
"jne TryCyrix \n\t"
"jmp AMD \n\t"
// Check for Cyrix
"TryCyrix: \n\t"
"cmpl $0x69727943, %%ebx \n\t" // Cyri
"jne NotSupported \n\t"
"cmpl $0x736e4978, %%edx \n\t" // xIns
"jne NotSupported \n\t"
"cmpl $0x64616574, %%ecx \n\t" // tead
"jne NotSupported \n\t"
// Drop through to Cyrix...
// Cyrix Section
// See if extended CPUID is supported
"movl $0x80000000, %%eax \n\t"
"cpuid \n\t"
"cmpl $0x80000000, %%eax \n\t"
"jl MMXtest \n\t" // try std CPUID
// Extended CPUID supported, so get extended features
"movl $0x80000001, %%eax \n\t"
"cpuid \n\t"
"testl $0x00800000, %%eax \n\t" // test for MMX
"jz NotSupported \n\t" // no MMX
"movl $1, %0 \n\t" // has MMX
"testl $0x01000000, %%eax \n\t" // test for EMMX
"jz Return \n\t" // no EMMX
"addl $2, %0 \n\t" // has EMMX
"jmp Return \n\t"
// AMD Section
"AMD: \n\t"
// See if extended CPUID is supported
"movl $0x80000000, %%eax \n\t"
"cpuid \n\t"
"cmpl $0x80000000, %%eax \n\t"
"jl MMXtest \n\t" // try std CPUID
// Extended CPUID supported, so get extended features
"movl $0x80000001, %%eax \n\t"
"cpuid \n\t"
"testl $0x00800000, %%edx \n\t" // test for MMX
"jz NotSupported \n\t" // no MMX
"movl $1, %0 \n\t" // has MMX
"testl $0x80000000, %%edx \n\t" // test for 3DNow!
"jz Return \n\t"
"addl $4, %0 \n\t" // has 3DNow!
// Athlon(tm) XP has both 3DNow! and SSE
"pushl %%eax \n\t"
"movl $1, %%eax \n\t"
"cpuid \n\t"
"popl %%eax \n\t"
"testl $0x02000000, %%edx \n\t" // test for SSE
"jz Return \n\t" // no SSE
"addl $8, %0 \n\t" // has SSE
"jmp Return \n\t"
// Intel Section
"Intel: \n\t"
// Check for MMX
"MMXtest: \n\t"
"movl $1, %%eax \n\t"
"cpuid \n\t"
"testl $0x00800000, %%edx \n\t" // test for MMX
"jz NotSupported \n\t" // no MMX
"movl $1, %0 \n\t" // has MMX
"testl $0x02000000, %%edx \n\t" // test for SSE
"jz Return \n\t" // no SSE
"addl $8, %0 \n\t" // has SSE
"jmp Return \n\t"
// Nothing supported
"NotSupported: \n\t"
"movl $0, %0 \n\t"
"Return: \n\t"
"popl %%edx \n\t"
"popl %%ecx \n\t"
"popl %%ebx \n\t"
: "=a" (CpuInfo::s_flags)
: /* no input */
: "memory"
);
// SSE must be supported by the OS, if it's not, any SSE insn will
// trigger an invalid opcode exception, to check for this, a SIGILL
// handler is installed and a SSE insn run. If the handler is called,
// the SSE bit is cleared in CpuInfo::s_flags
if (CpuInfo::s_flags & CpuInfo::CpuSSE)
{
void (*oldHandler)(int) = signal(SIGILL, sseCheckHandler);
if (setjmp(s_sseCheckEnv))
{
CpuInfo::s_flags &= ~CpuInfo::CpuSSE;
}
else
{
__asm__ __volatile__ (
"subl $0x10, %esp \n"
"movups %xmm0, (%esp) \n"
"emms \n"
"addl $0x10, %esp \n"
);
}
signal(SIGILL, oldHandler);
}
#endif /* HAVE_X86_SSE */
}
static CpuInfoStartup cpuInfoStartup;