/********************************************************************1* *2* THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *3* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *4* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *5* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *6* *7* THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *8* by the Xiph.Org Foundation and contributors *9* https://www.xiph.org/ *10* *11********************************************************************1213CPU capability detection for x86 processors.14Originally written by Rudolf Marek.1516function:1718********************************************************************/1920#include "x86cpu.h"2122#if !defined(OC_X86_ASM)23ogg_uint32_t oc_cpu_flags_get(void){24return 0;25}26#else27# if defined(__amd64__)||defined(__x86_64__)28/*On x86-64, gcc seems to be able to figure out how to save %rbx for us when29compiling with -fPIC.*/30# define cpuid(_op,_eax,_ebx,_ecx,_edx) \31__asm__ __volatile__( \32"cpuid\n\t" \33:[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \34:"a"(_op) \35:"cc" \36)37# else38/*On x86-32, not so much.*/39# define cpuid(_op,_eax,_ebx,_ecx,_edx) \40__asm__ __volatile__( \41"xchgl %%ebx,%[ebx]\n\t" \42"cpuid\n\t" \43"xchgl %%ebx,%[ebx]\n\t" \44:[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \45:"a"(_op) \46:"cc" \47)48# endif4950static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){51ogg_uint32_t flags;52/*If there isn't even MMX, give up.*/53if(!(_edx&0x00800000))return 0;54flags=OC_CPU_X86_MMX;55if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;56if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;57if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;58if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;59if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;60if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;61return flags;62}6364static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){65ogg_uint32_t flags;66/*If there isn't even MMX, give up.*/67if(!(_edx&0x00800000))return 0;68flags=OC_CPU_X86_MMX;69if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;70if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;71if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;72if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;73if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;74return flags;75}7677ogg_uint32_t oc_cpu_flags_get(void){78ogg_uint32_t flags;79ogg_uint32_t eax;80ogg_uint32_t ebx;81ogg_uint32_t ecx;82ogg_uint32_t edx;83# if !defined(__amd64__)&&!defined(__x86_64__)84/*Not all x86-32 chips support cpuid, so we have to check.*/85__asm__ __volatile__(86"pushfl\n\t"87"pushfl\n\t"88"popl %[a]\n\t"89"movl %[a],%[b]\n\t"90"xorl $0x200000,%[a]\n\t"91"pushl %[a]\n\t"92"popfl\n\t"93"pushfl\n\t"94"popl %[a]\n\t"95"popfl\n\t"96:[a]"=r"(eax),[b]"=r"(ebx)97:98:"cc"99);100/*No cpuid.*/101if(eax==ebx)return 0;102# endif103cpuid(0,eax,ebx,ecx,edx);104/* l e t n I e n i u n e G*/105if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||106/* 6 8 x M T e n i u n e G*/107ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){108int family;109int model;110/*Intel, Transmeta (tested with Crusoe TM5800):*/111cpuid(1,eax,ebx,ecx,edx);112flags=oc_parse_intel_flags(edx,ecx);113family=(eax>>8)&0xF;114model=(eax>>4)&0xF;115/*The SSE unit on the Pentium M and Core Duo is much slower than the MMX116unit, so don't use it.*/117if(family==6&&(model==9||model==13||model==14)){118flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);119}120}121/* D M A c i t n e h t u A*/122else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||123/* C S N y b e d o e G*/124ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){125/*AMD, Geode:*/126cpuid(0x80000000,eax,ebx,ecx,edx);127if(eax<0x80000001)flags=0;128else{129cpuid(0x80000001,eax,ebx,ecx,edx);130flags=oc_parse_amd_flags(edx,ecx);131}132/*Also check for SSE.*/133cpuid(1,eax,ebx,ecx,edx);134flags|=oc_parse_intel_flags(edx,ecx);135}136/*Technically some VIA chips can be configured in the BIOS to return any137string here the user wants.138There is a special detection method that can be used to identify such139processors, but in my opinion, if the user really wants to change it, they140deserve what they get.*/141/* s l u a H r u a t n e C*/142else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){143/*VIA:*/144/*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)145chips (thanks to the engineers from Centaur Technology who provided it).146These chips support Intel-like cpuid info.147The C3-2 (Nehemiah) cores appear to, as well.*/148cpuid(1,eax,ebx,ecx,edx);149flags=oc_parse_intel_flags(edx,ecx);150if(eax>=0x80000001){151/*The (non-Nehemiah) C3 processors support AMD-like cpuid info.152We need to check this even if the Intel test succeeds to pick up 3DNow!153support on these processors.154Unlike actual AMD processors, we cannot _rely_ on this info, since155some cores (e.g., the 693 stepping of the Nehemiah) claim to support156this function, yet return edx=0, despite the Intel test indicating157MMX support.158Therefore the features detected here are strictly added to those159detected by the Intel test.*/160/*TODO: How about earlier chips?*/161cpuid(0x80000001,eax,ebx,ecx,edx);162/*Note: As of the C7, this function returns Intel-style extended feature163flags, not AMD-style.164Currently, this only defines bits 11, 20, and 29 (0x20100800), which165do not conflict with any of the AMD flags we inspect.166For the remaining bits, Intel tells us, "Do not count on their value",167but VIA assures us that they will all be zero (at least on the C7 and168Isaiah chips).169In the (unlikely) event a future processor uses bits 18, 19, 30, or 31170(0xC0C00000) for something else, we will have to add code to detect171the model to decide when it is appropriate to inspect them.*/172flags|=oc_parse_amd_flags(edx,ecx);173}174}175else{176/*Implement me.*/177flags=0;178}179return flags;180}181#endif182183184